Compare commits
947 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| de588ce198 | |||
| c15f84507d | |||
| d65158aa00 | |||
| 5b71d02dd2 | |||
| 11a58c587d | |||
| 9efc569ae5 | |||
| bee268ca10 | |||
| 9a15597983 | |||
| 552aedc95c | |||
| b641746863 | |||
| 2d2f7880ca | |||
| 5d6dc09dd9 | |||
| 87359e262a | |||
| 9b948c0150 | |||
| b52647b2c9 | |||
| 8d2637e6a5 | |||
| 216534d5e9 | |||
| 59ba45da4e | |||
| 9497c0897a | |||
| 2fdb55e340 | |||
| 2d96bfe3b2 | |||
| e0ecbb649f | |||
| 20b0d9d60e | |||
| 2b03bff637 | |||
| 1e9587826c | |||
| aa09279bab | |||
| a7ad638eb6 | |||
| bc5b1daaff | |||
| 7ddf820603 | |||
| 4c305088ac | |||
| e5bb8b2151 | |||
| 645c15b4c9 | |||
| 70fca6820e | |||
| aa7d8a6f17 | |||
| ec3b6fb901 | |||
| 090bb3b84a | |||
| 14e8744a16 | |||
| e512ae876f | |||
| 8ef7391c59 | |||
| 1476c1fdc8 | |||
| b4b029d189 | |||
| 91edd31d9f | |||
| 153ad0d84b | |||
| efdbb176e5 | |||
| 9fc59835eb | |||
| 9d52949b37 | |||
| 6292407a59 | |||
| a72f980728 | |||
| 39a6347310 | |||
| 6015686b31 | |||
| 0e6b4e969d | |||
| ccb509fedd | |||
| 7caf43059a | |||
| 8ef4d9ae63 | |||
| 120b8a218f | |||
| 316c0d5859 | |||
| 5dc6da40ea | |||
| 8a94b88d32 | |||
| a7bc33b939 | |||
| 9da843f749 | |||
| fa5bcff358 | |||
| f27a3fdc44 | |||
| 2683386aa5 | |||
| ca93161f2f | |||
| fd1b3c81ad | |||
| a3ed3feb2c | |||
| 88812e5257 | |||
| 5100f44b46 | |||
| 50a662db4b | |||
| ddd135bf22 | |||
| fcfe827615 | |||
| 4f03913543 | |||
| 05fda58d33 | |||
| 9077f9bbe2 | |||
| c1f8889088 | |||
| b0c409a2f8 | |||
| dc13e7271d | |||
| 60cedbc26b | |||
| e11e7dddca | |||
| 7f017d5590 | |||
| a8d48d4060 | |||
| 0c6ea09caf | |||
| edbaedb989 | |||
| 28f8ac1704 | |||
| c5543ffbc0 | |||
| f4227f6179 | |||
| 5dc9667ddf | |||
| f8e297943f | |||
| 5889037854 | |||
| 94bee32151 | |||
| 631b3bf914 | |||
| d0874b1011 | |||
| 88266e4a79 | |||
| 3b1f748bb9 | |||
| e288d80030 | |||
| bf24a0c9f5 | |||
| 173d4077d2 | |||
| 8939ff9b0f | |||
| 60e0ad1ec2 | |||
| d5df14df11 | |||
| 57338c0979 | |||
| 44fdec7885 | |||
| 81afb58554 | |||
| 94749d14d4 | |||
| 294fa457f5 | |||
| efd953406a | |||
| 3b83c1b835 | |||
| d198de9ce6 | |||
| bb462ef789 | |||
| 90ce207393 | |||
| ced3542da5 | |||
| 17aada579e | |||
| 908cc0e516 | |||
| c0a20305d0 | |||
| 3a95707e6f | |||
| 2f201f4590 | |||
| 0c203a7c14 | |||
| 873c2b9dc1 | |||
| 24b23ab3b9 | |||
| ef9ea24769 | |||
| 6ee33c23e4 | |||
| 2001477110 | |||
| 36ff69f941 | |||
| 4ce9a8ce60 | |||
| fad7891100 | |||
| 5cce2cc12f | |||
| 81f016bbfc | |||
| 3011a2b2c5 | |||
| 5153211f6e | |||
| 70129af847 | |||
| bf1f40a4f5 | |||
| b99e842e93 | |||
| d1fd865c35 | |||
| ab8fdf7e57 | |||
| ce68373277 | |||
| b4992ab037 | |||
| d491f6adef | |||
| 9dfeb086ba | |||
| 56b52a1aa5 | |||
| de8e62584e | |||
| 2d92aa9480 | |||
| 957e24fd48 | |||
| dd3e6e01b1 | |||
| dfbc9cda6d | |||
| d5af1838fb | |||
| 57cbae4ed9 | |||
| 92b790b8e4 | |||
| 74cd5fabdc | |||
| e401c23f0e | |||
| 4449095716 | |||
| 5c76188db3 | |||
| c665605d5a | |||
| 5086dee55b | |||
| cb58bba324 | |||
| 0d4b6a7aaf | |||
| dec785155c | |||
| fa87b159ed | |||
| 954ee42233 | |||
| 2c877bae80 | |||
| 5d87e004d7 | |||
| 511f6dbc69 | |||
| e592a4a584 | |||
| 239bb348d1 | |||
| b288dacd75 | |||
| 8827ce38a4 | |||
| 6393c07995 | |||
| efd6f0bd78 | |||
| a73b5236e6 | |||
| da1d88c069 | |||
| 885d8faba1 | |||
| b888d9a3b3 | |||
| a465ecebfa | |||
| bf4267ef1a | |||
| 893e0ab424 | |||
| c58668f3bb | |||
| 2bfddd467b | |||
| bf53b6334c | |||
| 2c7a00408b | |||
| 6aae754d9c | |||
| 013ed37253 | |||
| 1a47912020 | |||
| 8aca9cbd17 | |||
| 79d74aca1b | |||
| 77d4029a12 | |||
| 25db760ad7 | |||
| 6c56cb823a | |||
| e06b19696b | |||
| 84f6fed4ba | |||
| 78aa0b1727 | |||
| 08e0f22643 | |||
| 6544a1aacd | |||
| 3ef3e847cb | |||
| 43cfa0fe4c | |||
| 9718e52802 | |||
| 75ffc6b6f4 | |||
| 02ef7fc6c7 | |||
| f548d3698b | |||
| 7a064a58ce | |||
| 471b08ef22 | |||
| 94378c4b4d | |||
| 9b49989ddc | |||
| b767da350e | |||
| dfbe904db7 | |||
| 5564e9c325 | |||
| 781aae4cbd | |||
| e3addf9da4 | |||
| b98a223b01 | |||
| 56f858d97a | |||
| b47f3f5635 | |||
| eaeaec0278 | |||
| 85cab27623 | |||
| 5c38a6d8d8 | |||
| e9d99f71f5 | |||
| 2aefa0d3c9 | |||
| 44ec05bfce | |||
| 86ca76dbf1 | |||
| b473d78aa0 | |||
| 58a772f677 | |||
| 04c625bcbf | |||
| 5074bea663 | |||
| 15472c4186 | |||
| f66af885ab | |||
| c0233fbc3c | |||
| 1911080876 | |||
| 134c448d3a | |||
| acc1a62ea1 | |||
| 4829bcf17a | |||
| 45e33e594b | |||
| cf70327975 | |||
| 7aa26d5dc3 | |||
| 3395c0dcaa | |||
| ddfe2b6bb0 | |||
| 8bef87fdd6 | |||
| ad84c3afa3 | |||
| 3220de9527 | |||
| 1cf95cf7c4 | |||
| d6b3efebe3 | |||
| b7bb2d3e94 | |||
| 758a033c63 | |||
| e7457c83ec | |||
| acd452e37b | |||
| b650d0aa13 | |||
| 88e6f0dd10 | |||
| 636c0f5855 | |||
| bdfba6720c | |||
| ac6fdb8ccd | |||
| 0b1c8ab293 | |||
| bfac689761 | |||
| 613627f4e9 | |||
| e56ea68db1 | |||
| 7175728e96 | |||
| 1f1ec234ad | |||
| c714f8b235 | |||
| a0747e7f91 | |||
| 623477958b | |||
| 474acaaf92 | |||
| 6bb5f503eb | |||
| 5c20fa3744 | |||
| be8f3c973c | |||
| cf4835170a | |||
| c18ed8f63b | |||
| c325c1746e | |||
| f3d9591453 | |||
| 1364041fb6 | |||
| 48d55efe31 | |||
| 60969166db | |||
| 48caccb287 | |||
| fa6a9e1dad | |||
| 8bc082636e | |||
| 1a0d3ef5d5 | |||
| 54b7eac369 | |||
| 457b12da91 | |||
| 9fce462de5 | |||
| 39d2830104 | |||
| 9a6bb11bf9 | |||
| 76ab6ccdef | |||
| 30736e9b0c | |||
| da60fe3ec5 | |||
| 3a63ac5ccd | |||
| 06ac1bcc8c | |||
| 2d03e6526c | |||
| 9c43225f4c | |||
| cbbe80dd07 | |||
| 705b54155b | |||
| 76e3e418f4 | |||
| a4bef57acd | |||
| 5290de022e | |||
| 782dfafd45 | |||
| d3e8c4ab55 | |||
| 9f4f9a76bf | |||
| 0ba2871186 | |||
| bc7edb660f | |||
| a7a1cbfd23 | |||
| ea86288f6a | |||
| 68827edfd6 | |||
| 95321fc44e | |||
| 1061b94501 | |||
| e9cde7d57c | |||
| bebc33dc5b | |||
| 580f5469dc | |||
| 67003ad16f | |||
| 10d696f6a7 | |||
| 56d94f265c | |||
| c88bfd7ec5 | |||
| 92fa5c97b9 | |||
| b18eaecf48 | |||
| 076c98e1db | |||
| f66719270b | |||
| 43aa90634b | |||
| 48d0d23911 | |||
| 76fceb9d6a | |||
| 5c2f288d0c | |||
| d74d5c624d | |||
| 41a5f892d3 | |||
| ec78c8d2a6 | |||
| 45e1224975 | |||
| 817b24dcc8 | |||
| 1a74608567 | |||
| d7d21d1d63 | |||
| 205641c348 | |||
| 097d6caf63 | |||
| 6e100b2b1e | |||
| 25eb9bd4fa | |||
| b3ecc6d1fc | |||
| 9d138f7c4d | |||
| ea67d4bde0 | |||
| 321f2da312 | |||
| efd6d7e810 | |||
| 3779056dcc | |||
| 1549727859 | |||
| 106d596d82 | |||
| 48ea298718 | |||
| e5217f16bf | |||
| c14eefb773 | |||
| df9529c8d7 | |||
| d45aba4715 | |||
| 7413ef19fa | |||
| b14d7b42a5 | |||
| c285e9fe97 | |||
| 52dc20503b | |||
| 492aaa479b | |||
| 97c19806d9 | |||
| eaeab701e0 | |||
| 902353d426 | |||
| fc4d60c931 | |||
| 21cb19d8ef | |||
| 00efe2db27 | |||
| 448921c13c | |||
| 762ae01b11 | |||
| 0d7637cf85 | |||
| 25a0d33391 | |||
| c42b1b4334 | |||
| 850de1ca35 | |||
| 5156037581 | |||
| 81a249c09d | |||
| d961205788 | |||
| 6b84267918 | |||
| c0c4cb2a40 | |||
| e152b0826e | |||
| 096aa86f6f | |||
| 820a063848 | |||
| 8e1e729208 | |||
| 8d7d0411bd | |||
| 5e3a36b7a5 | |||
| 426826ae38 | |||
| f35c5e64d5 | |||
| cc7489021a | |||
| 1ad2ea4c53 | |||
| 61e130be8a | |||
| 1e51b6c2e0 | |||
| 1fe04d3288 | |||
| cbe5cfbd8f | |||
| 8d7a293376 | |||
| 629d0fff9d | |||
| 518c8304fa | |||
| 0056fbf9f8 | |||
| 88cfa65427 | |||
| 89c1345af9 | |||
| 27b9d942f3 | |||
| 92dc116c8e | |||
| a0aa347266 | |||
| 3273bd3b9f | |||
| 5fce72cb71 | |||
| 408afb5817 | |||
| c54d0c2716 | |||
| d0192ce143 | |||
| 254d69702d | |||
| 52bce935da | |||
| 1b1a467f87 | |||
| 85a2eccdd9 | |||
| 50e8175378 | |||
| 3041c381b7 | |||
| 9db5f97e93 | |||
| 98dc651173 | |||
| 2520099f7f | |||
| 900b2a265f | |||
| 19ec766fa7 | |||
| 1f1243de18 | |||
| 63b6b55b3d | |||
| 318982e2d9 | |||
| 51d664a7fd | |||
| 6817911900 | |||
| 2c9e99ee79 | |||
| df81354c59 | |||
| ea5ce7cc6d | |||
| 573346fdbc | |||
| aff122104e | |||
| e8fb022fc3 | |||
| 68e932685a | |||
| 359e98c2e4 | |||
| b49476c7e7 | |||
| ba3614b6da | |||
| df8665cbc7 | |||
| fda9c85d3e | |||
| f19322debc | |||
| 5e660e6a19 | |||
| f8a58d5695 | |||
| e58a372957 | |||
| 85a47ed67f | |||
| 7466a35657 | |||
| dc5c8bc156 | |||
| 7ca2be67bc | |||
| 461a055722 | |||
| 23ae97ab24 | |||
| 453829a979 | |||
| f62ea0a8da | |||
| 67d825204b | |||
| 348df64985 | |||
| e6c2c443a1 | |||
| 507ba01811 | |||
| f64af6bb62 | |||
| db0ae8d641 | |||
| 15a5603e9f | |||
| 1f60ee22bc | |||
| 662c5168c5 | |||
| b2e7127ae1 | |||
| f9b858629e | |||
| 30c833f701 | |||
| 6514a7d637 | |||
| 19c0e035fc | |||
| 12dc0492f6 | |||
| 86d596ed64 | |||
| 5c698bbdb0 | |||
| 93ae59477d | |||
| d2d7996ef2 | |||
| 9f35958d1e | |||
| 3509fb3a66 | |||
| 5449f5bb65 | |||
| 195face0b7 | |||
| 6e72e794a7 | |||
| 8bdf1d5d75 | |||
| a0bda40586 | |||
| 846d883cad | |||
| 9d21b27683 | |||
| e94fe45d48 | |||
| c98013059a | |||
| ffc369e561 | |||
| b73c365e6c | |||
| e5c026a7bb | |||
| 63b38d2ede | |||
| a89206157a | |||
| 274cb2b096 | |||
| d36ca7a521 | |||
| 46445273ad | |||
| 1892a29891 | |||
| 4b81339a2b | |||
| afa88ddaaf | |||
| 7b47eba942 | |||
| c62fa0329b | |||
| dd3b6a1185 | |||
| 3428e9ddf0 | |||
| 41de4c7944 | |||
| 0cb196b7fa | |||
| 0a553b9896 | |||
| 3530680225 | |||
| 04b3d7e45d | |||
| 10b6513250 | |||
| 02fce4905e | |||
| b5fff95824 | |||
| 38856b4b19 | |||
| 1fa43f2962 | |||
| b64aa18acd | |||
| f46c75e1e3 | |||
| 0cb6c941bf | |||
| 2217875a23 | |||
| 8854dad074 | |||
| b034c5652e | |||
| 592c440c03 | |||
| a225514e09 | |||
| 5e7b64230e | |||
| 014fe70c10 | |||
| bdce1ed68f | |||
| 738068153d | |||
| 7815e5c201 | |||
| 3edf7de79a | |||
| 6fb94f69e4 | |||
| a0f59c37ab | |||
| 38f46a6f29 | |||
| d0c6bb5e82 | |||
| a39dcb92ea | |||
| 814aecade5 | |||
| 4970c7f301 | |||
| 5ed2e8d8f5 | |||
| 81b07f1e3a | |||
| 84a4eae354 | |||
| 9d1ff5f8a8 | |||
| 423b20af50 | |||
| 94a9fb880b | |||
| 111353007e | |||
| 6a4e948cfb | |||
| 83205a89ae | |||
| 0993331053 | |||
| 6501fb8f90 | |||
| 178399e194 | |||
| 830a2766e7 | |||
| 919aa87be3 | |||
| e21dadfc05 | |||
| 09938266e7 | |||
| ed13718f40 | |||
| 4ec35a54cf | |||
| a3e89bbe15 | |||
| 987a85c60f | |||
| d9d89d3400 | |||
| d6c3e25ff2 | |||
| c9dba88248 | |||
| c31f87a055 | |||
| 3217b0109e | |||
| 37a64bbbfb | |||
| c061f0aa7e | |||
| 11322f7eb2 | |||
| 5a30dd8c66 | |||
| d59a6d9ad8 | |||
| 6548c151b3 | |||
| b5132e5712 | |||
| c26f32bf85 | |||
| a88db156a0 | |||
| 26d02d53ef | |||
| e13e5310f0 | |||
| 3c276824e2 | |||
| 0f12128ada | |||
| 29e6a1ace1 | |||
| 986d8356bc | |||
| da5a23ba5e | |||
| 06a7a4f898 | |||
| 28ff444e14 | |||
| a3f367938f | |||
| 1a17c5c928 | |||
| 40ce57c871 | |||
| ed63a66101 | |||
| 3749a3c80c | |||
| 69711ea65a | |||
| 8e5ac5f481 | |||
| 9e8fc55142 | |||
| dc12109f48 | |||
| 9a9ee50adf | |||
| f784beb981 | |||
| a84816f04c | |||
| f40e17d43f | |||
| aa5d31ac74 | |||
| 45ae6210ba | |||
| 7f032dbfd6 | |||
| 8e26701f37 | |||
| 911861725d | |||
| 23aa0096d8 | |||
| aabc1505cb | |||
| a7f99b7ebb | |||
| dc78df121e | |||
| a69b845e4a | |||
| 3f916d0f95 | |||
| b05d6ae8e1 | |||
| 3a866eba7d | |||
| f6fd22a1c0 | |||
| 03fc82695b | |||
| ff1523a5e9 | |||
| 7588963d63 | |||
| 2152cfac6f | |||
| e9c21e27a7 | |||
| 6f520bfb8f | |||
| 94c6e67436 | |||
| 098fe051cd | |||
| e1068c2ae2 | |||
| ee0dd02dd0 | |||
| 6236f47996 | |||
| 5703159607 | |||
| aee048e04c | |||
| 505d369ab5 | |||
| 1dbd544fdb | |||
| 40fb86f282 | |||
| f04f8baed2 | |||
| 324d742423 | |||
| 76529e1248 | |||
| 9905f19668 | |||
| 263aa270d1 | |||
| 31db0de0ba | |||
| 5600327c5f | |||
| 45c336e883 | |||
| 79ca9d75e4 | |||
| d4125fe729 | |||
| 92a49646dc | |||
| cc81ea1585 | |||
| 09d5b42b9a | |||
| b5756d7e6b | |||
| e9c60bc8d2 | |||
| 3a80532366 | |||
| e1f93acfca | |||
| ac6b604ce1 | |||
| 5e9a867efc | |||
| 143fda3fa6 | |||
| db21390026 | |||
| 017bc2429d | |||
| b019793a42 | |||
| a024a787c2 | |||
| 685d5f16c3 | |||
| 39d0b17894 | |||
| 6c302ca0d1 | |||
| e8e7a6317f | |||
| 2336c9719e | |||
| ba59e6c48c | |||
| 2769a23902 | |||
| 82d217ffd5 | |||
| 3d6319b47d | |||
| 46f1d4c84b | |||
| 0771e99d26 | |||
| d3905d5975 | |||
| 2ad747a239 | |||
| bb3968dd51 | |||
| 19f1874fbe | |||
| ccb7134256 | |||
| 5241e96113 | |||
| 982c1cb8e3 | |||
| 8352c20e57 | |||
| 47923244fc | |||
| 082cbe2649 | |||
| 68d1c7333b | |||
| e399374063 | |||
| 2b72cf6453 | |||
| bcd55fd530 | |||
| e5b8ac9e47 | |||
| 1f17227e7d | |||
| 40e903cb3f | |||
| d786299a95 | |||
| f028ddb05c | |||
| 866ee1895f | |||
| 72712b6d94 | |||
| aab34becfa | |||
| 12c4caef80 | |||
| 87d0a856f5 | |||
| ba79acfe64 | |||
| 4449c7dcfc | |||
| 31b9272b7d | |||
| 1db602aa46 | |||
| 03be094a6a | |||
| 037a930c76 | |||
| 5698ab021d | |||
| d3220529d1 | |||
| 89a3a6c6ea | |||
| 77480b98bc | |||
| 0c0d14851d | |||
| ad0234f0eb | |||
| 45e0e9ef4c | |||
| d2b7bf0ef5 | |||
| 790ee9e598 | |||
| 9bac82b7c3 | |||
| cf380d1e3e | |||
| 8155367ae4 | |||
| 5c2c97af42 | |||
| c03834c9e4 | |||
| 76da53b924 | |||
| 7716020c01 | |||
| 8c9c75ee37 | |||
| e3dc31c4d3 | |||
| 9b83858d31 | |||
| 01ec3856f8 | |||
| 11c08783e2 | |||
| f1fd1b66a9 | |||
| 8d360aafaa | |||
| d6b55a9a88 | |||
| ba3ab2eb93 | |||
| a565d8302a | |||
| f9ef85939a | |||
| 4e24b85036 | |||
| 727bd4420d | |||
| 5f8dc7f14f | |||
| 8001c3a523 | |||
| 4cd646255a | |||
| 33aff9ea02 | |||
| fb51a455e7 | |||
| ad48f91424 | |||
| 8be80df905 | |||
| 8f43222de9 | |||
| 3110938f74 | |||
| adde25b778 | |||
| 18434830c9 | |||
| 2c705416fc | |||
| 83a04998e1 | |||
| 572e6fa2d6 | |||
| a39d0d1465 | |||
| 2de94ed050 | |||
| 9263f850fd | |||
| daa2eb0a47 | |||
| 3ca29342f7 | |||
| 87a379c1f3 | |||
| 5aa314582f | |||
| 46ee60f0e8 | |||
| e73efe1519 | |||
| e816432d9d | |||
| bb925e4e53 | |||
| 671c586620 | |||
| e368e17af9 | |||
| 6e176965f9 | |||
| df641335b8 | |||
| 0faf59b663 | |||
| 37dfc777ab | |||
| c23b413110 | |||
| 061828bddc | |||
| 4423ba406e | |||
| a055cd2a1a | |||
| c12aae8e02 | |||
| 0d47fe7b34 | |||
| d1cda466e6 | |||
| 32442818ff | |||
| 0bcd3e5898 | |||
| 27abc7f577 | |||
| 770a700257 | |||
| 57ebafe45c | |||
| d5d9e2009f | |||
| 36d7ff52a0 | |||
| f184f2b3fb | |||
| 2fde691fd3 | |||
| 2e24e37ab8 | |||
| 8a7605bbf7 | |||
| ae42480e3b | |||
| f3d34f750a | |||
| 9b6c663953 | |||
| a892819304 | |||
| 60a5ee333a | |||
| 905f689e6a | |||
| d4a7f362f4 | |||
| 2ec42da73c | |||
| b826fc223c | |||
| 374018cb73 | |||
| 2d10053324 | |||
| 3785f38179 | |||
| 8c24959d46 | |||
| 8de6312609 | |||
| 151c429f8b | |||
| ce31ba0eb2 | |||
| df61cc1fd8 | |||
| 58971d3290 | |||
| bea59c15da | |||
| d14a5f3635 | |||
| 7661a16cc7 | |||
| 5a099a0fb6 | |||
| b3dd31145f | |||
| 85b98257c4 | |||
| 9c17974971 | |||
| 046dd033b8 | |||
| c0d4b9e432 | |||
| 234ed11b36 | |||
| d8aec8b52b | |||
| 4acbfccd1c | |||
| e8260d61a9 | |||
| ab002a67e2 | |||
| f23645fc58 | |||
| 609f55db28 | |||
| 6be26f3ac8 | |||
| 2e0e164583 | |||
| 1282a2c168 | |||
| dcb80fb15b | |||
| c2eac412f0 | |||
| 4453b71cec | |||
| 9576766186 | |||
| 39538b500c | |||
| 007e14c816 | |||
| 2be38776f7 | |||
| 4e2eab1c28 | |||
| e66feb63c4 | |||
| 5e7edd3d48 | |||
| 77282708c6 | |||
| 2fa6719028 | |||
| ef17c0bf57 | |||
| 1f34d31374 | |||
| 1434fb068d | |||
| cca3fb4b6a | |||
| 683737a864 | |||
| 714c29abd5 | |||
| e2c73a9228 | |||
| 29c988dcbf | |||
| acab5b3fa6 | |||
| 980fc79258 | |||
| 1f1754b94f | |||
| be7680bf63 | |||
| 6e8835a75c | |||
| e720b4b796 | |||
| 52b2978691 | |||
| 543ace5bb9 | |||
| f58f1b19fb | |||
| 9391f5dbeb | |||
| 5f40d51a8c | |||
| a7cc6266dd | |||
| f5615f22b3 | |||
| b4edcfabce | |||
| 161c8da6d1 | |||
| a256d17c3c | |||
| 031ebb5174 | |||
| 036ec8e1c4 | |||
| 976b39af9f | |||
| 655c5ca40c | |||
| 059cee4650 | |||
| 3618276910 | |||
| f0e13b4652 | |||
| dba88052f7 | |||
| af2082b8be | |||
| fe68ea525b | |||
| 410720e3cb | |||
| 98937fc48b | |||
| 51f5c72bc0 | |||
| 646f4b4fa4 | |||
| 59fe31c7cd | |||
| d1e63ec9a9 | |||
| babbb1ca82 | |||
| 8d99a508ae | |||
| cb9f518fcc | |||
| 4ee51d86ec | |||
| aaf1187132 | |||
| 3875e37e06 | |||
| 1e528a8ace | |||
| 9bd1770c5d | |||
| ba7f60314b | |||
| db9e2ef8a0 | |||
| 170217bd78 | |||
| cd64609383 | |||
| b92a6a144b | |||
| 9cce0357f4 | |||
| 3cfeabcde9 | |||
| d93a2761a4 | |||
| d265e72590 | |||
| d25217d5bd | |||
| a26c4e984e | |||
| be93354493 | |||
| fdd3f43913 | |||
| 81aa2ed881 | |||
| fb3e24255b | |||
| b6abe77a18 | |||
| f4c27d3a33 | |||
| ef0f04a66c | |||
| 0be1228a8d | |||
| a0e8d6dc64 | |||
| d44b2cf875 | |||
| 0a0a09ebbc | |||
| 56ece06266 | |||
| 666cb791e5 | |||
| 8b09492091 | |||
| bcd9f59578 | |||
| 7d62d315a7 | |||
| 4facc1a2b0 | |||
| befc500a4a | |||
| 23fd8a8f7d | |||
| d3d7625d25 | |||
| 28e59d67ea | |||
| d9a511f08f | |||
| 0e9202021e | |||
| 2eec9ea60c | |||
| 58d80cc600 | |||
| 365c1d8483 | |||
| 1a001afc57 | |||
| db3e906d80 | |||
| 472d08283a | |||
| 43f290d6bc | |||
| c169ac6e42 | |||
| d7f4e96de4 | |||
| 1ab3676087 | |||
| 5c23cc43d0 | |||
| ac802e862b | |||
| c6b331d31a | |||
| 56ae2bc62f | |||
| acf2bb63bc | |||
| b61d06c812 | |||
| ca86373fdf | |||
| e44c6c4006 | |||
| 66bfda2e79 | |||
| 5c1ff95535 | |||
| a4ffdf57d9 | |||
| cf91de3c35 | |||
| 1884261435 | |||
| 2666fe301c | |||
| 91bf1f10ef | |||
| 5bcc66db06 | |||
| bdab1c9ec7 | |||
| cee97f0786 | |||
| 344758d343 | |||
| 23423397a8 | |||
| 6c116ca505 | |||
| 2d0162969f | |||
| 3720a74a6c | |||
| 9dd0ff9e83 | |||
| 3fce516c39 | |||
| 23bf888ede | |||
| a9a09b1f0f | |||
| e1b9b1895e | |||
| 7091226578 | |||
| f9b7b35d1b | |||
| 4c160dd323 | |||
| 494655c741 | |||
| e45637f101 | |||
| 0dd3c0b4ac | |||
| 36e219cc3e | |||
| eb6e14442e | |||
| c8401519cc | |||
| d09e9172c5 | |||
| 887e17c2cd | |||
| b9f29c4d9a | |||
| d203c362ef | |||
| dfa3c92a71 | |||
| a1e345c00b | |||
| 2ca2a6f538 | |||
| 6ef77f86b6 | |||
| 0f9ac1b210 | |||
| 3019dcdc76 | |||
| c5e31c8f15 | |||
| 8b15d9b3be | |||
| 9947888c1a | |||
| 066414989f | |||
| e1112073fa | |||
| 9e1026b14f | |||
| 4aca6e3409 | |||
| a1a7d0e9ee | |||
| cbdea59049 | |||
| a70d6d527b | |||
| 3c6a5c934c | |||
| f0681a0703 | |||
| d72fb56f2f | |||
| 364231c7e0 | |||
| 56726ffd2a | |||
| 08c814c71b | |||
| 574ab49496 | |||
| c553833b79 | |||
| d8f92da702 | |||
| 89c698e642 | |||
| 786b7bc2e3 | |||
| 314d4fdd39 | |||
| ff0be92c3f | |||
| f504eb5185 | |||
| 02b7aba063 | |||
| 341b50703e | |||
| b58261f8a0 | |||
| 5b65a5d1fd |
@@ -0,0 +1,14 @@
|
||||
name: 'Parallel ctest'
|
||||
description: 'Runs a set of labeled ctests in parallel via multiple docker containers'
|
||||
inputs:
|
||||
container:
|
||||
required: true
|
||||
error-log-paths:
|
||||
required: true
|
||||
log-tarball-prefix:
|
||||
required: true
|
||||
tests-label:
|
||||
required: true
|
||||
runs:
|
||||
using: 'node16'
|
||||
main: 'dist/index.mjs'
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,69 @@
|
||||
import child_process from 'node:child_process';
|
||||
import process from 'node:process';
|
||||
import stream from 'node:stream';
|
||||
import fs from 'node:fs';
|
||||
import zlib from 'node:zlib';
|
||||
import tar from 'tar-stream';
|
||||
import core from '@actions/core'
|
||||
|
||||
const container = core.getInput('container', {required: true});
|
||||
const error_log_paths = JSON.parse(core.getInput('error-log-paths', {required: true}));
|
||||
const log_tarball_prefix = core.getInput('log-tarball-prefix', {required: true});
|
||||
const tests_label = core.getInput('tests-label', {required: true});
|
||||
|
||||
try {
|
||||
if(child_process.spawnSync("docker", ["run", "--name", "base", "-v", `${process.cwd()}/build.tar.zst:/build.tar.zst`, "--workdir", "/__w/leap/leap", container, "sh", "-c", "zstdcat /build.tar.zst | tar x"], {stdio:"inherit"}).status)
|
||||
throw new Error("Failed to create base container");
|
||||
if(child_process.spawnSync("docker", ["commit", "base", "baseimage"], {stdio:"inherit"}).status)
|
||||
throw new Error("Failed to create base image");
|
||||
if(child_process.spawnSync("docker", ["rm", "base"], {stdio:"inherit"}).status)
|
||||
throw new Error("Failed to remove base container");
|
||||
|
||||
// the correct approach is by far "--show-only=json-v1" and then pluck out .tests[].name; but that doesn't work on U18's cmake 3.10 since it lacks json-v1 output
|
||||
const test_query_result = child_process.spawnSync("docker", ["run", "--rm", "baseimage", "bash", "-e", "-o", "pipefail", "-c", `cd build; ctest -L '${tests_label}' --show-only | head -n -1 | cut -d ':' -f 2 -s | jq -cnR '[inputs | select(length>0)[1:]]'`]);
|
||||
if(test_query_result.status)
|
||||
throw new Error("Failed to discover tests with label")
|
||||
const tests = JSON.parse(test_query_result.stdout);
|
||||
|
||||
let subprocesses = [];
|
||||
tests.forEach(t => {
|
||||
subprocesses.push(new Promise(resolve => {
|
||||
child_process.spawn("docker", ["run", "--name", t, "--init", "baseimage", "bash", "-c", `cd build; ctest --output-on-failure -R '^${t}$'`], {stdio:"inherit"}).on('close', code => resolve(code));
|
||||
}));
|
||||
});
|
||||
|
||||
const results = await Promise.all(subprocesses);
|
||||
|
||||
for(let i = 0; i < results.length; ++i) {
|
||||
if(results[i] === 0)
|
||||
continue;
|
||||
|
||||
//failing test
|
||||
core.setFailed("Some tests failed");
|
||||
|
||||
let extractor = tar.extract();
|
||||
let packer = tar.pack();
|
||||
|
||||
extractor.on('entry', (header, stream, next) => {
|
||||
if(!header.name.startsWith(`__w/leap/leap/build`)) {
|
||||
stream.on('end', () => next());
|
||||
stream.resume();
|
||||
return;
|
||||
}
|
||||
|
||||
header.name = header.name.substring(`__w/leap/leap/`.length);
|
||||
if(header.name !== "build/" && error_log_paths.filter(p => header.name.startsWith(p)).length === 0) {
|
||||
stream.on('end', () => next());
|
||||
stream.resume();
|
||||
return;
|
||||
}
|
||||
|
||||
stream.pipe(packer.entry(header, next));
|
||||
}).on('finish', () => {packer.finalize()});
|
||||
|
||||
child_process.spawn("docker", ["export", tests[i]]).stdout.pipe(extractor);
|
||||
stream.promises.pipeline(packer, zlib.createGzip(), fs.createWriteStream(`${log_tarball_prefix}-${tests[i]}-logs.tar.gz`));
|
||||
}
|
||||
} catch(e) {
|
||||
core.setFailed(`Uncaught exception ${e.message}`);
|
||||
}
|
||||
@@ -0,0 +1,351 @@
|
||||
{
|
||||
"name": "parallel-ctest-containers",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"dependencies": {
|
||||
"@actions/core": "^1.9.1",
|
||||
"@vercel/ncc": "^0.34.0",
|
||||
"tar-stream": "^2.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@actions/core": {
|
||||
"version": "1.9.1",
|
||||
"resolved": "https://registry.npmjs.org/@actions/core/-/core-1.9.1.tgz",
|
||||
"integrity": "sha512-5ad+U2YGrmmiw6du20AQW5XuWo7UKN2052FjSV7MX+Wfjf8sCqcsZe62NfgHys4QI4/Y+vQvLKYL8jWtA1ZBTA==",
|
||||
"dependencies": {
|
||||
"@actions/http-client": "^2.0.1",
|
||||
"uuid": "^8.3.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@actions/http-client": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.0.1.tgz",
|
||||
"integrity": "sha512-PIXiMVtz6VvyaRsGY268qvj57hXQEpsYogYOu2nrQhlf+XCGmZstmuZBbAybUl1nQGnvS1k1eEsQ69ZoD7xlSw==",
|
||||
"dependencies": {
|
||||
"tunnel": "^0.0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/@vercel/ncc": {
|
||||
"version": "0.34.0",
|
||||
"resolved": "https://registry.npmjs.org/@vercel/ncc/-/ncc-0.34.0.tgz",
|
||||
"integrity": "sha512-G9h5ZLBJ/V57Ou9vz5hI8pda/YQX5HQszCs3AmIus3XzsmRn/0Ptic5otD3xVST8QLKk7AMk7AqpsyQGN7MZ9A==",
|
||||
"bin": {
|
||||
"ncc": "dist/ncc/cli.js"
|
||||
}
|
||||
},
|
||||
"node_modules/base64-js": {
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
|
||||
"integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
]
|
||||
},
|
||||
"node_modules/bl": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz",
|
||||
"integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==",
|
||||
"dependencies": {
|
||||
"buffer": "^5.5.0",
|
||||
"inherits": "^2.0.4",
|
||||
"readable-stream": "^3.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/buffer": {
|
||||
"version": "5.7.1",
|
||||
"resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
|
||||
"integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"base64-js": "^1.3.1",
|
||||
"ieee754": "^1.1.13"
|
||||
}
|
||||
},
|
||||
"node_modules/end-of-stream": {
|
||||
"version": "1.4.4",
|
||||
"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
|
||||
"integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==",
|
||||
"dependencies": {
|
||||
"once": "^1.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/fs-constants": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
|
||||
"integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow=="
|
||||
},
|
||||
"node_modules/ieee754": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
|
||||
"integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
]
|
||||
},
|
||||
"node_modules/inherits": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
|
||||
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
|
||||
},
|
||||
"node_modules/once": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
||||
"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
|
||||
"dependencies": {
|
||||
"wrappy": "1"
|
||||
}
|
||||
},
|
||||
"node_modules/readable-stream": {
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
|
||||
"integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
|
||||
"dependencies": {
|
||||
"inherits": "^2.0.3",
|
||||
"string_decoder": "^1.1.1",
|
||||
"util-deprecate": "^1.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/safe-buffer": {
|
||||
"version": "5.2.1",
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
|
||||
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
]
|
||||
},
|
||||
"node_modules/string_decoder": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
|
||||
"integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
|
||||
"dependencies": {
|
||||
"safe-buffer": "~5.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/tar-stream": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz",
|
||||
"integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==",
|
||||
"dependencies": {
|
||||
"bl": "^4.0.3",
|
||||
"end-of-stream": "^1.4.1",
|
||||
"fs-constants": "^1.0.0",
|
||||
"inherits": "^2.0.3",
|
||||
"readable-stream": "^3.1.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/tunnel": {
|
||||
"version": "0.0.6",
|
||||
"resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz",
|
||||
"integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==",
|
||||
"engines": {
|
||||
"node": ">=0.6.11 <=0.7.0 || >=0.7.3"
|
||||
}
|
||||
},
|
||||
"node_modules/util-deprecate": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
||||
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
|
||||
},
|
||||
"node_modules/uuid": {
|
||||
"version": "8.3.2",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
|
||||
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
|
||||
"bin": {
|
||||
"uuid": "dist/bin/uuid"
|
||||
}
|
||||
},
|
||||
"node_modules/wrappy": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@actions/core": {
|
||||
"version": "1.9.1",
|
||||
"resolved": "https://registry.npmjs.org/@actions/core/-/core-1.9.1.tgz",
|
||||
"integrity": "sha512-5ad+U2YGrmmiw6du20AQW5XuWo7UKN2052FjSV7MX+Wfjf8sCqcsZe62NfgHys4QI4/Y+vQvLKYL8jWtA1ZBTA==",
|
||||
"requires": {
|
||||
"@actions/http-client": "^2.0.1",
|
||||
"uuid": "^8.3.2"
|
||||
}
|
||||
},
|
||||
"@actions/http-client": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.0.1.tgz",
|
||||
"integrity": "sha512-PIXiMVtz6VvyaRsGY268qvj57hXQEpsYogYOu2nrQhlf+XCGmZstmuZBbAybUl1nQGnvS1k1eEsQ69ZoD7xlSw==",
|
||||
"requires": {
|
||||
"tunnel": "^0.0.6"
|
||||
}
|
||||
},
|
||||
"@vercel/ncc": {
|
||||
"version": "0.34.0",
|
||||
"resolved": "https://registry.npmjs.org/@vercel/ncc/-/ncc-0.34.0.tgz",
|
||||
"integrity": "sha512-G9h5ZLBJ/V57Ou9vz5hI8pda/YQX5HQszCs3AmIus3XzsmRn/0Ptic5otD3xVST8QLKk7AMk7AqpsyQGN7MZ9A=="
|
||||
},
|
||||
"base64-js": {
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
|
||||
"integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="
|
||||
},
|
||||
"bl": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz",
|
||||
"integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==",
|
||||
"requires": {
|
||||
"buffer": "^5.5.0",
|
||||
"inherits": "^2.0.4",
|
||||
"readable-stream": "^3.4.0"
|
||||
}
|
||||
},
|
||||
"buffer": {
|
||||
"version": "5.7.1",
|
||||
"resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
|
||||
"integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
|
||||
"requires": {
|
||||
"base64-js": "^1.3.1",
|
||||
"ieee754": "^1.1.13"
|
||||
}
|
||||
},
|
||||
"end-of-stream": {
|
||||
"version": "1.4.4",
|
||||
"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
|
||||
"integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==",
|
||||
"requires": {
|
||||
"once": "^1.4.0"
|
||||
}
|
||||
},
|
||||
"fs-constants": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
|
||||
"integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow=="
|
||||
},
|
||||
"ieee754": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
|
||||
"integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="
|
||||
},
|
||||
"inherits": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
|
||||
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
|
||||
},
|
||||
"once": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
||||
"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
|
||||
"requires": {
|
||||
"wrappy": "1"
|
||||
}
|
||||
},
|
||||
"readable-stream": {
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
|
||||
"integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
|
||||
"requires": {
|
||||
"inherits": "^2.0.3",
|
||||
"string_decoder": "^1.1.1",
|
||||
"util-deprecate": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"safe-buffer": {
|
||||
"version": "5.2.1",
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
|
||||
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="
|
||||
},
|
||||
"string_decoder": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
|
||||
"integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
|
||||
"requires": {
|
||||
"safe-buffer": "~5.2.0"
|
||||
}
|
||||
},
|
||||
"tar-stream": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz",
|
||||
"integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==",
|
||||
"requires": {
|
||||
"bl": "^4.0.3",
|
||||
"end-of-stream": "^1.4.1",
|
||||
"fs-constants": "^1.0.0",
|
||||
"inherits": "^2.0.3",
|
||||
"readable-stream": "^3.1.1"
|
||||
}
|
||||
},
|
||||
"tunnel": {
|
||||
"version": "0.0.6",
|
||||
"resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz",
|
||||
"integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg=="
|
||||
},
|
||||
"util-deprecate": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
||||
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
|
||||
},
|
||||
"uuid": {
|
||||
"version": "8.3.2",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
|
||||
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="
|
||||
},
|
||||
"wrappy": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"@actions/core": "^1.9.1",
|
||||
"@vercel/ncc": "^0.34.0",
|
||||
"tar-stream": "^2.2.0"
|
||||
}
|
||||
}
|
||||
@@ -7,13 +7,9 @@ on:
|
||||
- "release/*"
|
||||
pull_request:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
run-lr-tests:
|
||||
description: 'Run long running tests'
|
||||
type: boolean
|
||||
|
||||
permissions:
|
||||
packages: write
|
||||
packages: read
|
||||
contents: read
|
||||
|
||||
defaults:
|
||||
@@ -44,6 +40,9 @@ jobs:
|
||||
matrix:
|
||||
platform: ${{fromJSON(needs.d.outputs.missing-platforms)}}
|
||||
runs-on: ["self-hosted", "enf-x86-beefy"]
|
||||
permissions:
|
||||
packages: write
|
||||
contents: read
|
||||
steps:
|
||||
- name: Login to Container Registry
|
||||
uses: docker/login-action@v2
|
||||
@@ -57,6 +56,7 @@ jobs:
|
||||
push: true
|
||||
tags: ${{fromJSON(needs.d.outputs.p)[matrix.platform].image}}
|
||||
file: ${{fromJSON(needs.d.outputs.p)[matrix.platform].dockerfile}}
|
||||
|
||||
Build:
|
||||
needs: [d, build-platforms]
|
||||
if: always() && needs.d.result == 'success' && (needs.build-platforms.result == 'success' || needs.build-platforms.result == 'skipped')
|
||||
@@ -64,8 +64,6 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
platform: [ubuntu18, ubuntu20, ubuntu22]
|
||||
outputs:
|
||||
lr-tests: ${{steps.build.outputs.lr-tests}}
|
||||
runs-on: ["self-hosted", "enf-x86-beefy"]
|
||||
container: ${{fromJSON(needs.d.outputs.p)[matrix.platform].image}}
|
||||
steps:
|
||||
@@ -81,25 +79,38 @@ jobs:
|
||||
cd build
|
||||
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr -GNinja ..
|
||||
ninja
|
||||
# the correct approach is by far "--show-only=json-v1 | jq '.tests[].name' | jq -sc" but that doesn't work on U18's cmake 3.10 since it lacks json-v1
|
||||
echo ::set-output name=lr-tests::$(ctest -L "long_running_tests" --show-only | head -n -1 | cut -d ':' -f 2 -s | jq -cnR '[inputs | select(length>0)[1:]]')
|
||||
tar -pc -C .. --exclude "*.a" --exclude "*.o" build | zstd --long -T0 -9 > ../build.tar.gz
|
||||
tar -pc -C .. --exclude "*.o" build | zstd --long -T0 -9 > ../build.tar.zst
|
||||
- name: Upload builddir
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: AntelopeIO/upload-artifact-large-chunks-action@v1
|
||||
with:
|
||||
name: ${{matrix.platform}}-build
|
||||
path: build.tar.gz
|
||||
- name: Build dev package (Ubuntu 20 only)
|
||||
if: matrix.platform == 'ubuntu20'
|
||||
run: |
|
||||
cd build
|
||||
ninja package
|
||||
- name: Upload dev package (Ubuntu 20 only)
|
||||
if: matrix.platform == 'ubuntu20'
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: leap-dev-ubuntu20-amd64
|
||||
path: build/leap-dev*.deb
|
||||
path: build.tar.zst
|
||||
|
||||
dev-package:
|
||||
name: Build leap-dev package
|
||||
needs: [d, Build]
|
||||
if: always() && needs.Build.result == 'success'
|
||||
runs-on: ubuntu-latest
|
||||
container: ${{fromJSON(needs.d.outputs.p)['ubuntu20'].image}}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: true
|
||||
- name: Download builddir
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: ubuntu20-build
|
||||
- name: Build dev package
|
||||
run: |
|
||||
zstdcat build.tar.zst | tar x
|
||||
cd build
|
||||
cpack
|
||||
- name: Upload dev package
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: leap-dev-ubuntu20-amd64
|
||||
path: build/leap-dev*.deb
|
||||
|
||||
tests:
|
||||
name: Tests
|
||||
needs: [d, Build]
|
||||
@@ -107,13 +118,11 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
platform: [ubuntu20]
|
||||
runs-on: ["self-hosted", "enf-x86-beefy"]
|
||||
platform: [ubuntu20, ubuntu22]
|
||||
runs-on: ["self-hosted", "enf-x86-hightier"]
|
||||
container: ${{fromJSON(needs.d.outputs.p)[matrix.platform].image}}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: true
|
||||
- name: Download builddir
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
@@ -122,9 +131,13 @@ jobs:
|
||||
run: |
|
||||
# https://github.com/actions/runner/issues/2033 -- need this because of full version label test looking at git revs
|
||||
chown -R $(id -u):$(id -g) $PWD
|
||||
zstdcat build.tar.gz | tar x
|
||||
# jammy's boost 1.74 can stumble on an EXDEV via copy_file_range() it doesn't have a fallback for; re-eval once moving to std::filesystem
|
||||
export TMPDIR="$PWD/tmp"
|
||||
mkdir -p $TMPDIR
|
||||
zstdcat build.tar.zst | tar x
|
||||
cd build
|
||||
ctest --output-on-failure -j $(nproc) -LE "(nonparallelizable_tests|long_running_tests)"
|
||||
|
||||
np-tests:
|
||||
name: NP Tests
|
||||
needs: [d, Build]
|
||||
@@ -132,70 +145,62 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
platform: [ubuntu20]
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: ${{fromJSON(needs.d.outputs.p)[matrix.platform].image}}
|
||||
options: --init
|
||||
platform: [ubuntu18, ubuntu20, ubuntu22]
|
||||
runs-on: ["self-hosted", "enf-x86-midtier"]
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Download builddir
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: ${{matrix.platform}}-build
|
||||
- name: Run NP Tests
|
||||
run: |
|
||||
zstdcat build.tar.gz | tar x
|
||||
cd build
|
||||
ctest --output-on-failure -L "nonparallelizable_tests"
|
||||
- name: Bundle logs from failed tests
|
||||
if: failure()
|
||||
run: tar --ignore-failed-read -czf ${{matrix.platform}}-serial-logs.tar.gz build/var build/etc build/leap-ignition-wd
|
||||
- name: Run tests in parallel containers
|
||||
uses: ./.github/actions/parallel-ctest-containers
|
||||
with:
|
||||
container: ${{fromJSON(needs.d.outputs.p)[matrix.platform].image}}
|
||||
error-log-paths: '["build/etc", "build/var", "build/leap-ignition-wd"]'
|
||||
log-tarball-prefix: ${{matrix.platform}}
|
||||
tests-label: nonparallelizable_tests
|
||||
- name: Upload logs from failed tests
|
||||
uses: actions/upload-artifact@v3
|
||||
if: failure()
|
||||
with:
|
||||
name: ${{matrix.platform}}-serial-logs
|
||||
path: ${{matrix.platform}}-serial-logs.tar.gz
|
||||
name: ${{matrix.platform}}-np-logs
|
||||
path: '*-logs.tar.gz'
|
||||
|
||||
lr-tests:
|
||||
name: LR Tests
|
||||
needs: [d, Build]
|
||||
if: always() && needs.Build.result == 'success' && (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/heads/release/') || inputs.run-lr-tests)
|
||||
if: always() && needs.Build.result == 'success'
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
platform: [ubuntu20]
|
||||
test-name: ${{fromJSON(needs.Build.outputs.lr-tests)}}
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: ${{fromJSON(needs.d.outputs.p)[matrix.platform].image}}
|
||||
options: --init
|
||||
platform: [ubuntu18, ubuntu20, ubuntu22]
|
||||
runs-on: ["self-hosted", "enf-x86-lowtier"]
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Download builddir
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: ${{matrix.platform}}-build
|
||||
- name: Run ${{matrix.test-name}} Test
|
||||
run: |
|
||||
zstdcat build.tar.gz | tar x
|
||||
cd build
|
||||
ctest --output-on-failure -R ${{matrix.test-name}}
|
||||
- name: Bundle logs from failed tests
|
||||
if: failure()
|
||||
run: tar --ignore-failed-read -czf ${{matrix.platform}}-${{matrix.test-name}}-logs.tar.gz build/var build/etc build/leap-ignition-wd
|
||||
- name: Upload logs from failed tests
|
||||
- name: Run tests in parallel containers
|
||||
uses: ./.github/actions/parallel-ctest-containers
|
||||
with:
|
||||
container: ${{fromJSON(needs.d.outputs.p)[matrix.platform].image}}
|
||||
error-log-paths: '["build/etc", "build/var", "build/leap-ignition-wd"]'
|
||||
log-tarball-prefix: ${{matrix.platform}}
|
||||
tests-label: long_running_tests
|
||||
- name: Upload logs from failed tests
|
||||
uses: actions/upload-artifact@v3
|
||||
if: failure()
|
||||
with:
|
||||
name: ${{matrix.platform}}-${{matrix.test-name}}-logs
|
||||
path: ${{matrix.platform}}-${{matrix.test-name}}-logs.tar.gz
|
||||
name: ${{matrix.platform}}-lr-logs
|
||||
path: '*-logs.tar.gz'
|
||||
|
||||
all-passing:
|
||||
name: All Required Tests Passed
|
||||
needs: [tests, np-tests]
|
||||
needs: [dev-package, tests, np-tests]
|
||||
if: always()
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- if: needs.tests.result != 'success' || needs.np-tests.result != 'success'
|
||||
- if: needs.dev-package.result != 'success' || needs.tests.result != 'success' || needs.np-tests.result != 'success'
|
||||
run: false
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
name: Jira Issue Creator
|
||||
on:
|
||||
issues:
|
||||
types:
|
||||
- labeled
|
||||
|
||||
jobs:
|
||||
create-jira-issue:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event.label.name == 'OCI'
|
||||
steps:
|
||||
- name: Create json issue file
|
||||
run: |
|
||||
cat << EOF > issue.json
|
||||
{
|
||||
"fields": {
|
||||
"project":
|
||||
{
|
||||
"key": "$JIRA_PROJECT_KEY"
|
||||
},
|
||||
"summary": "$JIRA_ISSUE_SUMMARY",
|
||||
"description": "$JIRA_ISSUE_DESCRIPTION",
|
||||
"issuetype": {
|
||||
"name": "$JIRA_ISSUE_TYPE_NAME"
|
||||
}
|
||||
}
|
||||
}
|
||||
EOF
|
||||
env:
|
||||
JIRA_PROJECT_KEY: ${{ secrets.JIRA_PROJECT_KEY }}
|
||||
JIRA_ISSUE_SUMMARY: ${{ github.event.issue.title }}
|
||||
JIRA_ISSUE_DESCRIPTION: "${{ github.event.issue.url }}\\n\\n${{ github.event.issue.html_url }}"
|
||||
JIRA_ISSUE_TYPE_NAME: "Story"
|
||||
- name: Check issue json
|
||||
run: |
|
||||
cat issue.json
|
||||
- name: Trigger jira issue creation
|
||||
run: |
|
||||
curl -u $JIRA_AUTH -X POST --data @issue.json -H "Content-Type: application/json" --url $JIRA_PROJECT_URL
|
||||
env:
|
||||
JIRA_AUTH: ${{ secrets.JIRA_USN_AND_TOKEN }}
|
||||
JIRA_PROJECT_URL: ${{ secrets.JIRA_PROJECT_URL }}
|
||||
@@ -0,0 +1,17 @@
|
||||
name: Label New Issue
|
||||
|
||||
on:
|
||||
issues:
|
||||
types: opened
|
||||
|
||||
jobs:
|
||||
label_new_issue:
|
||||
uses: AntelopeIO/issue-project-labeler-workflow/.github/workflows/issue-project-labeler.yaml@v1
|
||||
with:
|
||||
issue-id: ${{github.event.issue.node_id}}
|
||||
label: triage
|
||||
org-project: 'Team Backlog'
|
||||
project-field: Status=Todo
|
||||
secrets:
|
||||
token: ${{secrets.ENFCIBOT_REPO_AND_PROJECTS}}
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
*.abi.hpp
|
||||
*.cmake
|
||||
!.cicd
|
||||
!package.cmake
|
||||
!CMakeModules/*.cmake
|
||||
*.ninja
|
||||
\#*
|
||||
|
||||
+12
-6
@@ -7,18 +7,24 @@
|
||||
[submodule "libraries/eos-vm"]
|
||||
path = libraries/eos-vm
|
||||
url = https://github.com/AntelopeIO/eos-vm
|
||||
[submodule "libraries/fc"]
|
||||
path = libraries/fc
|
||||
url = https://github.com/AntelopeIO/fc
|
||||
[submodule "libraries/softfloat"]
|
||||
path = libraries/softfloat
|
||||
url = https://github.com/AntelopeIO/berkeley-softfloat-3
|
||||
[submodule "libraries/rapidjson"]
|
||||
path = libraries/rapidjson
|
||||
url = https://github.com/Tencent/rapidjson/
|
||||
[submodule "libraries/yubihsm"]
|
||||
path = libraries/yubihsm
|
||||
url = https://github.com/Yubico/yubihsm-shell
|
||||
[submodule "tests/abieos"]
|
||||
path = tests/abieos
|
||||
url = https://github.com/AntelopeIO/abieos
|
||||
[submodule "wasm-spec-tests"]
|
||||
path = wasm-spec-tests
|
||||
url = https://github.com/AntelopeIO/wasm-spec-tests
|
||||
[submodule "libraries/libfc/include/fc/crypto/webauthn_json"]
|
||||
path = libraries/libfc/include/fc/crypto/webauthn_json
|
||||
url = https://github.com/Tencent/rapidjson/
|
||||
[submodule "libraries/libfc/secp256k1/secp256k1"]
|
||||
path = libraries/libfc/secp256k1/secp256k1
|
||||
url = https://github.com/bitcoin-core/secp256k1
|
||||
[submodule "libraries/libfc/libraries/ff"]
|
||||
path = libraries/libfc/libraries/ff
|
||||
url = https://github.com/AntelopeIO/libff
|
||||
|
||||
+29
-36
@@ -14,9 +14,9 @@ set( CMAKE_CXX_EXTENSIONS ON )
|
||||
set( CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
set(VERSION_MAJOR 3)
|
||||
set(VERSION_MINOR 1)
|
||||
set(VERSION_PATCH 3)
|
||||
#set(VERSION_SUFFIX rc4)
|
||||
set(VERSION_MINOR 2)
|
||||
set(VERSION_PATCH 0)
|
||||
#set(VERSION_SUFFIX rc2)
|
||||
|
||||
if(VERSION_SUFFIX)
|
||||
set(VERSION_FULL "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}-${VERSION_SUFFIX}")
|
||||
@@ -27,6 +27,7 @@ endif()
|
||||
set( CLI_CLIENT_EXECUTABLE_NAME cleos )
|
||||
set( NODE_EXECUTABLE_NAME nodeos )
|
||||
set( KEY_STORE_EXECUTABLE_NAME keosd )
|
||||
set( LEAP_UTIL_EXECUTABLE_NAME leap-util )
|
||||
|
||||
# http://stackoverflow.com/a/18369825
|
||||
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
|
||||
@@ -53,7 +54,11 @@ set(ENABLE_MULTIVERSION_PROTOCOL_TEST FALSE CACHE BOOL "Enable nodeos multiversi
|
||||
|
||||
# add defaults for openssl
|
||||
if(APPLE AND UNIX AND "${OPENSSL_ROOT_DIR}" STREQUAL "")
|
||||
set(OPENSSL_ROOT_DIR "/usr/local/opt/openssl@3;/usr/local/opt/openssl@1.1")
|
||||
if(CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64")
|
||||
set(OPENSSL_ROOT_DIR "/opt/homebrew/opt/openssl@3;/opt/homebrew/opt/openssl@1.1")
|
||||
else()
|
||||
set(OPENSSL_ROOT_DIR "/usr/local/opt/openssl@3;/usr/local/opt/openssl@1.1")
|
||||
endif()
|
||||
endif()
|
||||
# fc also adds these definitions to its public interface. once fc becomes the sole importer of openssl, this should be removed
|
||||
add_definitions(-DOPENSSL_API_COMPAT=0x10100000L -DOPENSSL_NO_DEPRECATED)
|
||||
@@ -177,13 +182,10 @@ add_subdirectory( scripts )
|
||||
add_subdirectory( unittests )
|
||||
add_subdirectory( tests )
|
||||
add_subdirectory( tools )
|
||||
add_subdirectory( benchmark )
|
||||
|
||||
option(DISABLE_WASM_SPEC_TESTS "disable building of wasm spec unit tests" OFF)
|
||||
|
||||
if (NOT DISABLE_WASM_SPEC_TESTS)
|
||||
add_subdirectory( wasm-spec-tests/generated-tests )
|
||||
endif()
|
||||
|
||||
install(FILES testnet.template DESTINATION ${CMAKE_INSTALL_FULL_SYSCONFDIR}/eosio/launcher COMPONENT dev EXCLUDE_FROM_ALL)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/testnet.template ${CMAKE_CURRENT_BINARY_DIR}/etc/eosio/launcher/testnet.template COPYONLY)
|
||||
|
||||
@@ -213,35 +215,26 @@ install(FILES ${CMAKE_BINARY_DIR}/modules/leap-config.cmake DESTINATION ${CMAKE_
|
||||
install(FILES ${CMAKE_BINARY_DIR}/modules/EosioTester.cmake DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR}/cmake/leap COMPONENT dev EXCLUDE_FROM_ALL)
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/CMakeModules/EosioCheckVersion.cmake DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR}/cmake/leap COMPONENT dev EXCLUDE_FROM_ALL)
|
||||
|
||||
configure_file(${CMAKE_SOURCE_DIR}/LICENSE
|
||||
${CMAKE_BINARY_DIR}/licenses/leap/LICENSE COPYONLY)
|
||||
configure_file(${CMAKE_SOURCE_DIR}/libraries/softfloat/COPYING.txt
|
||||
${CMAKE_BINARY_DIR}/licenses/leap/LICENSE.softfloat COPYONLY)
|
||||
configure_file(${CMAKE_SOURCE_DIR}/libraries/wasm-jit/LICENSE
|
||||
${CMAKE_BINARY_DIR}/licenses/leap/LICENSE.wavm COPYONLY)
|
||||
configure_file(${CMAKE_SOURCE_DIR}/libraries/fc/secp256k1/secp256k1/COPYING
|
||||
${CMAKE_BINARY_DIR}/licenses/leap/LICENSE.secp256k1 COPYONLY)
|
||||
configure_file(${CMAKE_SOURCE_DIR}/libraries/fc/include/fc/crypto/webauthn_json/license.txt
|
||||
${CMAKE_BINARY_DIR}/licenses/leap/LICENSE.rapidjson COPYONLY)
|
||||
configure_file(${CMAKE_SOURCE_DIR}/libraries/fc/src/network/LICENSE.go
|
||||
${CMAKE_BINARY_DIR}/licenses/leap/LICENSE.go COPYONLY)
|
||||
configure_file(${CMAKE_SOURCE_DIR}/libraries/yubihsm/LICENSE
|
||||
${CMAKE_BINARY_DIR}/licenses/leap/LICENSE.yubihsm COPYONLY)
|
||||
configure_file(${CMAKE_SOURCE_DIR}/libraries/eos-vm/LICENSE
|
||||
${CMAKE_BINARY_DIR}/licenses/leap/LICENSE.eos-vm COPYONLY)
|
||||
configure_file(${CMAKE_SOURCE_DIR}/programs/cleos/LICENSE.CLI11
|
||||
${CMAKE_BINARY_DIR}/programs/cleos/LICENSE.CLI11 COPYONLY)
|
||||
configure_file(LICENSE licenses/leap/LICENSE COPYONLY)
|
||||
configure_file(libraries/softfloat/COPYING.txt licenses/leap/LICENSE.softfloat COPYONLY)
|
||||
configure_file(libraries/wasm-jit/LICENSE licenses/leap/LICENSE.wavm COPYONLY)
|
||||
configure_file(libraries/libfc/secp256k1/secp256k1/COPYING licenses/leap/LICENSE.secp256k1 COPYONLY)
|
||||
configure_file(libraries/libfc/include/fc/crypto/webauthn_json/license.txt licenses/leap/LICENSE.rapidjson COPYONLY)
|
||||
configure_file(libraries/libfc/src/network/LICENSE.go licenses/leap/LICENSE.go COPYONLY)
|
||||
configure_file(libraries/eos-vm/LICENSE licenses/leap/LICENSE.eos-vm COPYONLY)
|
||||
configure_file(libraries/libfc/libraries/ff/LICENSE licenses/leap/LICENSE.libff COPYONLY)
|
||||
configure_file(programs/cleos/LICENSE.CLI11 licenses/leap/LICENSE.CLI11 COPYONLY)
|
||||
configure_file(libraries/yubihsm/LICENSE licenses/leap/LICENSE.yubihsm COPYONLY)
|
||||
|
||||
install(FILES LICENSE DESTINATION ${CMAKE_INSTALL_FULL_DATAROOTDIR}/licenses/leap/ COMPONENT base)
|
||||
install(FILES libraries/softfloat/COPYING.txt DESTINATION ${CMAKE_INSTALL_FULL_DATAROOTDIR}/licenses/leap/ RENAME LICENSE.softfloat COMPONENT base)
|
||||
install(FILES libraries/wasm-jit/LICENSE DESTINATION ${CMAKE_INSTALL_FULL_DATAROOTDIR}/licenses/leap/ RENAME LICENSE.wavm COMPONENT base)
|
||||
install(FILES libraries/fc/secp256k1/secp256k1/COPYING DESTINATION ${CMAKE_INSTALL_FULL_DATAROOTDIR}/licenses/leap/ RENAME LICENSE.secp256k1 COMPONENT base)
|
||||
install(FILES libraries/fc/include/fc/crypto/webauthn_json/license.txt DESTINATION ${CMAKE_INSTALL_FULL_DATAROOTDIR}/licenses/leap/ RENAME LICENSE.rapidjson COMPONENT base)
|
||||
install(FILES libraries/fc/src/network/LICENSE.go DESTINATION ${CMAKE_INSTALL_FULL_DATAROOTDIR}/licenses/leap/ COMPONENT base)
|
||||
install(FILES libraries/yubihsm/LICENSE DESTINATION ${CMAKE_INSTALL_FULL_DATAROOTDIR}/licenses/leap/ RENAME LICENSE.yubihsm COMPONENT base)
|
||||
install(FILES libraries/eos-vm/LICENSE DESTINATION ${CMAKE_INSTALL_FULL_DATAROOTDIR}/licenses/leap/ RENAME LICENSE.eos-vm COMPONENT base)
|
||||
install(FILES libraries/fc/libraries/ff/LICENSE DESTINATION ${CMAKE_INSTALL_FULL_DATAROOTDIR}/licenses/leap/ RENAME LICENSE.libff COMPONENT base)
|
||||
install(FILES programs/cleos/LICENSE.CLI11 DESTINATION ${CMAKE_INSTALL_FULL_DATAROOTDIR}/licenses/leap/ COMPONENT base)
|
||||
install(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/licenses/leap" DESTINATION "${CMAKE_INSTALL_FULL_DATAROOTDIR}/licenses/" COMPONENT base)
|
||||
|
||||
configure_file(${CMAKE_SOURCE_DIR}/libraries/cli11/bash-completion/completions/leap-util
|
||||
${CMAKE_BINARY_DIR}/programs/leap-util/bash-completion/completions/leap-util COPYONLY)
|
||||
configure_file(${CMAKE_SOURCE_DIR}/libraries/cli11/bash-completion/completions/cleos
|
||||
${CMAKE_BINARY_DIR}/programs/cleos/bash-completion/completions/cleos COPYONLY)
|
||||
|
||||
install(FILES libraries/cli11/bash-completion/completions/leap-util DESTINATION ${CMAKE_INSTALL_FULL_DATAROOTDIR}/bash-completion/completions COMPONENT base)
|
||||
install(FILES libraries/cli11/bash-completion/completions/cleos DESTINATION ${CMAKE_INSTALL_FULL_DATAROOTDIR}/bash-completion/completions COMPONENT base)
|
||||
|
||||
add_custom_target(dev-install
|
||||
COMMAND "${CMAKE_COMMAND}" --build "${CMAKE_BINARY_DIR}"
|
||||
|
||||
@@ -54,13 +54,8 @@ find_package(Boost @Boost_MAJOR_VERSION@.@Boost_MINOR_VERSION@ EXACT REQUIRED CO
|
||||
|
||||
find_library(libtester eosio_testing @CMAKE_INSTALL_FULL_LIBDIR@ NO_DEFAULT_PATH)
|
||||
find_library(libchain eosio_chain @CMAKE_INSTALL_FULL_LIBDIR@ NO_DEFAULT_PATH)
|
||||
if ( "${CMAKE_BUILD_TYPE}" STREQUAL "Debug" )
|
||||
find_library(libfc fc_debug @CMAKE_INSTALL_FULL_LIBDIR@ NO_DEFAULT_PATH)
|
||||
find_library(libsecp256k1 secp256k1_debug @CMAKE_INSTALL_FULL_LIBDIR@ NO_DEFAULT_PATH)
|
||||
else()
|
||||
find_library(libfc fc @CMAKE_INSTALL_FULL_LIBDIR@ NO_DEFAULT_PATH)
|
||||
find_library(libsecp256k1 secp256k1 @CMAKE_INSTALL_FULL_LIBDIR@ NO_DEFAULT_PATH)
|
||||
endif()
|
||||
find_library(libfc fc @CMAKE_INSTALL_FULL_LIBDIR@ NO_DEFAULT_PATH)
|
||||
find_library(libsecp256k1 secp256k1 @CMAKE_INSTALL_FULL_LIBDIR@ NO_DEFAULT_PATH)
|
||||
|
||||
find_library(libff ff @CMAKE_INSTALL_FULL_LIBDIR@ NO_DEFAULT_PATH)
|
||||
find_library(libwasm WASM @CMAKE_INSTALL_FULL_LIBDIR@ NO_DEFAULT_PATH)
|
||||
|
||||
@@ -51,16 +51,10 @@ find_package(Boost @Boost_MAJOR_VERSION@.@Boost_MINOR_VERSION@ EXACT REQUIRED CO
|
||||
|
||||
find_library(libtester eosio_testing @CMAKE_BINARY_DIR@/libraries/testing NO_DEFAULT_PATH)
|
||||
find_library(libchain eosio_chain @CMAKE_BINARY_DIR@/libraries/chain NO_DEFAULT_PATH)
|
||||
if ( "${CMAKE_BUILD_TYPE}" STREQUAL "Debug" )
|
||||
find_library(libfc fc_debug @CMAKE_BINARY_DIR@/libraries/fc NO_DEFAULT_PATH)
|
||||
find_library(libsecp256k1 secp256k1_debug @CMAKE_BINARY_DIR@/libraries/fc/secp256k1 NO_DEFAULT_PATH)
|
||||
find_library(libfc fc @CMAKE_BINARY_DIR@/libraries/libfc NO_DEFAULT_PATH)
|
||||
find_library(libsecp256k1 secp256k1 @CMAKE_BINARY_DIR@/libraries/libfc/secp256k1 NO_DEFAULT_PATH)
|
||||
|
||||
else()
|
||||
find_library(libfc fc @CMAKE_BINARY_DIR@/libraries/fc NO_DEFAULT_PATH)
|
||||
find_library(libsecp256k1 secp256k1 @CMAKE_BINARY_DIR@/libraries/fc/secp256k1 NO_DEFAULT_PATH)
|
||||
endif()
|
||||
|
||||
find_library(libff ff @CMAKE_BINARY_DIR@/libraries/fc/libraries/ff/libff NO_DEFAULT_PATH)
|
||||
find_library(libff ff @CMAKE_BINARY_DIR@/libraries/libfc/libraries/ff/libff NO_DEFAULT_PATH)
|
||||
find_library(libwasm WASM @CMAKE_BINARY_DIR@/libraries/wasm-jit/Source/WASM NO_DEFAULT_PATH)
|
||||
find_library(libwast WAST @CMAKE_BINARY_DIR@/libraries/wasm-jit/Source/WAST NO_DEFAULT_PATH)
|
||||
find_library(libir IR @CMAKE_BINARY_DIR@/libraries/wasm-jit/Source/IR NO_DEFAULT_PATH)
|
||||
@@ -129,7 +123,7 @@ macro(add_eosio_test_executable test_name)
|
||||
@OPENSSL_INCLUDE_DIR@
|
||||
@CMAKE_SOURCE_DIR@/libraries/chain/include
|
||||
@CMAKE_BINARY_DIR@/libraries/chain/include
|
||||
@CMAKE_SOURCE_DIR@/libraries/fc/include
|
||||
@CMAKE_SOURCE_DIR@/libraries/libfc/include
|
||||
@CMAKE_SOURCE_DIR@/libraries/softfloat/source/include
|
||||
@CMAKE_SOURCE_DIR@/libraries/appbase/include
|
||||
@CMAKE_SOURCE_DIR@/libraries/chainbase/include
|
||||
@@ -176,7 +170,7 @@ if(ENABLE_COVERAGE_TESTING)
|
||||
|
||||
COMMAND ${LCOV_PATH} --directory . --capture --gcov-tool ${CMAKE_SOURCE_DIR}/tools/llvm-gcov.sh --output-file ${Coverage_NAME}.info
|
||||
|
||||
COMMAND ${LCOV_PATH} -remove ${Coverage_NAME}.info '*/boost/*' '/usr/lib/*' '/usr/include/*' '*/externals/*' '*/fc/*' '*/wasm-jit/*' --output-file ${Coverage_NAME}_filtered.info
|
||||
COMMAND ${LCOV_PATH} -remove ${Coverage_NAME}.info '*/boost/*' '/usr/lib/*' '/usr/include/*' '*/externals/*' '*/libfc/*' '*/wasm-jit/*' --output-file ${Coverage_NAME}_filtered.info
|
||||
|
||||
COMMAND ${GENHTML_PATH} -o ${Coverage_NAME} ${PROJECT_BINARY_DIR}/${Coverage_NAME}_filtered.info
|
||||
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
file(GLOB BENCHMARK "*.cpp")
|
||||
add_executable( benchmark ${BENCHMARK} )
|
||||
|
||||
target_link_libraries( benchmark fc Boost::program_options )
|
||||
target_include_directories( benchmark PUBLIC
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
)
|
||||
@@ -0,0 +1,123 @@
|
||||
#include <iostream>
|
||||
|
||||
#include <fc/crypto/alt_bn128.hpp>
|
||||
|
||||
#include <benchmark.hpp>
|
||||
|
||||
namespace benchmark {
|
||||
|
||||
using bytes = std::vector<char>;
|
||||
using g1g2_pair = std::vector<std::string>;
|
||||
|
||||
void add_benchmarking() {
|
||||
std::vector<unsigned char> point1_raw = {
|
||||
12,175,215,144,98,95,151,228,179,85,31,170,172,159,40,255,250,252,68,28,235,65,172,180,69,164,153,29,187,239,220,201, // x
|
||||
18,102,219,76,79,148,120,28,39,149,42,172,41,248,120,249,255,69,42,51,160,239,13,219,239,183,77,174,217,158,130,10,}; // y
|
||||
std::vector<unsigned char> point2_raw = {
|
||||
12,144,10,32,104,85,103,36,222,232,48,152,108,217,40,145,230,48,8,54,0,7,134,164,7,10,139,110,95,205,124,121, // x
|
||||
22,254,176,251,18,168,78,220,142,100,102,113,58,176,83,186,212,62,154,138,235,135,34,46,237,117,54,36,198,40,79,73,}; // y
|
||||
|
||||
bytes point1, point2;
|
||||
point1.insert(point1.begin(), point1_raw.begin(), point1_raw.end());
|
||||
point2.insert(point2.begin(), point2_raw.begin(), point2_raw.end());
|
||||
|
||||
auto f = [&]() {
|
||||
auto res = fc::alt_bn128_add(point1, point2);
|
||||
if (std::holds_alternative<fc::alt_bn128_error>(res)) {
|
||||
std::cout << "alt_bn128_add failed: "
|
||||
<< (int)std::get<fc::alt_bn128_error>(res) << std::endl;
|
||||
}
|
||||
};
|
||||
|
||||
benchmarking("alt_bn128_add", f);
|
||||
}
|
||||
|
||||
void mul_benchmarking() {
|
||||
std::vector<unsigned char> point_raw = {
|
||||
12,175,215,144,98,95,151,228,179,85,31,170,172,159,40,255,250,252,68,28,235,65,172,180,69,164,153,29,187,239,220,201, // x
|
||||
18,102,219,76,79,148,120,28,39,149,42,172,41,248,120,249,255,69,42,51,160,239,13,219,239,183,77,174,217,158,130,10,}; // y
|
||||
std::vector<unsigned char> scaler_raw = {
|
||||
25,62,182,170,104,140,135,90,37,150,0,77,2,77,146,71,54,101,113,69,177,216,157,4,229,213,33,215,169,99,150,91, }; // scaler size 256 bits
|
||||
|
||||
bytes point, scaler;
|
||||
point.insert(point.begin(), point_raw.begin(), point_raw.end());
|
||||
scaler.insert(scaler.begin(), scaler_raw.begin(), scaler_raw.end());
|
||||
|
||||
auto f = [&]() {
|
||||
auto res = fc::alt_bn128_mul(point, scaler);
|
||||
if (std::holds_alternative<fc::alt_bn128_error>(res)) {
|
||||
std::cout << "alt_bn128_mul failed: "
|
||||
<< (int)std::get<fc::alt_bn128_error>(res) << std::endl;
|
||||
}
|
||||
};
|
||||
|
||||
benchmarking("alt_bn128_mul", f);
|
||||
}
|
||||
|
||||
void pair_benchmarking() {
|
||||
std::vector<unsigned char> g1_g2_pairs_raw = {
|
||||
/* pair 1 */
|
||||
12,175,215,144,98,95,151,228,179,85,31,170,172,159,40,255,250,252,68,28,235,65,172,180,69,164,153,29,187,239,220,201,18,102,219,76,79,148,120,28,39,149,42,172,41,248,120,249,255,69,42,51,160,239,13,219,239,183,77,174,217,158,130,10,
|
||||
46,24,234,176,148,82,198,136,44,30,157,18,217,25,49,241,63,197,2,151,14,150,136,210,114,4,74,124,145,225,131,139,13,60,0,50,236,103,39,15,150,226,246,189,209,113,0,46,151,39,41,6,87,119,228,213,45,225,29,234,161,110,43,87,3,237,74,227,93,23,171,129,49,118,228,173,154,111,168,220,161,46,140,103,155,56,168,207,254,90,228,76,188,232,25,34,44,102,159,35,193,216,177,31,131,247,226,19,170,222,26,227,86,37,81,149,202,144,188,126,120,168,9,195,32,169,147,161,
|
||||
/* pair,2,*/
|
||||
12,144,10,32,104,85,103,36,222,232,48,152,108,217,40,145,230,48,8,54,0,7,134,164,7,10,139,110,95,205,124,121,22,254,176,251,18,168,78,220,142,100,102,113,58,176,83,186,212,62,154,138,235,135,34,46,237,117,54,36,198,40,79,73,
|
||||
0,186,148,242,227,252,208,242,165,128,1,160,59,2,6,195,30,54,69,118,8,28,223,92,254,98,110,219,90,92,7,113,26,8,119,98,122,61,119,91,216,107,29,179,122,218,203,6,84,109,119,140,44,12,57,157,203,90,14,108,218,54,94,44,42,77,118,169,232,192,189,60,129,213,156,157,215,160,91,214,138,130,119,145,167,89,237,149,225,85,151,33,89,181,224,235,2,91,213,225,37,226,214,14,255,84,254,117,142,211,28,164,78,254,64,11,126,217,25,124,203,220,52,181,39,32,78,132,
|
||||
/* pair 3 */
|
||||
48,58,116,183,56,3,62,111,104,127,0,7,202,204,146,2,236,192,214,213,231,100,12,17,104,47,76,49,149,39,35,179,2,162,218,104,52,130,61,134,223,111,123,225,186,122,171,2,144,236,110,29,26,142,113,183,238,44,130,30,76,212,52,15,
|
||||
19,206,16,79,220,158,153,194,12,48,10,79,173,10,97,199,113,25,255,87,220,3,102,235,164,170,50,240,177,237,223,205,11,75,211,28,143,229,192,35,171,167,172,238,138,235,82,134,111,165,144,29,118,150,179,21,158,9,202,2,242,109,33,148,14,188,33,145,213,186,0,126,178,10,131,168,121,66,121,193,106,209,176,34,176,41,145,227,3,55,245,150,82,218,232,155,31,153,213,183,157,2,159,247,25,69,49,215,219,36,46,5,192,205,201,182,72,189,84,62,61,47,136,81,51,65,231,161,
|
||||
/* pair 4 */
|
||||
27,31,150,92,17,82,135,210,46,161,0,24,16,199,200,165,29,165,157,168,222,9,83,17,44,27,64,226,208,112,223,128,20,253,182,130,45,130,249,9,168,206,153,86,197,214,59,248,241,191,93,113,70,113,247,244,43,214,240,246,24,38,33,50,
|
||||
23,76,241,195,191,99,69,237,123,173,212,42,74,85,138,108,39,80,105,135,226,11,84,237,39,73,180,224,42,230,246,76,26,61,86,57,253,213,223,2,93,42,38,186,38,38,206,38,209,138,153,181,57,89,16,187,234,2,110,23,12,14,252,240,32,231,237,147,16,62,220,6,160,64,154,167,57,238,243,112,255,35,80,36,100,173,21,58,96,244,77,245,75,202,24,63,35,178,46,215,219,69,120,221,70,119,111,195,145,45,109,84,206,76,254,205,98,167,30,72,117,5,128,129,156,128,196,192,
|
||||
/* pair 5 */
|
||||
33,230,106,254,43,77,114,126,9,205,25,63,9,170,62,237,149,102,198,184,60,31,185,213,103,120,71,249,28,106,238,107,1,133,60,180,58,152,18,177,142,248,46,186,90,34,94,200,235,158,242,255,209,32,143,133,102,195,19,107,153,42,207,228,
|
||||
30,43,165,137,133,231,242,156,65,126,94,159,26,27,78,164,165,159,225,150,220,158,247,118,118,170,195,122,12,125,8,34,39,57,159,231,167,233,3,47,243,142,174,224,162,38,147,65,74,191,98,144,126,125,81,177,75,140,161,27,34,97,46,249,8,65,220,15,139,144,78,12,72,239,54,163,39,6,30,147,154,208,89,111,170,126,6,214,32,181,195,140,215,53,218,239,44,43,229,0,169,242,16,227,163,185,224,21,142,203,135,66,60,53,91,80,48,112,8,13,226,206,58,249,163,52,196,53,
|
||||
/* pair 6 */
|
||||
14,157,100,136,255,206,130,101,56,187,235,39,67,209,67,124,40,174,153,135,155,26,166,170,118,193,244,21,70,71,120,150,3,189,254,120,183,98,23,175,175,28,195,233,165,224,35,95,247,132,40,64,26,208,70,206,247,92,134,105,118,181,21,242,
|
||||
16,159,200,208,93,99,234,139,8,222,239,67,3,187,15,125,5,144,190,196,146,171,15,218,92,36,37,130,2,201,241,182,36,31,104,164,95,29,73,231,87,50,174,142,209,72,31,75,48,13,70,237,118,193,39,85,97,88,228,50,77,163,209,112,7,202,214,212,235,15,224,247,229,179,101,15,72,130,125,8,62,227,46,20,109,53,26,168,10,237,222,85,169,133,181,196,25,36,112,182,41,208,39,132,100,181,199,189,44,99,238,140,6,187,19,197,99,93,243,63,159,132,211,0,230,118,153,54,
|
||||
/* pair 7 */
|
||||
31,60,154,8,188,169,224,107,69,183,223,15,60,32,61,51,81,226,85,38,72,88,241,202,216,204,253,98,0,250,116,167,21,255,0,81,80,3,108,196,240,102,114,33,33,122,116,155,188,19,232,217,42,217,54,195,91,187,88,188,249,218,240,146,
|
||||
12,28,171,60,8,166,151,19,125,237,128,127,207,183,19,1,188,189,105,181,170,172,8,180,30,175,4,108,191,252,197,161,37,122,14,151,117,34,172,227,236,154,84,99,189,197,91,46,43,148,174,218,83,61,196,48,131,45,242,61,92,242,56,251,39,125,111,11,24,37,76,62,151,59,183,3,156,187,249,232,229,56,230,171,55,2,246,70,74,102,0,156,185,237,126,90,0,30,248,164,199,146,66,237,158,134,139,168,128,189,126,55,35,198,48,18,112,40,63,70,254,246,88,111,254,67,213,223,
|
||||
/* pair 8 */
|
||||
27,106,52,232,120,148,201,234,161,123,171,160,223,151,6,105,206,47,94,147,47,22,27,21,248,20,223,51,116,192,29,221,25,149,109,33,131,198,32,101,157,94,62,164,205,151,23,108,214,43,231,7,95,228,183,1,242,205,19,62,124,79,48,203,
|
||||
37,186,150,204,63,241,145,219,169,250,247,76,247,18,135,175,140,58,209,133,113,144,185,191,101,197,252,253,50,126,188,177,45,103,105,194,21,229,145,210,89,135,244,248,238,64,102,155,129,232,252,32,208,82,51,131,113,100,25,174,253,19,211,18,6,77,66,232,173,42,146,120,106,72,92,144,51,233,117,184,113,60,33,118,209,83,119,93,170,253,126,41,58,13,85,111,30,233,117,238,183,18,219,38,216,163,244,98,219,254,156,189,57,246,220,178,17,190,88,84,13,41,8,236,181,155,85,198,
|
||||
/* pair 9 */
|
||||
25,62,182,170,104,140,135,90,37,150,0,77,2,77,146,71,54,101,113,69,177,216,157,4,229,213,33,215,169,99,150,91,5,185,157,10,152,12,220,171,39,188,1,48,87,129,192,101,36,179,99,212,123,207,13,76,89,78,8,154,75,239,117,189,
|
||||
19,87,226,242,101,183,176,42,195,135,40,225,195,207,13,62,60,37,28,251,13,165,96,198,173,250,251,107,25,141,77,68,45,115,128,233,135,104,231,12,192,206,60,249,137,191,114,141,3,235,34,189,208,170,23,59,231,12,197,116,5,188,52,20,11,153,186,15,96,240,54,123,212,242,168,141,151,187,17,38,185,238,196,242,26,194,193,18,34,107,95,238,108,154,140,224,13,76,71,149,81,56,85,83,56,59,203,183,170,10,167,200,128,135,105,19,93,203,131,146,116,209,62,27,81,80,234,172,
|
||||
/* pair 10 */
|
||||
30,204,212,77,212,159,135,173,195,194,165,112,62,248,180,204,66,73,253,99,65,111,39,171,19,211,171,203,35,66,146,20,33,241,46,6,167,133,80,76,238,165,59,232,120,58,211,157,50,212,86,191,95,6,134,164,36,227,79,58,119,98,108,171,
|
||||
48,49,12,141,166,151,158,56,136,255,197,138,114,195,39,59,71,236,82,57,149,249,170,55,187,95,193,171,14,124,45,87,7,157,47,178,153,237,194,157,142,194,100,14,40,51,61,201,244,93,61,196,154,59,14,135,209,72,102,186,14,228,228,152,40,246,109,82,93,249,92,105,191,121,77,108,20,87,3,87,167,173,171,255,189,34,155,239,218,95,181,153,222,20,120,195,27,28,47,82,113,3,218,129,54,210,185,165,206,99,126,61,217,19,237,5,12,90,148,246,128,231,63,53,37,223,204,195
|
||||
};
|
||||
|
||||
// benchmarking 1 pair of points
|
||||
bytes g1_g2_1_pair;
|
||||
g1_g2_1_pair.insert(g1_g2_1_pair.begin(), g1_g2_pairs_raw.begin(), g1_g2_pairs_raw.begin() + 384);
|
||||
auto f_1_pair = [&]() {
|
||||
auto res = fc::alt_bn128_pair(g1_g2_1_pair, [](){});
|
||||
if (std::holds_alternative<fc::alt_bn128_error>(res)) {
|
||||
std::cout << "alt_bn128_pair 1 pair failed: "
|
||||
<< (int)std::get<fc::alt_bn128_error>(res) << std::endl;
|
||||
}
|
||||
};
|
||||
benchmarking("alt_bn128_pair (1 pair)", f_1_pair);
|
||||
|
||||
// benchmarking 10 pair of points
|
||||
bytes g1_g2_10_pairs;
|
||||
g1_g2_10_pairs.insert(g1_g2_10_pairs.begin(), g1_g2_pairs_raw.begin(), g1_g2_pairs_raw.end());
|
||||
auto f_10_pairs = [&]() {
|
||||
auto res = fc::alt_bn128_pair(g1_g2_10_pairs, [](){});
|
||||
if (std::holds_alternative<fc::alt_bn128_error>(res)) {
|
||||
std::cout << "alt_bn128_pair 10 pairs failed: "
|
||||
<< (int)std::get<fc::alt_bn128_error>(res) << std::endl;
|
||||
}
|
||||
};
|
||||
|
||||
benchmarking("alt_bn128_pair (10 pairs)", f_10_pairs);
|
||||
}
|
||||
|
||||
void alt_bn_128_benchmarking() {
|
||||
add_benchmarking();
|
||||
mul_benchmarking();
|
||||
pair_benchmarking();
|
||||
}
|
||||
|
||||
} // benchmark
|
||||
@@ -0,0 +1,82 @@
|
||||
#include <chrono>
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <locale>
|
||||
|
||||
#include <benchmark.hpp>
|
||||
|
||||
namespace benchmark {
|
||||
|
||||
// update this map when a new feature is supported
|
||||
// key is the name and value is the function doing benchmarking
|
||||
std::map<std::string, std::function<void()>> features {
|
||||
{ "alt_bn_128", alt_bn_128_benchmarking },
|
||||
{ "modexp", modexp_benchmarking },
|
||||
{ "key", key_benchmarking },
|
||||
{ "hash", hash_benchmarking },
|
||||
{ "blake2", blake2_benchmarking },
|
||||
};
|
||||
|
||||
// values to control cout format
|
||||
constexpr auto name_width = 28;
|
||||
constexpr auto runs_width = 5;
|
||||
constexpr auto time_width = 12;
|
||||
constexpr auto ns_width = 2;
|
||||
|
||||
uint32_t num_runs = 1;
|
||||
|
||||
std::map<std::string, std::function<void()>> get_features() {
|
||||
return features;
|
||||
}
|
||||
|
||||
void set_num_runs(uint32_t runs) {
|
||||
num_runs = runs;
|
||||
}
|
||||
|
||||
void print_header() {
|
||||
std::cout << std::left << std::setw(name_width) << "function"
|
||||
<< std::setw(runs_width) << "runs"
|
||||
<< std::setw(time_width + ns_width) << std::right << "average"
|
||||
<< std::setw(time_width + ns_width) << "minimum"
|
||||
<< std::setw(time_width + ns_width) << "maximum"
|
||||
<< std::endl << std::endl;
|
||||
}
|
||||
|
||||
void print_results(std::string name, uint32_t runs, uint64_t total, uint64_t min, uint64_t max) {
|
||||
std::cout.imbue(std::locale(""));
|
||||
std::cout
|
||||
<< std::setw(name_width) << std::left << name
|
||||
<< std::setw(runs_width) << runs
|
||||
// std::fixed for not printing 1234 in 1.234e3.
|
||||
// setprecision(0) for not printing fractions
|
||||
<< std::right << std::fixed << std::setprecision(0)
|
||||
<< std::setw(time_width) << total/runs << std::setw(ns_width) << " ns"
|
||||
<< std::setw(time_width) << min << std::setw(ns_width) << " ns"
|
||||
<< std::setw(time_width) << max << std::setw(ns_width) << " ns"
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
bytes to_bytes(const std::string& source) {
|
||||
bytes output(source.length()/2);
|
||||
fc::from_hex(source, output.data(), output.size());
|
||||
return output;
|
||||
};
|
||||
|
||||
void benchmarking(std::string name, const std::function<void()>& func) {
|
||||
uint64_t total {0}, min {std::numeric_limits<uint64_t>::max()}, max {0};
|
||||
|
||||
for (auto i = 0U; i < num_runs; ++i) {
|
||||
auto start_time = std::chrono::high_resolution_clock::now();
|
||||
func();
|
||||
auto end_time = std::chrono::high_resolution_clock::now();
|
||||
|
||||
uint64_t duration = std::chrono::duration_cast<std::chrono::nanoseconds>(end_time - start_time).count();
|
||||
total += duration;
|
||||
min = std::min(min, duration);
|
||||
max = std::max(max, duration);
|
||||
}
|
||||
|
||||
print_results(name, num_runs, total, min, max);
|
||||
}
|
||||
|
||||
} // benchmark
|
||||
@@ -0,0 +1,25 @@
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#include <fc/crypto/hex.hpp>
|
||||
|
||||
namespace benchmark {
|
||||
using bytes = std::vector<char>;
|
||||
|
||||
void set_num_runs(uint32_t runs);
|
||||
std::map<std::string, std::function<void()>> get_features();
|
||||
void print_header();
|
||||
bytes to_bytes(const std::string& source);
|
||||
|
||||
void alt_bn_128_benchmarking();
|
||||
void modexp_benchmarking();
|
||||
void key_benchmarking();
|
||||
void hash_benchmarking();
|
||||
void blake2_benchmarking();
|
||||
|
||||
void benchmarking(std::string name, const std::function<void()>& func);
|
||||
|
||||
} // benchmark
|
||||
@@ -0,0 +1,21 @@
|
||||
#include <fc/crypto/blake2.hpp>
|
||||
|
||||
#include <benchmark.hpp>
|
||||
|
||||
namespace benchmark {
|
||||
|
||||
void blake2_benchmarking() {
|
||||
uint32_t _rounds = 0x0C;
|
||||
bytes _h = to_bytes( "48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b");
|
||||
bytes _m = to_bytes("6162630000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000");
|
||||
bytes _t0_offset = to_bytes("0300000000000000");
|
||||
bytes _t1_offset = to_bytes("0000000000000000");
|
||||
bool _f = false;
|
||||
|
||||
auto blake2_f = [&]() {
|
||||
fc::blake2b(_rounds, _h, _m, _t0_offset, _t1_offset, _f, [](){});;
|
||||
};
|
||||
benchmarking("blake2", blake2_f);
|
||||
}
|
||||
|
||||
} // benchmark
|
||||
@@ -0,0 +1,89 @@
|
||||
#include <fc/crypto/hex.hpp>
|
||||
#include <fc/crypto/sha1.hpp>
|
||||
#include <fc/crypto/sha3.hpp>
|
||||
#include <fc/crypto/sha256.hpp>
|
||||
#include <fc/crypto/sha512.hpp>
|
||||
#include <fc/crypto/ripemd160.hpp>
|
||||
#include <fc/utility.hpp>
|
||||
|
||||
#include <benchmark.hpp>
|
||||
|
||||
using namespace fc;
|
||||
|
||||
namespace benchmark {
|
||||
|
||||
void hash_benchmarking() {
|
||||
std::string small_message = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ01";
|
||||
|
||||
// build a large message
|
||||
constexpr auto large_msg_size = 4096;
|
||||
std::string large_message;
|
||||
large_message.reserve(large_msg_size);
|
||||
uint32_t num_concats = large_msg_size/small_message.length();
|
||||
for (uint32_t i = 0; i < num_concats; ++i) {
|
||||
large_message += small_message;
|
||||
}
|
||||
|
||||
auto sha1_small_msg = [&]() {
|
||||
fc::sha1::hash(small_message);
|
||||
};
|
||||
benchmarking("sha1 (" + std::to_string(small_message.length()) + " bytes)", sha1_small_msg);
|
||||
|
||||
auto sha1_large_msg = [&]() {
|
||||
fc::sha1::hash(large_message);
|
||||
};
|
||||
benchmarking("sha1 (" + std::to_string(large_message.length()) + " bytes)", sha1_large_msg);
|
||||
|
||||
auto sha256_small_msg = [&]() {
|
||||
fc::sha256::hash(small_message);
|
||||
};
|
||||
benchmarking("sha256 (" + std::to_string(small_message.length()) + " bytes)", sha256_small_msg);
|
||||
|
||||
auto sha256_large_msg = [&]() {
|
||||
fc::sha256::hash(large_message);
|
||||
};
|
||||
benchmarking("sha256 (" + std::to_string(large_message.length()) + " bytes)", sha256_large_msg);
|
||||
|
||||
auto sha512_small_msg = [&]() {
|
||||
fc::sha512::hash(small_message);
|
||||
};
|
||||
benchmarking("sha512 (" + std::to_string(small_message.length()) + " bytes)", sha512_small_msg);
|
||||
|
||||
auto sha512_large_msg = [&]() {
|
||||
fc::sha512::hash(large_message);
|
||||
};
|
||||
benchmarking("sha512 (" + std::to_string(large_message.length()) + " bytes)", sha512_large_msg);
|
||||
|
||||
auto ripemd160_small_msg = [&]() {
|
||||
fc::ripemd160::hash(small_message);
|
||||
};
|
||||
benchmarking("ripemd160 (" + std::to_string(small_message.length()) + " bytes)", ripemd160_small_msg);
|
||||
|
||||
auto ripemd160_large_msg = [&]() {
|
||||
fc::ripemd160::hash(large_message);
|
||||
};
|
||||
benchmarking("ripemd160 (" + std::to_string(large_message.length()) + " bytes)", ripemd160_large_msg);
|
||||
|
||||
auto sha3_small_msg = [&]() {
|
||||
fc::sha3::hash(small_message, true);
|
||||
};
|
||||
benchmarking("sha3-256 (" + std::to_string(small_message.length()) + " bytes)", sha3_small_msg);
|
||||
|
||||
auto sha3_large_msg = [&]() {
|
||||
fc::sha3::hash(large_message, true);
|
||||
};
|
||||
benchmarking("sha3-256 (" + std::to_string(large_message.length()) + " bytes)", sha3_large_msg);
|
||||
|
||||
auto keccak_small_msg = [&]() {
|
||||
fc::sha3::hash(small_message, false);
|
||||
};
|
||||
benchmarking("keccak256 (" + std::to_string(small_message.length()) + " bytes)", keccak_small_msg);
|
||||
|
||||
auto keccak_large_msg = [&]() {
|
||||
fc::sha3::hash(large_message, false);
|
||||
};
|
||||
benchmarking("keccak256 (" + std::to_string(large_message.length()) + " bytes)", keccak_large_msg);
|
||||
|
||||
}
|
||||
|
||||
} // benchmark
|
||||
@@ -0,0 +1,109 @@
|
||||
#include <fc/crypto/public_key.hpp>
|
||||
#include <fc/crypto/private_key.hpp>
|
||||
#include <fc/crypto/signature.hpp>
|
||||
#include <fc/crypto/k1_recover.hpp>
|
||||
|
||||
#include <benchmark.hpp>
|
||||
|
||||
using namespace fc::crypto;
|
||||
using namespace fc;
|
||||
using namespace std::literals;
|
||||
|
||||
namespace benchmark {
|
||||
|
||||
void k1_sign_benchmarking() {
|
||||
auto payload = "Test Cases";
|
||||
auto digest = sha256::hash(payload, const_strlen(payload));
|
||||
auto private_key_string = std::string("5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3");
|
||||
auto key = private_key(private_key_string);
|
||||
|
||||
auto sign_non_canonical_f = [&]() {
|
||||
key.sign(digest, false);
|
||||
};
|
||||
benchmarking("k1_sign_non_canonical", sign_non_canonical_f);
|
||||
}
|
||||
|
||||
void k1_recover_benchmarking() {
|
||||
auto signature = to_bytes( "1b323dd47a1dd5592c296ee2ee12e0af38974087a475e99098a440284f19c1f7642fa0baa10a8a3ab800dfdbe987dee68a09b6fa3db45a5cc4f3a5835a1671d4dd");
|
||||
auto digest = to_bytes( "92390316873c5a9d520b28aba61e7a8f00025ac069acd9c4d2a71d775a55fa5f");
|
||||
|
||||
auto recover_f = [&]() {
|
||||
fc::k1_recover(signature, digest);
|
||||
};
|
||||
benchmarking("k1_recover", recover_f);
|
||||
}
|
||||
|
||||
void k1_benchmarking() {
|
||||
k1_sign_benchmarking();
|
||||
k1_recover_benchmarking();
|
||||
}
|
||||
|
||||
void r1_benchmarking() {
|
||||
auto payload = "Test Cases";
|
||||
auto digest = sha256::hash(payload, const_strlen(payload));
|
||||
auto key = private_key::generate<r1::private_key_shim>();
|
||||
|
||||
auto sign_f = [&]() {
|
||||
key.sign(digest);
|
||||
};
|
||||
benchmarking("r1_sign", sign_f);
|
||||
|
||||
auto sig = key.sign(digest);
|
||||
auto recover_f = [&]() {
|
||||
public_key(sig, digest);;
|
||||
};
|
||||
benchmarking("r1_recover", recover_f);
|
||||
}
|
||||
|
||||
static fc::crypto::webauthn::signature make_webauthn_sig(const fc::crypto::r1::private_key& priv_key,
|
||||
std::vector<uint8_t>& auth_data,
|
||||
const std::string& json) {
|
||||
|
||||
//webauthn signature is sha256(auth_data || client_data_hash)
|
||||
fc::sha256 client_data_hash = fc::sha256::hash(json);
|
||||
fc::sha256::encoder e;
|
||||
e.write((char*)auth_data.data(), auth_data.size());
|
||||
e.write(client_data_hash.data(), client_data_hash.data_size());
|
||||
|
||||
r1::compact_signature sig = priv_key.sign_compact(e.result());
|
||||
|
||||
char buff[8192];
|
||||
datastream<char*> ds(buff, sizeof(buff));
|
||||
fc::raw::pack(ds, sig);
|
||||
fc::raw::pack(ds, auth_data);
|
||||
fc::raw::pack(ds, json);
|
||||
ds.seekp(0);
|
||||
|
||||
fc::crypto::webauthn::signature ret;
|
||||
fc::raw::unpack(ds, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void wa_benchmarking() {
|
||||
static const r1::private_key priv = fc::crypto::r1::private_key::generate();
|
||||
static const fc::sha256 d = fc::sha256::hash("sup"s);
|
||||
static const fc::sha256 origin_hash = fc::sha256::hash("fctesting.invalid"s);
|
||||
std::string json = "{\"origin\":\"https://fctesting.invalid\",\"type\":\"webauthn.get\", \"challenge\":\"" + fc::base64url_encode(d.data(), d.data_size()) + "\"}";
|
||||
std::vector<uint8_t> auth_data(37);
|
||||
memcpy(auth_data.data(), origin_hash.data(), sizeof(origin_hash));
|
||||
|
||||
auto sign = [&]() {
|
||||
make_webauthn_sig(priv, auth_data, json);
|
||||
};
|
||||
benchmarking("webauthn_sign", sign);
|
||||
|
||||
auto sig = make_webauthn_sig(priv, auth_data, json);
|
||||
auto recover= [&]() {
|
||||
sig.recover(d, true);
|
||||
};
|
||||
benchmarking("webauthn_recover", recover);
|
||||
}
|
||||
|
||||
void key_benchmarking() {
|
||||
k1_benchmarking();
|
||||
r1_benchmarking();
|
||||
wa_benchmarking();
|
||||
}
|
||||
|
||||
} // benchmark
|
||||
@@ -0,0 +1,80 @@
|
||||
#include <iostream>
|
||||
|
||||
#include <boost/program_options.hpp>
|
||||
|
||||
#include <benchmark.hpp>
|
||||
|
||||
namespace bpo = boost::program_options;
|
||||
using bpo::options_description;
|
||||
using bpo::variables_map;
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
uint32_t num_runs = 1;
|
||||
std::string feature_name;
|
||||
|
||||
auto features = benchmark::get_features();
|
||||
|
||||
options_description cli ("benchmark command line options");
|
||||
cli.add_options()
|
||||
("feature,f", bpo::value<std::string>(), "feature to be benchmarked; if this option is not present, all features are benchmarked.")
|
||||
("list,l", "list of supported features")
|
||||
("runs,r", bpo::value<uint32_t>(&num_runs)->default_value(1000), "the number of times running a function during benchmarking")
|
||||
("help,h", "benchmark functions, and report average, minimum, and maximum execution time in nanoseconds");
|
||||
|
||||
variables_map vmap;
|
||||
try {
|
||||
bpo::store(bpo::parse_command_line(argc, argv, cli), vmap);
|
||||
bpo::notify(vmap);
|
||||
|
||||
if (vmap.count("help") > 0) {
|
||||
cli.print(std::cerr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (vmap.count("list") > 0) {
|
||||
auto first = true;
|
||||
std::cout << "Supported features are ";
|
||||
for (auto& [name, f]: features) {
|
||||
if (first) {
|
||||
first = false;
|
||||
} else {
|
||||
std::cout << ", ";
|
||||
}
|
||||
std::cout << name;
|
||||
}
|
||||
std::cout << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (vmap.count("feature") > 0) {
|
||||
feature_name = vmap["feature"].as<std::string>();
|
||||
if (features.find(feature_name) == features.end()) {
|
||||
std::cout << feature_name << " is not supported" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
} catch (bpo::unknown_option &ex) {
|
||||
std::cerr << ex.what() << std::endl;
|
||||
cli.print (std::cerr);
|
||||
return 1;
|
||||
} catch( ... ) {
|
||||
std::cerr << "unknown exception" << std::endl;
|
||||
}
|
||||
|
||||
benchmark::set_num_runs(num_runs);
|
||||
benchmark::print_header();
|
||||
|
||||
if (feature_name.empty()) {
|
||||
for (auto& [name, f]: features) {
|
||||
std::cout << name << ":" << std::endl;
|
||||
f();
|
||||
std::cout << std::endl;
|
||||
}
|
||||
} else {
|
||||
std::cout << feature_name << ":" << std::endl;
|
||||
features[feature_name]();
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
#include <fc/crypto/modular_arithmetic.hpp>
|
||||
|
||||
#include <random>
|
||||
|
||||
#include <benchmark.hpp>
|
||||
|
||||
namespace benchmark {
|
||||
|
||||
void modexp_benchmarking() {
|
||||
std::mt19937 r(0x11223344);
|
||||
|
||||
auto generate_random_bytes = [](std::mt19937& rand_eng, unsigned int num_bytes) {
|
||||
std::vector<char> result(num_bytes);
|
||||
|
||||
uint_fast32_t v = 0;
|
||||
for(int byte_pos = 0, end = result.size(); byte_pos < end; ++byte_pos) {
|
||||
if ((byte_pos & 0x03) == 0) { // if divisible by 4
|
||||
v = rand_eng();
|
||||
}
|
||||
result[byte_pos] = v & 0xFF;
|
||||
v >>= 8;
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
static constexpr unsigned int start_num_bytes = 128; // 64
|
||||
static constexpr unsigned int end_num_bytes = 256; // 512
|
||||
static constexpr unsigned int delta_num_bytes = 128; // 64
|
||||
|
||||
static_assert(start_num_bytes <= end_num_bytes);
|
||||
static_assert(delta_num_bytes > 0);
|
||||
static_assert((end_num_bytes - start_num_bytes) % delta_num_bytes == 0);
|
||||
|
||||
for (unsigned int n = start_num_bytes, slot = 0; n <= end_num_bytes; n += delta_num_bytes, ++slot) {
|
||||
auto base = generate_random_bytes(r, n);
|
||||
auto exponent = generate_random_bytes(r, n);
|
||||
auto modulus = generate_random_bytes(r, n);
|
||||
|
||||
auto f = [&]() {
|
||||
fc::modexp(base, exponent, modulus);
|
||||
};
|
||||
|
||||
benchmarking(std::to_string(n*8) + " bit width", f);
|
||||
}
|
||||
|
||||
// Running the above benchmark (using commented values for num_trials and *_num_bytes) with a release build on an AMD 3.4 GHz CPU
|
||||
// provides average durations for executing mod_exp for increasing bit sizes for the value.
|
||||
|
||||
// For example: with 512-bit values, the average duration is approximately 40 microseconds; with 1024-bit values, the average duration
|
||||
// is approximately 260 microseconds; with 2048-bit values, the average duration is approximately 2 milliseconds; and, with 4096-bit
|
||||
// values, the average duration is approximately 14 milliseconds.
|
||||
|
||||
// It appears that a model of the average time that scales quadratically with the bit size fits the empirically generated data well.
|
||||
// TODO: See if theoretical analysis of the modular exponentiation algorithm also justifies quadratic scaling.
|
||||
}
|
||||
|
||||
} // benchmark
|
||||
@@ -2,19 +2,19 @@
|
||||
content_title: Build Antelope from Source
|
||||
---
|
||||
|
||||
The shell scripts previously recommended for building the software have been removed in favor of a build process entirely driven by CMake. Those wishing to build from source are now responsible for installing the necessary dependencies. The list of dependencies and the recommended build procedure are in the [`README.md`](https://github.com/AntelopeIO/leap/blob/release/3.1/README.md) file. Instructions are also included for efficiently running the tests.
|
||||
The shell scripts previously recommended for building the software have been removed in favor of a build process entirely driven by CMake. Those wishing to build from source are now responsible for installing the necessary dependencies. The list of dependencies and the recommended build procedure are in the [`README.md`](https://github.com/AntelopeIO/leap/blob/release/3.2/README.md) file. Instructions are also included for efficiently running the tests.
|
||||
|
||||
### Using DUNE
|
||||
As an alternative to building from source, try [Docker Utilities for Node Execution](https://github.com/AntelopeIO/DUNE) for the easiest way to get started and for multi-platform support.
|
||||
|
||||
### Building From Source
|
||||
You can also build and install Leap from source. Instructions for that currently live [here](https://github.com/AntelopeIO/leap/blob/release/3.1/README.md#build-and-install-from-source).
|
||||
You can also build and install Leap from source. Instructions for that currently live [here](https://github.com/AntelopeIO/leap/blob/release/3.2/README.md#build-and-install-from-source).
|
||||
|
||||
#### Building Pinned Build Binary Packages
|
||||
The pinned build instructions have moved [here](https://github.com/AntelopeIO/leap/blob/release/3.1/README.md#pinned-build). You may want to look at the [prerequisites](https://github.com/AntelopeIO/leap/blob/release/3.1/README.md#prerequisites) and our warning on parallelization using the `-j` jobs flag [here](https://github.com/AntelopeIO/leap/blob/release/3.1/README.md#step-3---build) before you build.
|
||||
The pinned build instructions have moved [here](https://github.com/AntelopeIO/leap/blob/release/3.2/README.md#pinned-build). You may want to look at the [prerequisites](https://github.com/AntelopeIO/leap/blob/release/3.2/README.md#prerequisites) and our warning on parallelization using the `-j` jobs flag [here](https://github.com/AntelopeIO/leap/blob/release/3.2/README.md#step-3---build) before you build.
|
||||
|
||||
#### Manual (non "pinned") Build Instructions
|
||||
The unpinned build instructions have moved [here](https://github.com/AntelopeIO/leap/blob/release/3.1/README.md#unpinned-build). You may want to look at the [prerequisites](https://github.com/AntelopeIO/leap/blob/release/3.1/README.md#prerequisites) and our warning on parallelization using the `-j` jobs flag [here](https://github.com/AntelopeIO/leap/blob/release/3.1/README.md#step-3---build) before you build.
|
||||
The unpinned build instructions have moved [here](https://github.com/AntelopeIO/leap/blob/release/3.2/README.md#unpinned-build). You may want to look at the [prerequisites](https://github.com/AntelopeIO/leap/blob/release/3.2/README.md#prerequisites) and our warning on parallelization using the `-j` jobs flag [here](https://github.com/AntelopeIO/leap/blob/release/3.2/README.md#step-3---build) before you build.
|
||||
|
||||
### Running Tests
|
||||
Documentation on available test suites and how to run them has moved [here](https://github.com/AntelopeIO/leap/blob/release/3.1/README.md#test).
|
||||
Documentation on available test suites and how to run them has moved [here](https://github.com/AntelopeIO/leap/blob/release/3.2/README.md#test).
|
||||
|
||||
@@ -64,3 +64,24 @@ Sample `logging.json`:
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Expected Output of Log Levels
|
||||
|
||||
* `error` - Log output that likely requires operator intervention.
|
||||
- Error level logging should be reserved for conditions that are completely unexpected or otherwise need human intervention.
|
||||
- Also used to indicate software errors such as: impossible values for an `enum`, out of bounds array access, null pointers, or other conditions that likely will throw an exception.
|
||||
- *Note*: Currently, there are numerous `error` level logging that likely should be `warn` as they do not require human intervention. The `net_plugin_impl`, for example, has a number of `error` level logs for bad network connections. This is handled and processed correctly. These should be changed to `warn` or `info`.
|
||||
* `warn` - Log output indicating unexpected but recoverable errors.
|
||||
- Although, `warn` level typically does not require human intervention, repeated output of `warn` level logs might indicate actions needed by an operator.
|
||||
- `warn` should not be used simply for conveying information. A `warn` level log is something to take notice of, but not necessarily be concerned about.
|
||||
* `info` (default) - Log output that provides useful information to an operator.
|
||||
- Can be just progress indication or other useful data to a user. Care is taken not to create excessive log output with `info` level logging. For example, no `info` level logging should be produced for every transaction.
|
||||
- For progress indication, some multiple of transactions should be processed between each log output; typically, every 1000 transactions.
|
||||
* `debug` - Useful log output for when non-default logging is enabled.
|
||||
- Answers the question: is this useful information for a user that is monitoring the log output. Care should be taken not to create excessive log output; similar to `info` level logging.
|
||||
- Enabling `debug` level logging should provide greater insight into behavior without overwhelming the output with log entries.
|
||||
- `debug` level should not be used for *trace* level logging; to that end, use `all` (see below).
|
||||
- Like `info`, no `debug` level logging should be produced for every transaction. There are specific transaction level loggers dedicated to transaction level logging: `transaction`, `transaction_trace_failure`, `transaction_trace_success`, `transaction_failure_tracing`, `transaction_success_tracing`.
|
||||
* `all` (trace) - For logging that would be overwhelming if `debug` level logging were used.
|
||||
- Can be used for trace level logging. Only used in a few places and not completely supported.
|
||||
- *Note*: In the future a different logging library may provide better trace level logging support. The current logging framework is not performant enough to enable excess trace level output.
|
||||
|
||||
@@ -4,15 +4,10 @@ set(APPBASE_INSTALL_COMPONENT "dev")
|
||||
set(SOFTFLOAT_INSTALL_COMPONENT "dev")
|
||||
set(EOSVM_INSTALL_COMPONENT "dev")
|
||||
|
||||
add_subdirectory( fc )
|
||||
add_subdirectory( libfc )
|
||||
add_subdirectory( builtins )
|
||||
|
||||
# Suppress warnings on 3rdParty Library
|
||||
add_definitions( -w )
|
||||
add_subdirectory( softfloat )
|
||||
add_subdirectory( wasm-jit )
|
||||
remove_definitions( -w )
|
||||
|
||||
add_subdirectory( chainbase )
|
||||
set(APPBASE_ENABLE_AUTO_VERSION OFF CACHE BOOL "enable automatic discovery of version via 'git describe'")
|
||||
add_subdirectory( appbase )
|
||||
@@ -20,6 +15,7 @@ add_subdirectory( chain )
|
||||
add_subdirectory( testing )
|
||||
add_subdirectory( version )
|
||||
add_subdirectory( state_history )
|
||||
add_subdirectory( cli11 )
|
||||
|
||||
set(USE_EXISTING_SOFTFLOAT ON CACHE BOOL "use pre-exisiting softfloat lib")
|
||||
set(ENABLE_TOOLS OFF CACHE BOOL "Build tools")
|
||||
@@ -31,6 +27,12 @@ if(eos-vm IN_LIST EOSIO_WASM_RUNTIMES OR eos-vm-jit IN_LIST EOSIO_WASM_RUNTIMES)
|
||||
add_subdirectory( eos-vm )
|
||||
endif()
|
||||
|
||||
#yubihsm's openssl discovery is via pkg-config instead of find_package. Help it out on macOS otherwise openssl's pkgconfig
|
||||
# files may not be found down in the /opt/homebrew/opt directory
|
||||
if(APPLE)
|
||||
get_filename_component(OPENSSL_LIB_PATH "${OPENSSL_CRYPTO_LIBRARY}" DIRECTORY)
|
||||
set(ENV{PKG_CONFIG_PATH} "$ENV{PKG_CONFIG_PATH}:${OPENSSL_LIB_PATH}/pkgconfig")
|
||||
endif()
|
||||
set(ENABLE_STATIC ON)
|
||||
set(CMAKE_MACOSX_RPATH OFF)
|
||||
set(BUILD_ONLY_LIB ON CACHE BOOL "Library only build")
|
||||
|
||||
+1
-1
Submodule libraries/appbase updated: 356a489123...78062207ea
@@ -72,6 +72,9 @@ set(CHAIN_WEBASSEMBLY_SOURCES
|
||||
webassembly/transaction.cpp
|
||||
)
|
||||
|
||||
add_library(eosio_rapidjson INTERFACE)
|
||||
target_include_directories(eosio_rapidjson INTERFACE ../rapidjson/include)
|
||||
|
||||
## SORT .cpp by most likely to change / break compile
|
||||
add_library( eosio_chain
|
||||
merkle.cpp
|
||||
@@ -125,7 +128,7 @@ add_library( eosio_chain
|
||||
${HEADERS}
|
||||
)
|
||||
|
||||
target_link_libraries( eosio_chain PUBLIC fc chainbase Logging IR WAST WASM Runtime
|
||||
target_link_libraries( eosio_chain PUBLIC fc chainbase eosio_rapidjson Logging IR WAST WASM Runtime
|
||||
softfloat builtins ${CHAIN_EOSVM_LIBRARIES} ${LLVM_LIBS} ${CHAIN_RT_LINKAGE}
|
||||
)
|
||||
target_include_directories( eosio_chain
|
||||
@@ -162,6 +165,3 @@ install( DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/eosio/chain/
|
||||
FILES_MATCHING PATTERN "*.hpp" PATTERN "*.h" EXCLUDE
|
||||
)
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/include/eosio/chain/core_symbol.hpp DESTINATION ${CMAKE_INSTALL_FULL_INCLUDEDIR}/eosio/chain COMPONENT dev EXCLUDE_FROM_ALL)
|
||||
#if(MSVC)
|
||||
# set_source_files_properties( db_init.cpp db_block.cpp database.cpp block_log.cpp PROPERTIES COMPILE_FLAGS "/bigobj" )
|
||||
#endif(MSVC)
|
||||
|
||||
@@ -77,7 +77,7 @@ namespace eosio { namespace chain {
|
||||
|
||||
abi_serializer::abi_serializer( const abi_def& abi, const fc::microseconds& max_serialization_time) {
|
||||
configure_built_in_types();
|
||||
set_abi(abi, max_serialization_time);
|
||||
set_abi(abi, create_yield_function(max_serialization_time));
|
||||
}
|
||||
|
||||
void abi_serializer::add_specialized_unpack_pack( const string& name,
|
||||
@@ -209,6 +209,19 @@ namespace eosio { namespace chain {
|
||||
return ends_with(type, "[]");
|
||||
}
|
||||
|
||||
bool abi_serializer::is_szarray(const string_view& type)const {
|
||||
auto pos1 = type.find_last_of('[');
|
||||
auto pos2 = type.find_last_of(']');
|
||||
if(pos1 == string_view::npos || pos2 == string_view::npos) return false;
|
||||
auto pos = pos1 + 1;
|
||||
if(pos == pos2) return false;
|
||||
while(pos < pos2) {
|
||||
if( ! (type[pos] >= '0' && type[pos] <= '9') ) return false;
|
||||
++pos;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool abi_serializer::is_optional(const string_view& type)const {
|
||||
return ends_with(type, "?");
|
||||
}
|
||||
@@ -225,6 +238,8 @@ namespace eosio { namespace chain {
|
||||
std::string_view abi_serializer::fundamental_type(const std::string_view& type)const {
|
||||
if( is_array(type) ) {
|
||||
return type.substr(0, type.size()-2);
|
||||
} else if (is_szarray (type) ){
|
||||
return type.substr(0, type.find_last_of('['));
|
||||
} else if ( is_optional(type) ) {
|
||||
return type.substr(0, type.size()-1);
|
||||
} else {
|
||||
@@ -395,10 +410,8 @@ namespace eosio { namespace chain {
|
||||
for( decltype(size.value) i = 0; i < size; ++i ) {
|
||||
ctx.set_array_index_of_path_back(i);
|
||||
auto v = _binary_to_variant(ftype, stream, ctx);
|
||||
// QUESTION: Is it actually desired behavior to require the returned variant to not be null?
|
||||
// This would disallow arrays of optionals in general (though if all optionals in the array were present it would be allowed).
|
||||
// Is there any scenario in which the returned variant would be null other than in the case of an empty optional?
|
||||
EOS_ASSERT( !v.is_null(), unpack_exception, "Invalid packed array '${p}'", ("p", ctx.get_path_string()) );
|
||||
// The exception below is commented out to allow array of optional as input data
|
||||
//EOS_ASSERT( !v.is_null(), unpack_exception, "Invalid packed array '${p}'", ("p", ctx.get_path_string()) );
|
||||
vars.emplace_back(std::move(v));
|
||||
}
|
||||
// QUESTION: Why would the assert below ever fail?
|
||||
|
||||
@@ -71,51 +71,53 @@ void apply_context::exec_one()
|
||||
try {
|
||||
action_return_value.clear();
|
||||
receiver_account = &db.get<account_metadata_object,by_name>( receiver );
|
||||
privileged = receiver_account->is_privileged();
|
||||
auto native = control.find_apply_handler( receiver, act->account, act->name );
|
||||
if( native ) {
|
||||
if( trx_context.enforce_whiteblacklist && control.is_producing_block() ) {
|
||||
control.check_contract_list( receiver );
|
||||
control.check_action_list( act->account, act->name );
|
||||
}
|
||||
(*native)( *this );
|
||||
}
|
||||
|
||||
if( ( receiver_account->code_hash != digest_type() ) &&
|
||||
( !( act->account == config::system_account_name
|
||||
&& act->name == "setcode"_n
|
||||
&& receiver == config::system_account_name )
|
||||
|| control.is_builtin_activated( builtin_protocol_feature_t::forward_setcode )
|
||||
)
|
||||
) {
|
||||
if( trx_context.enforce_whiteblacklist && control.is_producing_block() ) {
|
||||
control.check_contract_list( receiver );
|
||||
control.check_action_list( act->account, act->name );
|
||||
}
|
||||
try {
|
||||
control.get_wasm_interface().apply( receiver_account->code_hash, receiver_account->vm_type, receiver_account->vm_version, *this );
|
||||
} catch( const wasm_exit& ) {}
|
||||
}
|
||||
|
||||
if( !privileged && control.is_builtin_activated( builtin_protocol_feature_t::ram_restrictions ) ) {
|
||||
const size_t checktime_interval = 10;
|
||||
size_t counter = 0;
|
||||
bool not_in_notify_context = (receiver == act->account);
|
||||
const auto end = _account_ram_deltas.end();
|
||||
for( auto itr = _account_ram_deltas.begin(); itr != end; ++itr, ++counter ) {
|
||||
if( counter == checktime_interval ) {
|
||||
trx_context.checktime();
|
||||
counter = 0;
|
||||
if( !(context_free && control.skip_trx_checks()) ) {
|
||||
privileged = receiver_account->is_privileged();
|
||||
auto native = control.find_apply_handler( receiver, act->account, act->name );
|
||||
if( native ) {
|
||||
if( trx_context.enforce_whiteblacklist && control.is_producing_block() ) {
|
||||
control.check_contract_list( receiver );
|
||||
control.check_action_list( act->account, act->name );
|
||||
}
|
||||
if( itr->delta > 0 && itr->account != receiver ) {
|
||||
EOS_ASSERT( not_in_notify_context, unauthorized_ram_usage_increase,
|
||||
"unprivileged contract cannot increase RAM usage of another account within a notify context: ${account}",
|
||||
("account", itr->account)
|
||||
);
|
||||
EOS_ASSERT( has_authorization( itr->account ), unauthorized_ram_usage_increase,
|
||||
"unprivileged contract cannot increase RAM usage of another account that has not authorized the action: ${account}",
|
||||
("account", itr->account)
|
||||
);
|
||||
(*native)( *this );
|
||||
}
|
||||
|
||||
if( ( receiver_account->code_hash != digest_type() ) &&
|
||||
( !( act->account == config::system_account_name
|
||||
&& act->name == "setcode"_n
|
||||
&& receiver == config::system_account_name )
|
||||
|| control.is_builtin_activated( builtin_protocol_feature_t::forward_setcode )
|
||||
)
|
||||
) {
|
||||
if( trx_context.enforce_whiteblacklist && control.is_producing_block() ) {
|
||||
control.check_contract_list( receiver );
|
||||
control.check_action_list( act->account, act->name );
|
||||
}
|
||||
try {
|
||||
control.get_wasm_interface().apply( receiver_account->code_hash, receiver_account->vm_type, receiver_account->vm_version, *this );
|
||||
} catch( const wasm_exit& ) {}
|
||||
}
|
||||
|
||||
if( !privileged && control.is_builtin_activated( builtin_protocol_feature_t::ram_restrictions ) ) {
|
||||
const size_t checktime_interval = 10;
|
||||
size_t counter = 0;
|
||||
bool not_in_notify_context = (receiver == act->account);
|
||||
const auto end = _account_ram_deltas.end();
|
||||
for( auto itr = _account_ram_deltas.begin(); itr != end; ++itr, ++counter ) {
|
||||
if( counter == checktime_interval ) {
|
||||
trx_context.checktime();
|
||||
counter = 0;
|
||||
}
|
||||
if( itr->delta > 0 && itr->account != receiver ) {
|
||||
EOS_ASSERT( not_in_notify_context, unauthorized_ram_usage_increase,
|
||||
"unprivileged contract cannot increase RAM usage of another account within a notify context: ${account}",
|
||||
("account", itr->account)
|
||||
);
|
||||
EOS_ASSERT( has_authorization( itr->account ), unauthorized_ram_usage_increase,
|
||||
"unprivileged contract cannot increase RAM usage of another account that has not authorized the action: ${account}",
|
||||
("account", itr->account)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+150
-64
@@ -1,6 +1,5 @@
|
||||
#include <eosio/chain/block_log.hpp>
|
||||
#include <eosio/chain/exceptions.hpp>
|
||||
#include <fstream>
|
||||
#include <fc/bitutil.hpp>
|
||||
#include <fc/io/cfile.hpp>
|
||||
#include <fc/io/raw.hpp>
|
||||
@@ -49,14 +48,21 @@ namespace eosio { namespace chain {
|
||||
uint32_t first_block_num = 0; //the first number available to read
|
||||
uint32_t index_first_block_num = 0; //the first number in index & the log had it not been pruned
|
||||
std::optional<block_log_prune_config> prune_config;
|
||||
bool not_generate_block_log = false;
|
||||
|
||||
block_log_impl(std::optional<block_log_prune_config> prune_conf) :
|
||||
explicit block_log_impl(std::optional<block_log_prune_config> prune_conf) :
|
||||
prune_config(prune_conf) {
|
||||
if(prune_config) {
|
||||
EOS_ASSERT(prune_config->prune_blocks, block_log_exception, "block log prune configuration requires at least one block");
|
||||
EOS_ASSERT(__builtin_popcount(prune_config->prune_threshold) == 1, block_log_exception, "block log prune threshold must be power of 2");
|
||||
//switch this over to the mask that will be used
|
||||
prune_config->prune_threshold = ~(prune_config->prune_threshold-1);
|
||||
if (prune_config->prune_blocks == 0 ) {
|
||||
// not to generate blocks.log
|
||||
// disable prune log handling by resetting prune_config
|
||||
prune_config.reset();
|
||||
not_generate_block_log = true;
|
||||
} else {
|
||||
EOS_ASSERT(__builtin_popcount(prune_config->prune_threshold) == 1, block_log_exception, "block log prune threshold must be power of 2");
|
||||
//switch this over to the mask that will be used
|
||||
prune_config->prune_threshold = ~(prune_config->prune_threshold-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,6 +71,7 @@ namespace eosio { namespace chain {
|
||||
reopen();
|
||||
}
|
||||
}
|
||||
|
||||
void reopen();
|
||||
|
||||
//close() is called all over the place. Let's make this an explict call to ensure it only is called when
|
||||
@@ -99,13 +106,17 @@ namespace eosio { namespace chain {
|
||||
template<typename T>
|
||||
void reset( const T& t, const signed_block_ptr& genesis_block, uint32_t first_block_num );
|
||||
|
||||
void remove();
|
||||
|
||||
void write( const genesis_state& gs );
|
||||
|
||||
void write( const chain_id_type& chain_id );
|
||||
|
||||
void flush();
|
||||
|
||||
void append(const signed_block_ptr& b);
|
||||
void append(const signed_block_ptr& b, const block_id_type& id, const std::vector<char>& packed_block);
|
||||
|
||||
void update_head(const signed_block_ptr& b, const std::optional<block_id_type>& id={});
|
||||
|
||||
void prune(const fc::log_level& loglevel);
|
||||
|
||||
@@ -291,12 +302,7 @@ namespace eosio { namespace chain {
|
||||
}
|
||||
my->index_first_block_num = my->first_block_num;
|
||||
|
||||
my->head = read_head();
|
||||
if( my->head ) {
|
||||
my->head_id = my->head->calculate_id();
|
||||
} else {
|
||||
my->head_id = {};
|
||||
}
|
||||
my->update_head(read_head());
|
||||
|
||||
my->block_file.seek_end(0);
|
||||
if(is_currently_pruned && my->head) {
|
||||
@@ -355,14 +361,23 @@ namespace eosio { namespace chain {
|
||||
}
|
||||
}
|
||||
|
||||
void block_log::append(const signed_block_ptr& b) {
|
||||
my->append(b);
|
||||
void block_log::append(const signed_block_ptr& b, const block_id_type& id) {
|
||||
my->append(b, id, fc::raw::pack(*b));
|
||||
}
|
||||
|
||||
void detail::block_log_impl::append(const signed_block_ptr& b) {
|
||||
void block_log::append(const signed_block_ptr& b, const block_id_type& id, const std::vector<char>& packed_block) {
|
||||
my->append(b, id, packed_block);
|
||||
}
|
||||
|
||||
void detail::block_log_impl::append(const signed_block_ptr& b, const block_id_type& id, const std::vector<char>& packed_block) {
|
||||
try {
|
||||
EOS_ASSERT( genesis_written_to_block_log, block_log_append_fail, "Cannot append to block log until the genesis is first written" );
|
||||
|
||||
if (not_generate_block_log) {
|
||||
update_head(b, id);
|
||||
return;
|
||||
}
|
||||
|
||||
check_open_files();
|
||||
|
||||
block_file.seek_end(0);
|
||||
@@ -377,13 +392,12 @@ namespace eosio { namespace chain {
|
||||
"Append to index file occuring at wrong position.",
|
||||
("position", (uint64_t) index_file.tellp())
|
||||
("expected", (b->block_num() - index_first_block_num) * sizeof(uint64_t)));
|
||||
auto data = fc::raw::pack(*b);
|
||||
block_file.write(data.data(), data.size());
|
||||
block_file.write(packed_block.data(), packed_block.size());
|
||||
block_file.write((char*)&pos, sizeof(pos));
|
||||
const uint64_t end = block_file.tellp();
|
||||
index_file.write((char*)&pos, sizeof(pos));
|
||||
head = b;
|
||||
head_id = b->calculate_id();
|
||||
|
||||
update_head(b, id);
|
||||
|
||||
if(prune_config) {
|
||||
if((pos&prune_config->prune_threshold) != (end&prune_config->prune_threshold))
|
||||
@@ -398,6 +412,19 @@ namespace eosio { namespace chain {
|
||||
FC_LOG_AND_RETHROW()
|
||||
}
|
||||
|
||||
void detail::block_log_impl::update_head(const signed_block_ptr& b, const std::optional<block_id_type>& id) {
|
||||
head = b;
|
||||
if (id) {
|
||||
head_id = *id;
|
||||
} else {
|
||||
if (head) {
|
||||
head_id = b->calculate_id();
|
||||
} else {
|
||||
head_id = {};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void detail::block_log_impl::prune(const fc::log_level& loglevel) {
|
||||
if(!head)
|
||||
return;
|
||||
@@ -424,6 +451,9 @@ namespace eosio { namespace chain {
|
||||
}
|
||||
|
||||
void block_log::flush() {
|
||||
if (my->not_generate_block_log) {
|
||||
return;
|
||||
}
|
||||
my->flush();
|
||||
}
|
||||
|
||||
@@ -568,7 +598,7 @@ namespace eosio { namespace chain {
|
||||
block_file.write((char*)&totem, sizeof(totem));
|
||||
|
||||
if (first_block) {
|
||||
append(first_block);
|
||||
append(first_block, first_block->calculate_id(), fc::raw::pack(*first_block));
|
||||
} else {
|
||||
head.reset();
|
||||
head_id = {};
|
||||
@@ -591,15 +621,30 @@ namespace eosio { namespace chain {
|
||||
}
|
||||
|
||||
void block_log::reset( const genesis_state& gs, const signed_block_ptr& first_block ) {
|
||||
// At startup, OK to be called in no blocks.log mode from controller.cpp
|
||||
my->reset(gs, first_block, 1);
|
||||
}
|
||||
|
||||
void block_log::reset( const chain_id_type& chain_id, uint32_t first_block_num ) {
|
||||
// At startup, OK to be called in no blocks.log mode from controller.cpp
|
||||
EOS_ASSERT( first_block_num > 1, block_log_exception,
|
||||
"Block log version ${ver} needs to be created with a genesis state if starting from block number 1." );
|
||||
my->reset(chain_id, signed_block_ptr(), first_block_num);
|
||||
}
|
||||
|
||||
void detail::block_log_impl::remove() {
|
||||
close();
|
||||
|
||||
fc::remove( block_file.get_file_path() );
|
||||
fc::remove( index_file.get_file_path() );
|
||||
|
||||
ilog("block log ${l}, block index ${i} removed", ("l", block_file.get_file_path()) ("i", index_file.get_file_path()));
|
||||
}
|
||||
|
||||
void block_log::remove() {
|
||||
my->remove();
|
||||
}
|
||||
|
||||
void detail::block_log_impl::write( const genesis_state& gs ) {
|
||||
auto data = fc::raw::pack(gs);
|
||||
block_file.write(data.data(), data.size());
|
||||
@@ -610,6 +655,10 @@ namespace eosio { namespace chain {
|
||||
}
|
||||
|
||||
signed_block_ptr block_log::read_block(uint64_t pos)const {
|
||||
if (my->not_generate_block_log) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
my->check_open_files();
|
||||
|
||||
my->block_file.seek(pos);
|
||||
@@ -620,6 +669,10 @@ namespace eosio { namespace chain {
|
||||
}
|
||||
|
||||
void block_log::read_block_header(block_header& bh, uint64_t pos)const {
|
||||
if (my->not_generate_block_log) {
|
||||
return;
|
||||
}
|
||||
|
||||
my->check_open_files();
|
||||
|
||||
my->block_file.seek(pos);
|
||||
@@ -630,6 +683,12 @@ namespace eosio { namespace chain {
|
||||
signed_block_ptr block_log::read_block_by_num(uint32_t block_num)const {
|
||||
try {
|
||||
signed_block_ptr b;
|
||||
|
||||
if (my->not_generate_block_log) {
|
||||
// No blocks exist. Avoid cascading failures if going further.
|
||||
return b;
|
||||
}
|
||||
|
||||
uint64_t pos = get_block_pos(block_num);
|
||||
if (pos != npos) {
|
||||
b = read_block(pos);
|
||||
@@ -642,6 +701,9 @@ namespace eosio { namespace chain {
|
||||
|
||||
block_id_type block_log::read_block_id_by_num(uint32_t block_num)const {
|
||||
try {
|
||||
if (my->not_generate_block_log) {
|
||||
return {};
|
||||
}
|
||||
uint64_t pos = get_block_pos(block_num);
|
||||
if (pos != npos) {
|
||||
block_header bh;
|
||||
@@ -665,10 +727,17 @@ namespace eosio { namespace chain {
|
||||
}
|
||||
|
||||
uint64_t block_log::get_block_pos(uint32_t block_num) const {
|
||||
if (my->not_generate_block_log) {
|
||||
return block_log::npos;
|
||||
}
|
||||
return my->get_block_pos(block_num);
|
||||
}
|
||||
|
||||
signed_block_ptr block_log::read_head()const {
|
||||
if (my->not_generate_block_log) {
|
||||
return {};
|
||||
}
|
||||
|
||||
my->check_open_files();
|
||||
|
||||
uint64_t pos;
|
||||
@@ -708,6 +777,11 @@ namespace eosio { namespace chain {
|
||||
}
|
||||
|
||||
void block_log::construct_index() {
|
||||
if (my->not_generate_block_log) {
|
||||
ilog("Not need to construct index in no blocks.log mode (block-log-retain-blocks=0)");
|
||||
return;
|
||||
}
|
||||
|
||||
ilog("Reconstructing Block Log Index...");
|
||||
my->close();
|
||||
|
||||
@@ -1187,31 +1261,29 @@ namespace eosio { namespace chain {
|
||||
}
|
||||
}
|
||||
|
||||
bool block_log::trim_blocklog_front(const fc::path& block_dir, const fc::path& temp_dir, uint32_t truncate_at_block) {
|
||||
using namespace std;
|
||||
EOS_ASSERT( block_dir != temp_dir, block_log_exception, "block_dir and temp_dir need to be different directories" );
|
||||
ilog("In directory ${dir} will trim all blocks before block ${n} from blocks.log and blocks.index.",
|
||||
("dir", block_dir.generic_string())("n", truncate_at_block));
|
||||
bool block_log::extract_block_range(const fc::path& block_dir, const fc::path&output_dir, block_num_type& start, block_num_type& end, bool rename_input) {
|
||||
EOS_ASSERT( block_dir != output_dir, block_log_exception, "block_dir and output_dir need to be different directories" );
|
||||
trim_data original_block_log(block_dir);
|
||||
if (truncate_at_block <= original_block_log.first_block) {
|
||||
ilog("There are no blocks before block ${n} so do nothing.", ("n", truncate_at_block));
|
||||
return false;
|
||||
if(start < original_block_log.first_block) {
|
||||
dlog("Requested start block of ${start} is less than the first available block ${n}; adjusting to ${n}", ("start", start)("n", original_block_log.first_block));
|
||||
start = original_block_log.first_block;
|
||||
}
|
||||
if (truncate_at_block > original_block_log.last_block) {
|
||||
ilog("All blocks are before block ${n} so do nothing (trim front would delete entire blocks.log).", ("n", truncate_at_block));
|
||||
return false;
|
||||
if(end > original_block_log.last_block) {
|
||||
dlog("Requested end block of ${end} is greater than the last available block ${n}; adjusting to ${n}", ("end", end)("n", original_block_log.last_block));
|
||||
end = original_block_log.last_block;
|
||||
}
|
||||
|
||||
ilog("In directory ${output} will create new block log with range ${start}-${end}",
|
||||
("output", output_dir.generic_string())("start", start)("end", end));
|
||||
// ****** create the new block log file and write out the header for the file
|
||||
fc::create_directories(temp_dir);
|
||||
fc::path new_block_filename = temp_dir / "blocks.log";
|
||||
fc::create_directories(output_dir);
|
||||
fc::path new_block_filename = output_dir / "blocks.log";
|
||||
if (fc::remove(new_block_filename)) {
|
||||
ilog("Removing old blocks.out file");
|
||||
ilog("Removing existing blocks.log file");
|
||||
}
|
||||
fc::cfile new_block_file;
|
||||
new_block_file.set_file_path(new_block_filename);
|
||||
// need to open as append since the file doesn't already exist, then reopen without append to allow writing the
|
||||
// file in any order
|
||||
// need to open as write since the file doesn't already exist, then reopen
|
||||
// with read/write to allow writing the file in any order
|
||||
new_block_file.open( LOG_WRITE_C );
|
||||
new_block_file.close();
|
||||
new_block_file.open( LOG_RW_C );
|
||||
@@ -1221,37 +1293,49 @@ namespace eosio { namespace chain {
|
||||
uint32_t version = block_log::max_supported_version;
|
||||
new_block_file.seek(0);
|
||||
new_block_file.write((char*)&version, sizeof(version));
|
||||
new_block_file.write((char*)&truncate_at_block, sizeof(truncate_at_block));
|
||||
new_block_file.write((char*)&start, sizeof(start));
|
||||
|
||||
new_block_file << original_block_log.chain_id;
|
||||
if (start > 1) {
|
||||
new_block_file << original_block_log.chain_id;
|
||||
} else {
|
||||
fc::raw::pack(new_block_file, original_block_log.gs);
|
||||
}
|
||||
|
||||
// append a totem to indicate the division between blocks and header
|
||||
auto totem = block_log::npos;
|
||||
new_block_file.write((char*)&totem, sizeof(totem));
|
||||
|
||||
const auto new_block_file_first_block_pos = new_block_file.tellp();
|
||||
// ****** end of new block log header
|
||||
|
||||
const auto new_block_file_first_block_pos = new_block_file.tellp();
|
||||
|
||||
// copy over remainder of block log to new block log
|
||||
auto buffer = make_unique<char[]>(detail::reverse_iterator::_buf_len);
|
||||
auto buffer = std::make_unique<char[]>(detail::reverse_iterator::_buf_len);
|
||||
char* buf = buffer.get();
|
||||
|
||||
// offset bytes to shift from old blocklog position to new blocklog position
|
||||
const uint64_t original_file_block_pos = original_block_log.block_pos(truncate_at_block);
|
||||
const uint64_t pos_delta = original_file_block_pos - new_block_file_first_block_pos;
|
||||
auto status = fseek(original_block_log.blk_in, 0, SEEK_END);
|
||||
EOS_ASSERT( status == 0, block_log_exception, "blocks.log seek failed" );
|
||||
const uint64_t original_file_start_block_pos = original_block_log.block_pos(start);
|
||||
const uint64_t pos_delta = original_file_start_block_pos - new_block_file_first_block_pos;
|
||||
uint64_t original_file_end_block_pos;
|
||||
if (end == original_block_log.last_block) {
|
||||
auto status = fseek(original_block_log.blk_in, 0, SEEK_END);
|
||||
EOS_ASSERT( status == 0, block_log_exception, "blocks.log seek failed" );
|
||||
original_file_end_block_pos = ftell(original_block_log.blk_in);
|
||||
} else {
|
||||
original_file_end_block_pos = original_block_log.block_pos(end+1);
|
||||
auto status = fseek(original_block_log.blk_in, original_file_end_block_pos, SEEK_SET);
|
||||
EOS_ASSERT( status == 0, block_log_exception, "blocks.log seek failed" );
|
||||
}
|
||||
|
||||
// all blocks to copy to the new blocklog
|
||||
const uint64_t to_write = ftell(original_block_log.blk_in) - original_file_block_pos;
|
||||
const auto pos_size = sizeof(uint64_t);
|
||||
// all bytes to copy to the new blocklog
|
||||
const uint64_t to_write = original_file_end_block_pos - original_file_start_block_pos;
|
||||
|
||||
// start with the last block's position stored at the end of the block
|
||||
uint64_t original_pos = ftell(original_block_log.blk_in) - pos_size;
|
||||
const auto pos_size = sizeof(uint64_t);
|
||||
uint64_t original_pos = original_file_end_block_pos - pos_size;
|
||||
|
||||
const auto num_blocks = original_block_log.last_block - truncate_at_block + 1;
|
||||
const auto num_blocks = end - start + 1;
|
||||
|
||||
fc::path new_index_filename = temp_dir / "blocks.index";
|
||||
fc::path new_index_filename = output_dir / "blocks.index";
|
||||
detail::index_writer index(new_index_filename, num_blocks);
|
||||
|
||||
uint64_t read_size = 0;
|
||||
@@ -1263,10 +1347,11 @@ namespace eosio { namespace chain {
|
||||
}
|
||||
|
||||
// read in the previous contiguous memory into the read buffer
|
||||
const auto start_of_blk_buffer_pos = original_file_block_pos + to_write_remaining - read_size;
|
||||
status = fseek(original_block_log.blk_in, start_of_blk_buffer_pos, SEEK_SET);
|
||||
const auto start_of_blk_buffer_pos = original_file_start_block_pos + to_write_remaining - read_size;
|
||||
auto status = fseek(original_block_log.blk_in, start_of_blk_buffer_pos, SEEK_SET);
|
||||
EOS_ASSERT( status == 0, block_log_exception, "original blocks.log seek failed" );
|
||||
const auto num_read = fread(buf, read_size, 1, original_block_log.blk_in);
|
||||
EOS_ASSERT( num_read == 1, block_log_exception, "blocks.log read failed" );
|
||||
EOS_ASSERT( num_read == 1, block_log_exception, "original blocks.log read failed" );
|
||||
|
||||
// walk this memory section to adjust block position to match the adjusted location
|
||||
// of the block start and store in the new index file
|
||||
@@ -1295,12 +1380,14 @@ namespace eosio { namespace chain {
|
||||
new_block_file.flush();
|
||||
new_block_file.close();
|
||||
|
||||
fc::path old_log = temp_dir / "old.log";
|
||||
rename(original_block_log.block_file_name, old_log);
|
||||
rename(new_block_filename, original_block_log.block_file_name);
|
||||
fc::path old_ind = temp_dir / "old.index";
|
||||
rename(original_block_log.index_file_name, old_ind);
|
||||
rename(new_index_filename, original_block_log.index_file_name);
|
||||
if (rename_input) {
|
||||
fc::path old_log = output_dir / "old.log";
|
||||
rename(original_block_log.block_file_name, old_log);
|
||||
rename(new_block_filename, original_block_log.block_file_name);
|
||||
fc::path old_ind = output_dir / "old.index";
|
||||
rename(original_block_log.index_file_name, old_ind);
|
||||
rename(new_index_filename, original_block_log.index_file_name);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1335,7 +1422,6 @@ namespace eosio { namespace chain {
|
||||
EOS_ASSERT(size == 1, block_log_exception, "invalid format for file ${file}",
|
||||
("file", block_file_name.string()));
|
||||
if (block_log::contains_genesis_state(version, first_block)) {
|
||||
genesis_state gs;
|
||||
fc::raw::unpack(ds, gs);
|
||||
chain_id = gs.compute_chain_id();
|
||||
}
|
||||
@@ -1431,4 +1517,4 @@ namespace eosio { namespace chain {
|
||||
// used only for unit test to adjust the buffer length
|
||||
void block_log_set_buff_len(uint64_t len){
|
||||
eosio::chain::detail::reverse_iterator::_buf_len = len;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,7 +88,7 @@ namespace eosio { namespace chain {
|
||||
|
||||
block_state::block_state( pending_block_header_state&& cur,
|
||||
signed_block_ptr&& b,
|
||||
vector<transaction_metadata_ptr>&& trx_metas,
|
||||
deque<transaction_metadata_ptr>&& trx_metas,
|
||||
const protocol_feature_set& pfs,
|
||||
const std::function<void( block_timestamp_type,
|
||||
const flat_set<digest_type>&,
|
||||
|
||||
+154
-74
@@ -115,22 +115,23 @@ struct building_block {
|
||||
const vector<digest_type>& new_protocol_feature_activations )
|
||||
:_pending_block_header_state( prev.next( when, num_prev_blocks_to_confirm ) )
|
||||
,_new_protocol_feature_activations( new_protocol_feature_activations )
|
||||
,_trx_mroot_or_receipt_digests( digests_t{} )
|
||||
{}
|
||||
|
||||
pending_block_header_state _pending_block_header_state;
|
||||
std::optional<producer_authority_schedule> _new_pending_producer_schedule;
|
||||
vector<digest_type> _new_protocol_feature_activations;
|
||||
size_t _num_new_protocol_features_that_have_activated = 0;
|
||||
vector<transaction_metadata_ptr> _pending_trx_metas;
|
||||
vector<transaction_receipt> _pending_trx_receipts;
|
||||
vector<digest_type> _action_receipt_digests;
|
||||
std::optional<checksum256_type> _transaction_mroot;
|
||||
deque<transaction_metadata_ptr> _pending_trx_metas;
|
||||
deque<transaction_receipt> _pending_trx_receipts; // boost deque in 1.71 with 1024 elements performs better
|
||||
std::variant<checksum256_type, digests_t> _trx_mroot_or_receipt_digests;
|
||||
digests_t _action_receipt_digests;
|
||||
};
|
||||
|
||||
struct assembled_block {
|
||||
block_id_type _id;
|
||||
pending_block_header_state _pending_block_header_state;
|
||||
vector<transaction_metadata_ptr> _trx_metas;
|
||||
deque<transaction_metadata_ptr> _trx_metas;
|
||||
signed_block_ptr _unsigned_block;
|
||||
|
||||
// if the _unsigned_block pre-dates block-signing authorities this may be present.
|
||||
@@ -156,6 +157,7 @@ struct pending_state {
|
||||
block_stage_type _block_stage;
|
||||
controller::block_status _block_status = controller::block_status::incomplete;
|
||||
std::optional<block_id_type> _producer_block_id;
|
||||
controller::block_report _block_report{};
|
||||
|
||||
/** @pre _block_stage cannot hold completed_block alternative */
|
||||
const pending_block_header_state& get_pending_block_header_state()const {
|
||||
@@ -165,17 +167,7 @@ struct pending_state {
|
||||
return std::get<assembled_block>(_block_stage)._pending_block_header_state;
|
||||
}
|
||||
|
||||
const vector<transaction_receipt>& get_trx_receipts()const {
|
||||
if( std::holds_alternative<building_block>(_block_stage) )
|
||||
return std::get<building_block>(_block_stage)._pending_trx_receipts;
|
||||
|
||||
if( std::holds_alternative<assembled_block>(_block_stage) )
|
||||
return std::get<assembled_block>(_block_stage)._unsigned_block->transactions;
|
||||
|
||||
return std::get<completed_block>(_block_stage)._block_state->block->transactions;
|
||||
}
|
||||
|
||||
vector<transaction_metadata_ptr> extract_trx_metas() {
|
||||
deque<transaction_metadata_ptr> extract_trx_metas() {
|
||||
if( std::holds_alternative<building_block>(_block_stage) )
|
||||
return std::move( std::get<building_block>(_block_stage)._pending_trx_metas );
|
||||
|
||||
@@ -247,6 +239,7 @@ struct controller_impl {
|
||||
named_thread_pool thread_pool;
|
||||
platform_timer timer;
|
||||
deep_mind_handler* deep_mind_logger = nullptr;
|
||||
bool okay_to_print_integrity_hash_on_stop = false;
|
||||
#if defined(EOSIO_EOS_VM_RUNTIME_ENABLED) || defined(EOSIO_EOS_VM_JIT_RUNTIME_ENABLED)
|
||||
vm::wasm_allocator wasm_alloc;
|
||||
#endif
|
||||
@@ -411,12 +404,20 @@ struct controller_impl {
|
||||
if( fork_head->dpos_irreversible_blocknum <= lib_num )
|
||||
return;
|
||||
|
||||
const auto branch = fork_db.fetch_branch( fork_head->id, fork_head->dpos_irreversible_blocknum );
|
||||
auto branch = fork_db.fetch_branch( fork_head->id, fork_head->dpos_irreversible_blocknum );
|
||||
try {
|
||||
|
||||
std::vector<std::future<std::vector<char>>> v;
|
||||
v.reserve( branch.size() );
|
||||
for( auto bitr = branch.rbegin(); bitr != branch.rend(); ++bitr ) {
|
||||
v.emplace_back( async_thread_pool( thread_pool.get_executor(), [b=(*bitr)->block]() { return fc::raw::pack(*b); } ) );
|
||||
}
|
||||
auto it = v.begin();
|
||||
|
||||
for( auto bitr = branch.rbegin(); bitr != branch.rend(); ++bitr ) {
|
||||
if( read_mode == db_read_mode::IRREVERSIBLE ) {
|
||||
apply_block( *bitr, controller::block_status::complete, trx_meta_cache_lookup{} );
|
||||
controller::block_report br;
|
||||
apply_block( br, *bitr, controller::block_status::complete, trx_meta_cache_lookup{} );
|
||||
head = (*bitr);
|
||||
fork_db.mark_valid( head );
|
||||
}
|
||||
@@ -425,7 +426,8 @@ struct controller_impl {
|
||||
|
||||
// blog.append could fail due to failures like running out of space.
|
||||
// Do it before commit so that in case it throws, DB can be rolled back.
|
||||
blog.append( (*bitr)->block );
|
||||
blog.append( (*bitr)->block, (*bitr)->id, it->get() );
|
||||
++it;
|
||||
|
||||
db.commit( (*bitr)->block_num );
|
||||
root_id = (*bitr)->id;
|
||||
@@ -440,8 +442,12 @@ struct controller_impl {
|
||||
//db.commit( fork_head->dpos_irreversible_blocknum ); // redundant
|
||||
|
||||
if( root_id != fork_db.root()->id ) {
|
||||
branch.emplace_back(fork_db.root());
|
||||
fork_db.advance_root( root_id );
|
||||
}
|
||||
|
||||
// delete branch in thread pool
|
||||
boost::asio::post( thread_pool.get_executor(), [branch{std::move(branch)}]() {} );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -568,8 +574,6 @@ struct controller_impl {
|
||||
"Snapshot is invalid." );
|
||||
blog.reset( chain_id, lib_num + 1 );
|
||||
}
|
||||
const auto hash = calculate_integrity_hash();
|
||||
ilog( "database initialized with hash: ${hash}", ("hash", hash) );
|
||||
|
||||
init(check_shutdown);
|
||||
ilog( "Finished initialization from snapshot" );
|
||||
@@ -578,6 +582,9 @@ struct controller_impl {
|
||||
shutdown();
|
||||
}
|
||||
|
||||
if (conf.prune_config && conf.prune_config->prune_blocks == 0) {
|
||||
blog.remove();
|
||||
}
|
||||
}
|
||||
|
||||
void startup(std::function<void()> shutdown, std::function<bool()> check_shutdown, const genesis_state& genesis) {
|
||||
@@ -611,6 +618,10 @@ struct controller_impl {
|
||||
blog.reset( genesis, head->block );
|
||||
}
|
||||
init(check_shutdown);
|
||||
|
||||
if (conf.prune_config && conf.prune_config->prune_blocks == 0) {
|
||||
blog.remove();
|
||||
}
|
||||
}
|
||||
|
||||
void startup(std::function<void()> shutdown, std::function<bool()> check_shutdown) {
|
||||
@@ -641,6 +652,10 @@ struct controller_impl {
|
||||
head = fork_db.head();
|
||||
|
||||
init(check_shutdown);
|
||||
|
||||
if (conf.prune_config && conf.prune_config->prune_blocks == 0) {
|
||||
blog.remove();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -695,6 +710,10 @@ struct controller_impl {
|
||||
dm_logger->on_startup(db, head->block_num);
|
||||
}
|
||||
|
||||
if( conf.integrity_hash_on_start )
|
||||
ilog( "chain database started with hash: ${hash}", ("hash", calculate_integrity_hash()) );
|
||||
okay_to_print_integrity_hash_on_stop = true;
|
||||
|
||||
replay( check_shutdown ); // replay any irreversible and reversible blocks ahead of current head
|
||||
|
||||
if( check_shutdown() ) return;
|
||||
@@ -714,7 +733,8 @@ struct controller_impl {
|
||||
pending_head = fork_db.pending_head()
|
||||
) {
|
||||
wlog( "applying branch from fork database ending with block: ${id}", ("id", pending_head->id) );
|
||||
maybe_switch_forks( pending_head, controller::block_status::complete, forked_branch_callback{}, trx_meta_cache_lookup{} );
|
||||
controller::block_report br;
|
||||
maybe_switch_forks( br, pending_head, controller::block_status::complete, forked_branch_callback{}, trx_meta_cache_lookup{} );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -722,6 +742,9 @@ struct controller_impl {
|
||||
~controller_impl() {
|
||||
thread_pool.stop();
|
||||
pending.reset();
|
||||
//only log this not just if configured to, but also if initialization made it to the point we'd log the startup too
|
||||
if(okay_to_print_integrity_hash_on_stop && conf.integrity_hash_on_stop)
|
||||
ilog( "chain database stopped with hash: ${hash}", ("hash", calculate_integrity_hash()) );
|
||||
}
|
||||
|
||||
void add_indices() {
|
||||
@@ -1079,18 +1102,22 @@ struct controller_impl {
|
||||
// The returned scoped_exit should not exceed the lifetime of the pending which existed when make_block_restore_point was called.
|
||||
fc::scoped_exit<std::function<void()>> make_block_restore_point() {
|
||||
auto& bb = std::get<building_block>(pending->_block_stage);
|
||||
auto orig_block_transactions_size = bb._pending_trx_receipts.size();
|
||||
auto orig_state_transactions_size = bb._pending_trx_metas.size();
|
||||
auto orig_trx_receipts_size = bb._pending_trx_receipts.size();
|
||||
auto orig_trx_metas_size = bb._pending_trx_metas.size();
|
||||
auto orig_trx_receipt_digests_size = std::holds_alternative<digests_t>(bb._trx_mroot_or_receipt_digests) ?
|
||||
std::get<digests_t>(bb._trx_mroot_or_receipt_digests).size() : 0;
|
||||
auto orig_action_receipt_digests_size = bb._action_receipt_digests.size();
|
||||
|
||||
std::function<void()> callback = [this,
|
||||
orig_block_transactions_size,
|
||||
orig_state_transactions_size,
|
||||
orig_action_receipt_digests_size]()
|
||||
orig_trx_receipts_size,
|
||||
orig_trx_metas_size,
|
||||
orig_trx_receipt_digests_size,
|
||||
orig_action_receipt_digests_size]()
|
||||
{
|
||||
auto& bb = std::get<building_block>(pending->_block_stage);
|
||||
bb._pending_trx_receipts.resize(orig_block_transactions_size);
|
||||
bb._pending_trx_metas.resize(orig_state_transactions_size);
|
||||
bb._pending_trx_receipts.resize(orig_trx_receipts_size);
|
||||
bb._pending_trx_metas.resize(orig_trx_metas_size);
|
||||
if( std::holds_alternative<digests_t>(bb._trx_mroot_or_receipt_digests) )
|
||||
std::get<digests_t>(bb._trx_mroot_or_receipt_digests).resize(orig_trx_receipt_digests_size);
|
||||
bb._action_receipt_digests.resize(orig_action_receipt_digests_size);
|
||||
};
|
||||
|
||||
@@ -1228,6 +1255,7 @@ struct controller_impl {
|
||||
uint32_t billed_cpu_time_us, bool explicit_billed_cpu_time = false )
|
||||
{ try {
|
||||
|
||||
auto start = fc::time_point::now();
|
||||
const bool validating = !self.is_producing_block();
|
||||
EOS_ASSERT( !validating || explicit_billed_cpu_time, transaction_exception, "validating requires explicit billing" );
|
||||
|
||||
@@ -1267,6 +1295,10 @@ struct controller_impl {
|
||||
trace->scheduled = true;
|
||||
trace->receipt = push_receipt( gtrx.trx_id, transaction_receipt::expired, billed_cpu_time_us, 0 ); // expire the transaction
|
||||
trace->account_ram_delta = account_delta( gtrx.payer, trx_removal_ram_delta );
|
||||
trace->elapsed = fc::time_point::now() - start;
|
||||
pending->_block_report.total_cpu_usage_us += billed_cpu_time_us;
|
||||
pending->_block_report.total_elapsed_time += trace->elapsed;
|
||||
pending->_block_report.total_time += trace->elapsed;
|
||||
emit( self.accepted_transaction, trx );
|
||||
dmlog_applied_transaction(trace);
|
||||
emit( self.applied_transaction, std::tie(trace, trx->packed_trx()) );
|
||||
@@ -1297,7 +1329,7 @@ struct controller_impl {
|
||||
trace->error_code = controller::convert_exception_to_error_code( e );
|
||||
trace->except = e;
|
||||
trace->except_ptr = std::current_exception();
|
||||
trace->elapsed = fc::time_point::now() - trx_context.start;
|
||||
trace->elapsed = fc::time_point::now() - start;
|
||||
|
||||
if (auto dm_logger = get_deep_mind_logger()) {
|
||||
dm_logger->on_fail_deferred();
|
||||
@@ -1341,6 +1373,11 @@ struct controller_impl {
|
||||
|
||||
restore.cancel();
|
||||
|
||||
pending->_block_report.total_net_usage += trace->net_usage;
|
||||
pending->_block_report.total_cpu_usage_us += trace->receipt->cpu_usage_us;
|
||||
pending->_block_report.total_elapsed_time += trace->elapsed;
|
||||
pending->_block_report.total_time += fc::time_point::now() - start;
|
||||
|
||||
return trace;
|
||||
} catch( const disallowed_transaction_extensions_bad_block_exception& ) {
|
||||
throw;
|
||||
@@ -1371,13 +1408,18 @@ struct controller_impl {
|
||||
trace = error_trace;
|
||||
if( !trace->except_ptr ) {
|
||||
trace->account_ram_delta = account_delta( gtrx.payer, trx_removal_ram_delta );
|
||||
trace->elapsed = fc::time_point::now() - start;
|
||||
emit( self.accepted_transaction, trx );
|
||||
dmlog_applied_transaction(trace);
|
||||
emit( self.applied_transaction, std::tie(trace, trx->packed_trx()) );
|
||||
undo_session.squash();
|
||||
pending->_block_report.total_net_usage += trace->net_usage;
|
||||
if( trace->receipt ) pending->_block_report.total_cpu_usage_us += trace->receipt->cpu_usage_us;
|
||||
pending->_block_report.total_elapsed_time += trace->elapsed;
|
||||
pending->_block_report.total_time += trace->elapsed;
|
||||
return trace;
|
||||
}
|
||||
trace->elapsed = fc::time_point::now() - trx_context.start;
|
||||
trace->elapsed = fc::time_point::now() - start;
|
||||
}
|
||||
|
||||
// Only subjective OR hard failure logic below:
|
||||
@@ -1424,6 +1466,11 @@ struct controller_impl {
|
||||
emit( self.applied_transaction, std::tie(trace, trx->packed_trx()) );
|
||||
}
|
||||
|
||||
pending->_block_report.total_net_usage += trace->net_usage;
|
||||
if( trace->receipt ) pending->_block_report.total_cpu_usage_us += trace->receipt->cpu_usage_us;
|
||||
pending->_block_report.total_elapsed_time += trace->elapsed;
|
||||
pending->_block_report.total_time += fc::time_point::now() - start;
|
||||
|
||||
return trace;
|
||||
} FC_CAPTURE_AND_RETHROW() } /// push_scheduled_transaction
|
||||
|
||||
@@ -1442,6 +1489,9 @@ struct controller_impl {
|
||||
r.cpu_usage_us = cpu_usage_us;
|
||||
r.net_usage_words = net_usage_words;
|
||||
r.status = status;
|
||||
auto& bb = std::get<building_block>(pending->_block_stage);
|
||||
if( std::holds_alternative<digests_t>(bb._trx_mroot_or_receipt_digests) )
|
||||
std::get<digests_t>(bb._trx_mroot_or_receipt_digests).emplace_back( r.digest() );
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -1561,6 +1611,13 @@ struct controller_impl {
|
||||
trx_context.squash();
|
||||
}
|
||||
|
||||
if( !trx->read_only ) {
|
||||
pending->_block_report.total_net_usage += trace->net_usage;
|
||||
pending->_block_report.total_cpu_usage_us += trace->receipt->cpu_usage_us;
|
||||
pending->_block_report.total_elapsed_time += trace->elapsed;
|
||||
pending->_block_report.total_time += fc::time_point::now() - start;
|
||||
}
|
||||
|
||||
return trace;
|
||||
} catch( const disallowed_transaction_extensions_bad_block_exception& ) {
|
||||
throw;
|
||||
@@ -1578,9 +1635,14 @@ struct controller_impl {
|
||||
}
|
||||
|
||||
if (!trx->read_only) {
|
||||
emit(self.accepted_transaction, trx);
|
||||
dmlog_applied_transaction(trace);
|
||||
emit(self.applied_transaction, std::tie(trace, trx->packed_trx()));
|
||||
emit(self.accepted_transaction, trx);
|
||||
dmlog_applied_transaction(trace);
|
||||
emit(self.applied_transaction, std::tie(trace, trx->packed_trx()));
|
||||
|
||||
pending->_block_report.total_net_usage += trace->net_usage;
|
||||
if( trace->receipt ) pending->_block_report.total_cpu_usage_us += trace->receipt->cpu_usage_us;
|
||||
pending->_block_report.total_elapsed_time += trace->elapsed;
|
||||
pending->_block_report.total_time += fc::time_point::now() - start;
|
||||
}
|
||||
|
||||
return trace;
|
||||
@@ -1692,7 +1754,7 @@ struct controller_impl {
|
||||
});
|
||||
}
|
||||
|
||||
const auto& gpo = db.get<global_property_object>();
|
||||
const auto& gpo = self.get_global_properties();
|
||||
|
||||
if( gpo.proposed_schedule_block_num && // if there is a proposed schedule that was proposed in a block ...
|
||||
( *gpo.proposed_schedule_block_num <= pbhs.dpos_irreversible_blocknum ) && // ... that has now become irreversible ...
|
||||
@@ -1727,7 +1789,7 @@ struct controller_impl {
|
||||
});
|
||||
in_trx_requiring_checks = true;
|
||||
auto trace = push_transaction( onbtrx, fc::time_point::maximum(), fc::microseconds::maximum(),
|
||||
self.get_global_properties().configuration.min_transaction_cpu_usage, true, 0 );
|
||||
gpo.configuration.min_transaction_cpu_usage, true, 0 );
|
||||
if( trace->except ) {
|
||||
wlog("onblock ${block_num} is REJECTING: ${entire_trace}",("block_num", head->block_num + 1)("entire_trace", trace));
|
||||
}
|
||||
@@ -1763,6 +1825,21 @@ struct controller_impl {
|
||||
|
||||
auto& pbhs = pending->get_pending_block_header_state();
|
||||
|
||||
auto& bb = std::get<building_block>(pending->_block_stage);
|
||||
|
||||
auto action_merkle_fut = async_thread_pool( thread_pool.get_executor(),
|
||||
[ids{std::move( bb._action_receipt_digests )}]() mutable {
|
||||
return merkle( std::move( ids ) );
|
||||
} );
|
||||
const bool calc_trx_merkle = !std::holds_alternative<checksum256_type>(bb._trx_mroot_or_receipt_digests);
|
||||
std::future<checksum256_type> trx_merkle_fut;
|
||||
if( calc_trx_merkle ) {
|
||||
trx_merkle_fut = async_thread_pool( thread_pool.get_executor(),
|
||||
[ids{std::move( std::get<digests_t>(bb._trx_mroot_or_receipt_digests) )}]() mutable {
|
||||
return merkle( std::move( ids ) );
|
||||
} );
|
||||
}
|
||||
|
||||
// Update resource limits:
|
||||
resource_limits.process_account_limit_updates();
|
||||
const auto& chain_config = self.get_global_properties().configuration;
|
||||
@@ -1773,12 +1850,10 @@ struct controller_impl {
|
||||
);
|
||||
resource_limits.process_block_usage(pbhs.block_num);
|
||||
|
||||
auto& bb = std::get<building_block>(pending->_block_stage);
|
||||
|
||||
// Create (unsigned) block:
|
||||
auto block_ptr = std::make_shared<signed_block>( pbhs.make_block_header(
|
||||
bb._transaction_mroot ? *bb._transaction_mroot : calculate_trx_merkle( bb._pending_trx_receipts ),
|
||||
merkle( std::move( std::get<building_block>(pending->_block_stage)._action_receipt_digests ) ),
|
||||
calc_trx_merkle ? trx_merkle_fut.get() : std::get<checksum256_type>(bb._trx_mroot_or_receipt_digests),
|
||||
action_merkle_fut.get(),
|
||||
bb._new_pending_producer_schedule,
|
||||
std::move( bb._new_protocol_feature_activations ),
|
||||
protocol_features.get_protocol_feature_set()
|
||||
@@ -1938,15 +2013,20 @@ struct controller_impl {
|
||||
}
|
||||
|
||||
|
||||
void apply_block( const block_state_ptr& bsp, controller::block_status s, const trx_meta_cache_lookup& trx_lookup )
|
||||
void apply_block( controller::block_report& br, const block_state_ptr& bsp, controller::block_status s,
|
||||
const trx_meta_cache_lookup& trx_lookup )
|
||||
{ try {
|
||||
try {
|
||||
auto start = fc::time_point::now();
|
||||
const signed_block_ptr& b = bsp->block;
|
||||
const auto& new_protocol_feature_activations = bsp->get_new_protocol_feature_activations();
|
||||
|
||||
auto producer_block_id = bsp->id;
|
||||
start_block( b->timestamp, b->confirmed, new_protocol_feature_activations, s, producer_block_id, fc::time_point::maximum() );
|
||||
|
||||
// validated in create_block_state_future()
|
||||
std::get<building_block>(pending->_block_stage)._trx_mroot_or_receipt_digests = b->transaction_mroot;
|
||||
|
||||
const bool existing_trxs_metas = !bsp->trxs_metas().empty();
|
||||
const bool pub_keys_recovered = bsp->is_pub_keys_recovered();
|
||||
const bool skip_auth_checks = self.skip_auth_check();
|
||||
@@ -1981,8 +2061,8 @@ struct controller_impl {
|
||||
transaction_trace_ptr trace;
|
||||
|
||||
size_t packed_idx = 0;
|
||||
const auto& trx_receipts = std::get<building_block>(pending->_block_stage)._pending_trx_receipts;
|
||||
for( const auto& receipt : b->transactions ) {
|
||||
const auto& trx_receipts = std::get<building_block>(pending->_block_stage)._pending_trx_receipts;
|
||||
auto num_pending_receipts = trx_receipts.size();
|
||||
if( std::holds_alternative<packed_transaction>(receipt.trx) ) {
|
||||
const auto& trx_meta = ( use_bsp_cached ? bsp->trxs_metas().at( packed_idx )
|
||||
@@ -2018,9 +2098,6 @@ struct controller_impl {
|
||||
("lhs", r)("rhs", static_cast<const transaction_receipt_header&>(receipt)) );
|
||||
}
|
||||
|
||||
// validated in create_block_state_future()
|
||||
std::get<building_block>(pending->_block_stage)._transaction_mroot = b->transaction_mroot;
|
||||
|
||||
finalize_block();
|
||||
|
||||
auto& ab = std::get<assembled_block>(pending->_block_stage);
|
||||
@@ -2039,7 +2116,9 @@ struct controller_impl {
|
||||
// create completed_block with the existing block_state as we just verified it is the same as assembled_block
|
||||
pending->_block_stage = completed_block{ bsp };
|
||||
|
||||
br = pending->_block_report; // copy before commit block destroys pending
|
||||
commit_block(false);
|
||||
br.total_time = fc::time_point::now() - start;
|
||||
return;
|
||||
} catch ( const std::bad_alloc& ) {
|
||||
throw;
|
||||
@@ -2091,7 +2170,8 @@ struct controller_impl {
|
||||
} );
|
||||
}
|
||||
|
||||
void push_block( std::future<block_state_ptr>& block_state_future,
|
||||
void push_block( controller::block_report& br,
|
||||
std::future<block_state_ptr>& block_state_future,
|
||||
const forked_branch_callback& forked_branch_cb, const trx_meta_cache_lookup& trx_lookup )
|
||||
{
|
||||
controller::block_status s = controller::block_status::complete;
|
||||
@@ -2121,7 +2201,7 @@ struct controller_impl {
|
||||
emit( self.accepted_block_header, bsp );
|
||||
|
||||
if( read_mode != db_read_mode::IRREVERSIBLE ) {
|
||||
maybe_switch_forks( fork_db.pending_head(), s, forked_branch_cb, trx_lookup );
|
||||
maybe_switch_forks( br, fork_db.pending_head(), s, forked_branch_cb, trx_lookup );
|
||||
} else {
|
||||
log_irreversible();
|
||||
}
|
||||
@@ -2165,8 +2245,9 @@ struct controller_impl {
|
||||
|
||||
emit( self.accepted_block_header, bsp );
|
||||
|
||||
controller::block_report br;
|
||||
if( s == controller::block_status::irreversible ) {
|
||||
apply_block( bsp, s, trx_meta_cache_lookup{} );
|
||||
apply_block( br, bsp, s, trx_meta_cache_lookup{} );
|
||||
head = bsp;
|
||||
|
||||
// On replay, log_irreversible is not called and so no irreversible_block signal is emitted.
|
||||
@@ -2180,19 +2261,19 @@ struct controller_impl {
|
||||
} else {
|
||||
EOS_ASSERT( read_mode != db_read_mode::IRREVERSIBLE, block_validate_exception,
|
||||
"invariant failure: cannot replay reversible blocks while in irreversible mode" );
|
||||
maybe_switch_forks( bsp, s, forked_branch_callback{}, trx_meta_cache_lookup{} );
|
||||
maybe_switch_forks( br, bsp, s, forked_branch_callback{}, trx_meta_cache_lookup{} );
|
||||
}
|
||||
|
||||
} FC_LOG_AND_RETHROW( )
|
||||
}
|
||||
|
||||
void maybe_switch_forks( const block_state_ptr& new_head, controller::block_status s,
|
||||
void maybe_switch_forks( controller::block_report& br, const block_state_ptr& new_head, controller::block_status s,
|
||||
const forked_branch_callback& forked_branch_cb, const trx_meta_cache_lookup& trx_lookup )
|
||||
{
|
||||
bool head_changed = true;
|
||||
if( new_head->header.previous == head->id ) {
|
||||
try {
|
||||
apply_block( new_head, s, trx_lookup );
|
||||
apply_block( br, new_head, s, trx_lookup );
|
||||
fork_db.mark_valid( new_head );
|
||||
head = new_head;
|
||||
} catch ( const std::exception& e ) {
|
||||
@@ -2223,8 +2304,9 @@ struct controller_impl {
|
||||
for( auto ritr = branches.first.rbegin(); ritr != branches.first.rend(); ++ritr ) {
|
||||
auto except = std::exception_ptr{};
|
||||
try {
|
||||
apply_block( *ritr, (*ritr)->is_valid() ? controller::block_status::validated
|
||||
: controller::block_status::complete, trx_lookup );
|
||||
br = controller::block_report{};
|
||||
apply_block( br, *ritr, (*ritr)->is_valid() ? controller::block_status::validated
|
||||
: controller::block_status::complete, trx_lookup );
|
||||
fork_db.mark_valid( *ritr );
|
||||
head = *ritr;
|
||||
} catch ( const std::bad_alloc& ) {
|
||||
@@ -2255,7 +2337,8 @@ struct controller_impl {
|
||||
|
||||
// re-apply good blocks
|
||||
for( auto ritr = branches.second.rbegin(); ritr != branches.second.rend(); ++ritr ) {
|
||||
apply_block( *ritr, controller::block_status::validated /* we previously validated these blocks*/, trx_lookup );
|
||||
br = controller::block_report{};
|
||||
apply_block( br, *ritr, controller::block_status::validated /* we previously validated these blocks*/, trx_lookup );
|
||||
head = *ritr;
|
||||
}
|
||||
std::rethrow_exception(except);
|
||||
@@ -2272,8 +2355,8 @@ struct controller_impl {
|
||||
|
||||
} /// push_block
|
||||
|
||||
vector<transaction_metadata_ptr> abort_block() {
|
||||
vector<transaction_metadata_ptr> applied_trxs;
|
||||
deque<transaction_metadata_ptr> abort_block() {
|
||||
deque<transaction_metadata_ptr> applied_trxs;
|
||||
if( pending ) {
|
||||
applied_trxs = pending->extract_trx_metas();
|
||||
pending.reset();
|
||||
@@ -2282,9 +2365,8 @@ struct controller_impl {
|
||||
return applied_trxs;
|
||||
}
|
||||
|
||||
static checksum256_type calculate_trx_merkle( const vector<transaction_receipt>& trxs ) {
|
||||
vector<digest_type> trx_digests;
|
||||
trx_digests.reserve( trxs.size() );
|
||||
static checksum256_type calculate_trx_merkle( const deque<transaction_receipt>& trxs ) {
|
||||
deque<digest_type> trx_digests;
|
||||
for( const auto& a : trxs )
|
||||
trx_digests.emplace_back( a.digest() );
|
||||
|
||||
@@ -2775,7 +2857,7 @@ void controller::start_block( block_timestamp_type when,
|
||||
block_status::incomplete, std::optional<block_id_type>(), deadline );
|
||||
}
|
||||
|
||||
block_state_ptr controller::finalize_block( const signer_callback_type& signer_callback ) {
|
||||
block_state_ptr controller::finalize_block( block_report& br, const signer_callback_type& signer_callback ) {
|
||||
validate_db_available_size();
|
||||
|
||||
my->finalize_block();
|
||||
@@ -2796,6 +2878,8 @@ block_state_ptr controller::finalize_block( const signer_callback_type& signer_c
|
||||
|
||||
my->pending->_block_stage = completed_block{ bsp };
|
||||
|
||||
br = my->pending->_block_report;
|
||||
|
||||
return bsp;
|
||||
}
|
||||
|
||||
@@ -2804,7 +2888,7 @@ void controller::commit_block() {
|
||||
my->commit_block(true);
|
||||
}
|
||||
|
||||
vector<transaction_metadata_ptr> controller::abort_block() {
|
||||
deque<transaction_metadata_ptr> controller::abort_block() {
|
||||
return my->abort_block();
|
||||
}
|
||||
|
||||
@@ -2816,11 +2900,12 @@ std::future<block_state_ptr> controller::create_block_state_future( const block_
|
||||
return my->create_block_state_future( id, b );
|
||||
}
|
||||
|
||||
void controller::push_block( std::future<block_state_ptr>& block_state_future,
|
||||
void controller::push_block( controller::block_report& br,
|
||||
std::future<block_state_ptr>& block_state_future,
|
||||
const forked_branch_callback& forked_branch_cb, const trx_meta_cache_lookup& trx_lookup )
|
||||
{
|
||||
validate_db_available_size();
|
||||
my->push_block( block_state_future, forked_branch_cb, trx_lookup );
|
||||
my->push_block( br, block_state_future, forked_branch_cb, trx_lookup );
|
||||
}
|
||||
|
||||
transaction_trace_ptr controller::push_transaction( const transaction_metadata_ptr& trx,
|
||||
@@ -2976,11 +3061,6 @@ std::optional<block_id_type> controller::pending_producer_block_id()const {
|
||||
return my->pending->_producer_block_id;
|
||||
}
|
||||
|
||||
const vector<transaction_receipt>& controller::get_pending_trx_receipts()const {
|
||||
EOS_ASSERT( my->pending, block_validate_exception, "no pending block" );
|
||||
return my->pending->get_trx_receipts();
|
||||
}
|
||||
|
||||
uint32_t controller::last_irreversible_block_num() const {
|
||||
return my->fork_db.root()->block_num;
|
||||
}
|
||||
@@ -3468,11 +3548,11 @@ std::optional<chain_id_type> controller::extract_chain_id_from_db( const path& s
|
||||
|
||||
if( db.revision() < 1 ) return {};
|
||||
|
||||
return db.get<global_property_object>().chain_id;
|
||||
} catch( const bad_database_version_exception& ) {
|
||||
throw;
|
||||
} catch( ... ) {
|
||||
}
|
||||
auto * gpo = db.find<global_property_object>();
|
||||
if (gpo==nullptr) return {};
|
||||
|
||||
return gpo->chain_id;
|
||||
} catch (std::system_error &) {} // do not propagate db_error_code::not_found" for absent db, so it will be created
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -42,6 +42,7 @@ namespace eosio::chain {
|
||||
case deep_mind_handler::operation_qualifier::none: return "";
|
||||
case deep_mind_handler::operation_qualifier::modify: return "MODIFY_";
|
||||
case deep_mind_handler::operation_qualifier::push: return "PUSH_";
|
||||
default: elog("Unknown operation_qualifier"); return "";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -45,6 +45,7 @@ struct abi_serializer {
|
||||
/// @return string_view of `t` or internal string type
|
||||
std::string_view resolve_type(const std::string_view& t)const;
|
||||
bool is_array(const std::string_view& type)const;
|
||||
bool is_szarray(const std::string_view& type)const;
|
||||
bool is_optional(const std::string_view& type)const;
|
||||
bool is_type( const std::string_view& type, const yield_function_t& yield )const;
|
||||
[[deprecated("use the overload with yield_function_t[=create_yield_function(max_serialization_time)]")]]
|
||||
@@ -366,6 +367,23 @@ namespace impl {
|
||||
mvo(name, std::move(array));
|
||||
}
|
||||
|
||||
/**
|
||||
* template which overloads add for deques of types which contain ABI information in their trees
|
||||
* for these members we call ::add in order to trigger further processing
|
||||
*/
|
||||
template<typename M, typename Resolver, require_abi_t<M> = 1>
|
||||
static void add( mutable_variant_object &mvo, const char* name, const deque<M>& v, Resolver resolver, abi_traverse_context& ctx )
|
||||
{
|
||||
auto h = ctx.enter_scope();
|
||||
deque<fc::variant> array;
|
||||
|
||||
for (const auto& iter: v) {
|
||||
mutable_variant_object elem_mvo;
|
||||
add(elem_mvo, "_", iter, resolver, ctx);
|
||||
array.emplace_back(std::move(elem_mvo["_"]));
|
||||
}
|
||||
mvo(name, std::move(array));
|
||||
}
|
||||
/**
|
||||
* template which overloads add for shared_ptr of types which contain ABI information in their trees
|
||||
* for these members we call ::add in order to trigger further processing
|
||||
@@ -475,7 +493,6 @@ namespace impl {
|
||||
binary_to_variant_context _ctx(*abi, ctx, type);
|
||||
_ctx.short_path = true; // Just to be safe while avoiding the complexity of threading an override boolean all over the place
|
||||
mvo( "data", abi->_binary_to_variant( type, act.data, _ctx ));
|
||||
set_hex_data(mvo, "hex_data", act.data);
|
||||
} catch(...) {
|
||||
// any failure to serialize data, then leave as not serailzed
|
||||
set_hex_data(mvo, "data", act.data);
|
||||
@@ -489,6 +506,7 @@ namespace impl {
|
||||
} catch(...) {
|
||||
set_hex_data(mvo, "data", act.data);
|
||||
}
|
||||
set_hex_data(mvo, "hex_data", act.data);
|
||||
out(name, std::move(mvo));
|
||||
}
|
||||
|
||||
@@ -730,6 +748,24 @@ namespace impl {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* template which overloads extract for deque of types which contain ABI information in their trees
|
||||
* for these members we call ::extract in order to trigger further processing
|
||||
*/
|
||||
template<typename M, typename Resolver, require_abi_t<M> = 1>
|
||||
static void extract( const fc::variant& v, deque<M>& o, Resolver resolver, abi_traverse_context& ctx )
|
||||
{
|
||||
auto h = ctx.enter_scope();
|
||||
const variants& array = v.get_array();
|
||||
o.clear();
|
||||
for( auto itr = array.begin(); itr != array.end(); ++itr ) {
|
||||
M o_iter;
|
||||
extract(*itr, o_iter, resolver, ctx);
|
||||
o.emplace_back(std::move(o_iter));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* template which overloads extract for shared_ptr of types which contain ABI information in their trees
|
||||
* for these members we call ::extract in order to trigger further processing
|
||||
|
||||
@@ -84,6 +84,10 @@ struct permission_level_weight {
|
||||
friend bool operator == ( const permission_level_weight& lhs, const permission_level_weight& rhs ) {
|
||||
return tie( lhs.permission, lhs.weight ) == tie( rhs.permission, rhs.weight );
|
||||
}
|
||||
|
||||
friend bool operator < ( const permission_level_weight& lhs, const permission_level_weight& rhs ) {
|
||||
return tie( lhs.permission, lhs.weight ) < tie( rhs.permission, rhs.weight );
|
||||
}
|
||||
};
|
||||
|
||||
struct key_weight {
|
||||
@@ -93,6 +97,10 @@ struct key_weight {
|
||||
friend bool operator == ( const key_weight& lhs, const key_weight& rhs ) {
|
||||
return tie( lhs.key, lhs.weight ) == tie( rhs.key, rhs.weight );
|
||||
}
|
||||
|
||||
friend bool operator < ( const key_weight& lhs, const key_weight& rhs ) {
|
||||
return tie( lhs.key, lhs.weight ) < tie( rhs.key, rhs.weight );
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -137,6 +145,10 @@ struct wait_weight {
|
||||
friend bool operator == ( const wait_weight& lhs, const wait_weight& rhs ) {
|
||||
return tie( lhs.wait_sec, lhs.weight ) == tie( rhs.wait_sec, rhs.weight );
|
||||
}
|
||||
|
||||
friend bool operator < ( const wait_weight& lhs, const wait_weight& rhs ) {
|
||||
return tie( lhs.wait_sec, lhs.weight ) < tie( rhs.wait_sec, rhs.weight );
|
||||
}
|
||||
};
|
||||
|
||||
namespace config {
|
||||
@@ -191,6 +203,12 @@ struct authority {
|
||||
friend bool operator != ( const authority& lhs, const authority& rhs ) {
|
||||
return tie( lhs.threshold, lhs.keys, lhs.accounts, lhs.waits ) != tie( rhs.threshold, rhs.keys, rhs.accounts, rhs.waits );
|
||||
}
|
||||
|
||||
void sort_fields () {
|
||||
std::sort(std::begin(keys), std::end(keys));
|
||||
std::sort(std::begin(accounts), std::end(accounts));
|
||||
std::sort(std::begin(waits), std::end(waits));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -97,7 +97,7 @@ namespace eosio { namespace chain {
|
||||
signed_block& operator=(signed_block&&) = default;
|
||||
signed_block clone() const { return *this; }
|
||||
|
||||
vector<transaction_receipt> transactions; /// new or generated transactions
|
||||
deque<transaction_receipt> transactions; /// new or generated transactions
|
||||
extensions_type block_extensions;
|
||||
|
||||
flat_multimap<uint16_t, block_extension> validate_and_extract_extensions()const;
|
||||
|
||||
@@ -48,10 +48,13 @@ namespace eosio { namespace chain {
|
||||
block_log(block_log&& other);
|
||||
~block_log();
|
||||
|
||||
void append(const signed_block_ptr& b);
|
||||
void append(const signed_block_ptr& b, const block_id_type& id);
|
||||
void append(const signed_block_ptr& b, const block_id_type& id, const std::vector<char>& packed_block);
|
||||
|
||||
void flush();
|
||||
void reset( const genesis_state& gs, const signed_block_ptr& genesis_block );
|
||||
void reset( const chain_id_type& chain_id, uint32_t first_block_num );
|
||||
void remove(); // remove blocks.log and blocks.index
|
||||
|
||||
signed_block_ptr read_block(uint64_t file_pos)const;
|
||||
void read_block_header(block_header& bh, uint64_t file_pos)const;
|
||||
@@ -91,7 +94,7 @@ namespace eosio { namespace chain {
|
||||
|
||||
static bool is_pruned_log(const fc::path& data_dir);
|
||||
|
||||
static bool trim_blocklog_front(const fc::path& block_dir, const fc::path& temp_dir, uint32_t truncate_at_block);
|
||||
static bool extract_block_range(const fc::path& block_dir, const fc::path&output_dir, block_num_type& start, block_num_type& end, bool rename_input=false);
|
||||
|
||||
private:
|
||||
void open(const fc::path& data_dir);
|
||||
@@ -119,6 +122,7 @@ namespace eosio { namespace chain {
|
||||
FILE* ind_in = nullptr; //C style files for reading blocks.log and blocks.index
|
||||
//we use low level file IO because it is distinctly faster than C++ filebuf or iostream
|
||||
uint64_t first_block_pos = 0; //file position in blocks.log for the first block in the log
|
||||
genesis_state gs;
|
||||
chain_id_type chain_id;
|
||||
|
||||
static constexpr int blknum_offset{14}; //offset from start of block to 4 byte block number, valid for the only allowed versions
|
||||
|
||||
@@ -19,7 +19,7 @@ namespace eosio { namespace chain {
|
||||
|
||||
block_state( pending_block_header_state&& cur,
|
||||
signed_block_ptr&& b, // unsigned block
|
||||
vector<transaction_metadata_ptr>&& trx_metas,
|
||||
deque<transaction_metadata_ptr>&& trx_metas,
|
||||
const protocol_feature_set& pfs,
|
||||
const std::function<void( block_timestamp_type,
|
||||
const flat_set<digest_type>&,
|
||||
@@ -44,24 +44,24 @@ namespace eosio { namespace chain {
|
||||
bool is_valid()const { return validated; }
|
||||
bool is_pub_keys_recovered()const { return _pub_keys_recovered; }
|
||||
|
||||
vector<transaction_metadata_ptr> extract_trxs_metas() {
|
||||
deque<transaction_metadata_ptr> extract_trxs_metas() {
|
||||
_pub_keys_recovered = false;
|
||||
auto result = std::move( _cached_trxs );
|
||||
_cached_trxs.clear();
|
||||
return result;
|
||||
}
|
||||
void set_trxs_metas( vector<transaction_metadata_ptr>&& trxs_metas, bool keys_recovered ) {
|
||||
void set_trxs_metas( deque<transaction_metadata_ptr>&& trxs_metas, bool keys_recovered ) {
|
||||
_pub_keys_recovered = keys_recovered;
|
||||
_cached_trxs = std::move( trxs_metas );
|
||||
}
|
||||
const vector<transaction_metadata_ptr>& trxs_metas()const { return _cached_trxs; }
|
||||
const deque<transaction_metadata_ptr>& trxs_metas()const { return _cached_trxs; }
|
||||
|
||||
bool validated = false;
|
||||
|
||||
bool _pub_keys_recovered = false;
|
||||
/// this data is redundant with the data stored in block, but facilitates
|
||||
/// recapturing transactions when we pop a block
|
||||
vector<transaction_metadata_ptr> _cached_trxs;
|
||||
deque<transaction_metadata_ptr> _cached_trxs;
|
||||
};
|
||||
|
||||
using block_state_ptr = std::shared_ptr<block_state>;
|
||||
|
||||
@@ -85,6 +85,8 @@ namespace eosio { namespace chain {
|
||||
uint32_t maximum_variable_signature_length = chain::config::default_max_variable_signature_length;
|
||||
bool disable_all_subjective_mitigations = false; //< for developer & testing purposes, can be configured using `disable-all-subjective-mitigations` when `EOSIO_DEVELOPER` build option is provided
|
||||
uint32_t terminate_at_block = 0; //< primarily for testing purposes
|
||||
bool integrity_hash_on_start= false;
|
||||
bool integrity_hash_on_stop = false;
|
||||
|
||||
wasm_interface::vm_type wasm_runtime = chain::config::default_wasm_runtime;
|
||||
eosvmoc::config eosvmoc_config;
|
||||
@@ -144,7 +146,7 @@ namespace eosio { namespace chain {
|
||||
/**
|
||||
* @return transactions applied in aborted block
|
||||
*/
|
||||
vector<transaction_metadata_ptr> abort_block();
|
||||
deque<transaction_metadata_ptr> abort_block();
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -162,18 +164,27 @@ namespace eosio { namespace chain {
|
||||
fc::time_point block_deadline, fc::microseconds max_transaction_time,
|
||||
uint32_t billed_cpu_time_us, bool explicit_billed_cpu_time );
|
||||
|
||||
block_state_ptr finalize_block( const signer_callback_type& signer_callback );
|
||||
struct block_report {
|
||||
size_t total_net_usage = 0;
|
||||
size_t total_cpu_usage_us = 0;
|
||||
fc::microseconds total_elapsed_time{};
|
||||
fc::microseconds total_time{};
|
||||
};
|
||||
|
||||
block_state_ptr finalize_block( block_report& br, const signer_callback_type& signer_callback );
|
||||
void sign_block( const signer_callback_type& signer_callback );
|
||||
void commit_block();
|
||||
|
||||
std::future<block_state_ptr> create_block_state_future( const block_id_type& id, const signed_block_ptr& b );
|
||||
|
||||
/**
|
||||
* @param br returns statistics for block
|
||||
* @param block_state_future provide from call to create_block_state_future
|
||||
* @param cb calls cb with forked applied transactions for each forked block
|
||||
* @param trx_lookup user provided lookup function for externally cached transaction_metadata
|
||||
*/
|
||||
void push_block( std::future<block_state_ptr>& block_state_future,
|
||||
void push_block( block_report& br,
|
||||
std::future<block_state_ptr>& block_state_future,
|
||||
const forked_branch_callback& cb,
|
||||
const trx_meta_cache_lookup& trx_lookup );
|
||||
|
||||
@@ -230,8 +241,6 @@ namespace eosio { namespace chain {
|
||||
std::optional<block_id_type> pending_producer_block_id()const;
|
||||
uint32_t pending_block_num()const;
|
||||
|
||||
const vector<transaction_receipt>& get_pending_trx_receipts()const;
|
||||
|
||||
const producer_authority_schedule& active_producers()const;
|
||||
const producer_authority_schedule& pending_producers()const;
|
||||
std::optional<producer_authority_schedule> proposed_producers()const;
|
||||
|
||||
@@ -186,17 +186,6 @@ namespace fc {
|
||||
b = eosio::chain::shared_blob(_s.begin(), _s.end(), b.get_allocator());
|
||||
}
|
||||
|
||||
inline
|
||||
void to_variant( const blob& b, variant& v ) {
|
||||
v = variant(base64_encode(b.data.data(), b.data.size()));
|
||||
}
|
||||
|
||||
inline
|
||||
void from_variant( const variant& v, blob& b ) {
|
||||
string _s = base64_decode(v.as_string());
|
||||
b.data = std::vector<char>(_s.begin(), _s.end());
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void to_variant( const eosio::chain::shared_vector<T>& sv, variant& v ) {
|
||||
to_variant(std::vector<T>(sv.begin(), sv.end()), v);
|
||||
|
||||
@@ -6,11 +6,14 @@
|
||||
namespace eosio { namespace chain {
|
||||
|
||||
/**
|
||||
* @brief limits for a kv database.
|
||||
* @brief limits for a kv database: NOT IN USE for mandel
|
||||
*
|
||||
* Each database (ram or disk, currently) has its own limits for these parameters.
|
||||
* The key and value limits apply when adding or modifying elements. They may be reduced
|
||||
* below existing database entries.
|
||||
*
|
||||
* This has been marked for removal at a later date, when v7 snapshots are deemed necessary.
|
||||
* kv_database_config will be removed as part of that effort.
|
||||
*/
|
||||
struct kv_database_config {
|
||||
std::uint32_t max_key_size = 0; ///< the maximum size in bytes of a key
|
||||
|
||||
@@ -17,6 +17,6 @@ namespace eosio { namespace chain {
|
||||
/**
|
||||
* Calculates the merkle root of a set of digests, if ids is odd it will duplicate the last id.
|
||||
*/
|
||||
digest_type merkle( vector<digest_type> ids );
|
||||
digest_type merkle( deque<digest_type> ids );
|
||||
|
||||
} } /// eosio::chain
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <eosio/chain/config.hpp>
|
||||
#include <eosio/chain/trace.hpp>
|
||||
#include <eosio/chain/snapshot.hpp>
|
||||
#include <eosio/chain/block_timestamp.hpp>
|
||||
#include <chainbase/chainbase.hpp>
|
||||
#include <set>
|
||||
|
||||
@@ -56,6 +57,8 @@ namespace eosio { namespace chain {
|
||||
int64_t used = 0; ///< quantity used in current window
|
||||
int64_t available = 0; ///< quantity available in current window (based upon fractional reserve)
|
||||
int64_t max = 0; ///< max per window under current congestion
|
||||
block_timestamp_type last_usage_update_time; ///< last usage timestamp
|
||||
int64_t current_used = 0; ///< current usage according to the given timestamp
|
||||
};
|
||||
|
||||
class resource_limits_manager {
|
||||
@@ -102,8 +105,10 @@ namespace eosio { namespace chain {
|
||||
std::pair<int64_t, bool> get_account_cpu_limit( const account_name& name, uint32_t greylist_limit = config::maximum_elastic_resource_multiplier ) const;
|
||||
std::pair<int64_t, bool> get_account_net_limit( const account_name& name, uint32_t greylist_limit = config::maximum_elastic_resource_multiplier ) const;
|
||||
|
||||
std::pair<account_resource_limit, bool> get_account_cpu_limit_ex( const account_name& name, uint32_t greylist_limit = config::maximum_elastic_resource_multiplier ) const;
|
||||
std::pair<account_resource_limit, bool> get_account_net_limit_ex( const account_name& name, uint32_t greylist_limit = config::maximum_elastic_resource_multiplier ) const;
|
||||
std::pair<account_resource_limit, bool>
|
||||
get_account_cpu_limit_ex( const account_name& name, uint32_t greylist_limit = config::maximum_elastic_resource_multiplier, const std::optional<block_timestamp_type>& current_time={} ) const;
|
||||
std::pair<account_resource_limit, bool>
|
||||
get_account_net_limit_ex( const account_name& name, uint32_t greylist_limit = config::maximum_elastic_resource_multiplier, const std::optional<block_timestamp_type>& current_time={} ) const;
|
||||
|
||||
int64_t get_account_ram_usage( const account_name& name ) const;
|
||||
|
||||
@@ -113,6 +118,6 @@ namespace eosio { namespace chain {
|
||||
};
|
||||
} } } /// eosio::chain
|
||||
|
||||
FC_REFLECT( eosio::chain::resource_limits::account_resource_limit, (used)(available)(max) )
|
||||
FC_REFLECT( eosio::chain::resource_limits::account_resource_limit, (used)(available)(max)(last_usage_update_time)(current_used) )
|
||||
FC_REFLECT( eosio::chain::resource_limits::ratio, (numerator)(denominator))
|
||||
FC_REFLECT( eosio::chain::resource_limits::elastic_limit_parameters, (target)(max)(periods)(max_multiplier)(contract_rate)(expand_rate))
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include <fc/variant_object.hpp>
|
||||
#include <boost/core/demangle.hpp>
|
||||
#include <ostream>
|
||||
#include <memory>
|
||||
|
||||
namespace eosio { namespace chain {
|
||||
/**
|
||||
@@ -272,11 +273,6 @@ namespace eosio { namespace chain {
|
||||
read_section(detail::snapshot_section_traits<T>::section_name(), f);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool has_section(const std::string& suffix = std::string()) {
|
||||
return has_section(suffix + detail::snapshot_section_traits<T>::section_name());
|
||||
}
|
||||
|
||||
virtual void validate() const = 0;
|
||||
|
||||
virtual void return_to_header() = 0;
|
||||
@@ -284,7 +280,6 @@ namespace eosio { namespace chain {
|
||||
virtual ~snapshot_reader(){};
|
||||
|
||||
protected:
|
||||
virtual bool has_section( const std::string& section_name ) = 0;
|
||||
virtual void set_section( const std::string& section_name ) = 0;
|
||||
virtual bool read_row( detail::abstract_snapshot_row_reader& row_reader ) = 0;
|
||||
virtual bool empty( ) = 0;
|
||||
@@ -313,7 +308,6 @@ namespace eosio { namespace chain {
|
||||
explicit variant_snapshot_reader(const fc::variant& snapshot);
|
||||
|
||||
void validate() const override;
|
||||
bool has_section( const string& section_name ) override;
|
||||
void set_section( const string& section_name ) override;
|
||||
bool read_row( detail::abstract_snapshot_row_reader& row_reader ) override;
|
||||
bool empty ( ) override;
|
||||
@@ -342,7 +336,22 @@ namespace eosio { namespace chain {
|
||||
std::streampos header_pos;
|
||||
std::streampos section_pos;
|
||||
uint64_t row_count;
|
||||
};
|
||||
|
||||
class ostream_json_snapshot_writer : public snapshot_writer {
|
||||
public:
|
||||
explicit ostream_json_snapshot_writer(std::ostream& snapshot);
|
||||
|
||||
void write_start_section( const std::string& section_name ) override;
|
||||
void write_row( const detail::abstract_snapshot_row_writer& row_writer ) override;
|
||||
void write_end_section() override;
|
||||
void finalize();
|
||||
|
||||
static const uint32_t magic_number = 0x30510550;
|
||||
|
||||
private:
|
||||
detail::ostream_wrapper snapshot;
|
||||
uint64_t row_count;
|
||||
};
|
||||
|
||||
class istream_snapshot_reader : public snapshot_reader {
|
||||
@@ -350,7 +359,6 @@ namespace eosio { namespace chain {
|
||||
explicit istream_snapshot_reader(std::istream& snapshot);
|
||||
|
||||
void validate() const override;
|
||||
bool has_section( const string& section_name ) override;
|
||||
void set_section( const string& section_name ) override;
|
||||
bool read_row( detail::abstract_snapshot_row_reader& row_reader ) override;
|
||||
bool empty ( ) override;
|
||||
@@ -366,6 +374,24 @@ namespace eosio { namespace chain {
|
||||
uint64_t cur_row;
|
||||
};
|
||||
|
||||
class istream_json_snapshot_reader : public snapshot_reader {
|
||||
public:
|
||||
explicit istream_json_snapshot_reader(const fc::path& p);
|
||||
~istream_json_snapshot_reader();
|
||||
|
||||
void validate() const override;
|
||||
void set_section( const string& section_name ) override;
|
||||
bool read_row( detail::abstract_snapshot_row_reader& row_reader ) override;
|
||||
bool empty ( ) override;
|
||||
void clear_section() override;
|
||||
void return_to_header() override;
|
||||
|
||||
private:
|
||||
bool validate_section() const;
|
||||
|
||||
std::unique_ptr<struct istream_json_snapshot_reader_impl> impl;
|
||||
};
|
||||
|
||||
class integrity_hash_snapshot_writer : public snapshot_writer {
|
||||
public:
|
||||
explicit integrity_hash_snapshot_writer(fc::sha256::encoder& enc);
|
||||
|
||||
@@ -165,6 +165,25 @@ namespace eosio {
|
||||
return lhs.value() > rhs.value();
|
||||
}
|
||||
|
||||
inline bool operator== (const extended_symbol& lhs, const extended_symbol& rhs)
|
||||
{
|
||||
return std::tie(lhs.sym, lhs.contract) == std::tie(rhs.sym, rhs.contract);
|
||||
}
|
||||
|
||||
inline bool operator!= (const extended_symbol& lhs, const extended_symbol& rhs)
|
||||
{
|
||||
return std::tie(lhs.sym, lhs.contract) != std::tie(rhs.sym, rhs.contract);
|
||||
}
|
||||
|
||||
inline bool operator< (const extended_symbol& lhs, const extended_symbol& rhs)
|
||||
{
|
||||
return std::tie(lhs.sym, lhs.contract) < std::tie(rhs.sym, rhs.contract);
|
||||
}
|
||||
|
||||
inline bool operator> (const extended_symbol& lhs, const extended_symbol& rhs)
|
||||
{
|
||||
return std::tie(lhs.sym, lhs.contract) > std::tie(rhs.sym, rhs.contract);
|
||||
}
|
||||
} // namespace chain
|
||||
} // namespace eosio
|
||||
|
||||
|
||||
@@ -49,12 +49,6 @@ namespace eosio { namespace chain {
|
||||
* with a block_header::timestamp greater than expiration is
|
||||
* deemed irreversible, then a user can safely trust the transaction
|
||||
* will never be included.
|
||||
*
|
||||
|
||||
* Each region is an independent blockchain, it is included as routing
|
||||
* information for inter-blockchain communication. A contract in this
|
||||
* region might generate or authorize a transaction intended for a foreign
|
||||
* region.
|
||||
*/
|
||||
struct transaction_header {
|
||||
time_point_sec expiration; ///< the time at which a transaction expires
|
||||
@@ -76,7 +70,7 @@ namespace eosio { namespace chain {
|
||||
};
|
||||
|
||||
/**
|
||||
* A transaction consits of a set of messages which must all be applied or
|
||||
* A transaction consists of a set of messages which must all be applied or
|
||||
* all are rejected. These messages have access to data within the given
|
||||
* read and write scopes.
|
||||
*/
|
||||
|
||||
@@ -110,9 +110,9 @@ namespace eosio { namespace chain {
|
||||
void schedule_transaction();
|
||||
void record_transaction( const transaction_id_type& id, fc::time_point_sec expire );
|
||||
|
||||
void validate_cpu_usage_to_bill( int64_t billed_us, int64_t account_cpu_limit, bool check_minimum )const;
|
||||
void validate_account_cpu_usage( int64_t billed_us, int64_t account_cpu_limit )const;
|
||||
void validate_account_cpu_usage_estimate( int64_t billed_us, int64_t account_cpu_limit )const;
|
||||
void validate_cpu_usage_to_bill( int64_t billed_us, int64_t account_cpu_limit, bool check_minimum, int64_t subjective_billed_us )const;
|
||||
void validate_account_cpu_usage( int64_t billed_us, int64_t account_cpu_limit, int64_t subjective_billed_us )const;
|
||||
void validate_account_cpu_usage_estimate( int64_t billed_us, int64_t account_cpu_limit, int64_t subjective_billed_us )const;
|
||||
|
||||
void disallow_transaction_extensions( const char* error_msg )const;
|
||||
|
||||
@@ -128,7 +128,7 @@ namespace eosio { namespace chain {
|
||||
fc::time_point published;
|
||||
|
||||
|
||||
vector<digest_type> executed_action_receipt_digests;
|
||||
deque<digest_type> executed_action_receipt_digests;
|
||||
flat_set<account_name> bill_to_accounts;
|
||||
flat_set<account_name> validate_ram_usage;
|
||||
|
||||
|
||||
@@ -17,6 +17,9 @@
|
||||
#include <fc/fixed_string.hpp>
|
||||
#include <fc/crypto/private_key.hpp>
|
||||
|
||||
#include <boost/version.hpp>
|
||||
#include <boost/container/deque.hpp>
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <deque>
|
||||
@@ -45,7 +48,6 @@ namespace eosio { namespace chain {
|
||||
using std::vector;
|
||||
using std::unordered_map;
|
||||
using std::string;
|
||||
using std::deque;
|
||||
using std::shared_ptr;
|
||||
using std::weak_ptr;
|
||||
using std::unique_ptr;
|
||||
@@ -76,7 +78,15 @@ namespace eosio { namespace chain {
|
||||
using public_key_type = fc::crypto::public_key;
|
||||
using private_key_type = fc::crypto::private_key;
|
||||
using signature_type = fc::crypto::signature;
|
||||
|
||||
#if BOOST_VERSION >= 107100
|
||||
// configurable boost deque performs much better than std::deque in our use cases
|
||||
using block_1024_option_t = boost::container::deque_options< boost::container::block_size<1024u> >::type;
|
||||
template<typename T>
|
||||
using deque = boost::container::deque< T, void, block_1024_option_t >;
|
||||
#else
|
||||
template<typename T>
|
||||
using deque = std::deque<T>;
|
||||
#endif
|
||||
struct void_t{};
|
||||
|
||||
using chainbase::allocator;
|
||||
@@ -241,6 +251,7 @@ namespace eosio { namespace chain {
|
||||
using int128_t = __int128;
|
||||
using uint128_t = unsigned __int128;
|
||||
using bytes = vector<char>;
|
||||
using digests_t = deque<digest_type>;
|
||||
|
||||
struct sha256_less {
|
||||
bool operator()( const fc::sha256& lhs, const fc::sha256& rhs ) const {
|
||||
|
||||
@@ -32,12 +32,12 @@ using next_func_t = std::function<void(const std::variant<fc::exception_ptr, tra
|
||||
|
||||
struct unapplied_transaction {
|
||||
const transaction_metadata_ptr trx_meta;
|
||||
const fc::time_point expiry;
|
||||
trx_enum_type trx_type = trx_enum_type::unknown;
|
||||
bool return_failure_trace = false;
|
||||
next_func_t next;
|
||||
|
||||
const transaction_id_type& id()const { return trx_meta->id(); }
|
||||
fc::time_point_sec expiration()const { return trx_meta->packed_trx()->expiration(); }
|
||||
|
||||
unapplied_transaction(const unapplied_transaction&) = delete;
|
||||
unapplied_transaction() = delete;
|
||||
@@ -61,7 +61,7 @@ private:
|
||||
const_mem_fun<unapplied_transaction, const transaction_id_type&, &unapplied_transaction::id>
|
||||
>,
|
||||
ordered_non_unique< tag<by_type>, member<unapplied_transaction, trx_enum_type, &unapplied_transaction::trx_type> >,
|
||||
ordered_non_unique< tag<by_expiry>, member<unapplied_transaction, const fc::time_point, &unapplied_transaction::expiry> >
|
||||
ordered_non_unique< tag<by_expiry>, const_mem_fun<unapplied_transaction, fc::time_point_sec, &unapplied_transaction::expiration> >
|
||||
>
|
||||
> unapplied_trx_queue_type;
|
||||
|
||||
@@ -101,7 +101,7 @@ public:
|
||||
auto& persisted_by_expiry = queue.get<by_expiry>();
|
||||
while( !persisted_by_expiry.empty() ) {
|
||||
const auto& itr = persisted_by_expiry.begin();
|
||||
if( itr->expiry > pending_block_time ) {
|
||||
if( itr->expiration() > pending_block_time ) {
|
||||
break;
|
||||
}
|
||||
if( deadline <= fc::time_point::now() ) {
|
||||
@@ -146,17 +146,15 @@ public:
|
||||
const block_state_ptr& bsptr = *ritr;
|
||||
for( auto itr = bsptr->trxs_metas().begin(), end = bsptr->trxs_metas().end(); itr != end; ++itr ) {
|
||||
const auto& trx = *itr;
|
||||
fc::time_point expiry = trx->packed_trx()->expiration();
|
||||
auto insert_itr = queue.insert( { trx, expiry, trx_enum_type::forked } );
|
||||
auto insert_itr = queue.insert( { trx, trx_enum_type::forked } );
|
||||
if( insert_itr.second ) added( insert_itr.first );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void add_aborted( std::vector<transaction_metadata_ptr> aborted_trxs ) {
|
||||
void add_aborted( deque<transaction_metadata_ptr> aborted_trxs ) {
|
||||
for( auto& trx : aborted_trxs ) {
|
||||
fc::time_point expiry = trx->packed_trx()->expiration();
|
||||
auto insert_itr = queue.insert( { std::move( trx ), expiry, trx_enum_type::aborted } );
|
||||
auto insert_itr = queue.insert( { std::move( trx ), trx_enum_type::aborted } );
|
||||
if( insert_itr.second ) added( insert_itr.first );
|
||||
}
|
||||
}
|
||||
@@ -164,14 +162,14 @@ public:
|
||||
void add_persisted( const transaction_metadata_ptr& trx ) {
|
||||
auto itr = queue.get<by_trx_id>().find( trx->id() );
|
||||
if( itr == queue.get<by_trx_id>().end() ) {
|
||||
fc::time_point expiry = trx->packed_trx()->expiration();
|
||||
auto insert_itr = queue.insert( { trx, expiry, trx_enum_type::persisted } );
|
||||
auto insert_itr = queue.insert( { trx, trx_enum_type::persisted } );
|
||||
if( insert_itr.second ) added( insert_itr.first );
|
||||
} else if( itr->trx_type != trx_enum_type::persisted ) {
|
||||
if (itr->trx_type == trx_enum_type::incoming || itr->trx_type == trx_enum_type::incoming_persisted)
|
||||
--incoming_count;
|
||||
queue.get<by_trx_id>().modify( itr, [](auto& un){
|
||||
un.trx_type = trx_enum_type::persisted;
|
||||
un.next = nullptr; // persisted already have ack'ed initial trace
|
||||
} );
|
||||
}
|
||||
}
|
||||
@@ -179,9 +177,8 @@ public:
|
||||
void add_incoming( const transaction_metadata_ptr& trx, bool persist_until_expired, bool return_failure_trace, next_func_t next ) {
|
||||
auto itr = queue.get<by_trx_id>().find( trx->id() );
|
||||
if( itr == queue.get<by_trx_id>().end() ) {
|
||||
fc::time_point expiry = trx->packed_trx()->expiration();
|
||||
auto insert_itr = queue.insert(
|
||||
{ trx, expiry, persist_until_expired ? trx_enum_type::incoming_persisted : trx_enum_type::incoming, return_failure_trace, std::move( next ) } );
|
||||
{ trx, persist_until_expired ? trx_enum_type::incoming_persisted : trx_enum_type::incoming, return_failure_trace, std::move( next ) } );
|
||||
if( insert_itr.second ) added( insert_itr.first );
|
||||
} else {
|
||||
if( itr->trx_meta == trx ) return; // same trx meta pointer
|
||||
@@ -207,6 +204,12 @@ public:
|
||||
iterator incoming_begin() { return queue.get<by_type>().lower_bound( trx_enum_type::incoming_persisted ); }
|
||||
iterator incoming_end() { return queue.get<by_type>().end(); } // if changed to upper_bound, verify usage performance
|
||||
|
||||
iterator lower_bound( const transaction_id_type& id ) {
|
||||
auto itr = queue.get<by_trx_id>().find( id );
|
||||
if( itr == queue.get<by_trx_id>().end() ) return queue.get<by_type>().end();
|
||||
return queue.project<by_type>(itr);
|
||||
}
|
||||
|
||||
/// caller's responsibility to call next() if applicable
|
||||
iterator erase( iterator itr ) {
|
||||
removed( itr );
|
||||
|
||||
@@ -50,7 +50,9 @@ class memory {
|
||||
// The maximum amount of data that PIC code can include in the prologue
|
||||
static constexpr uintptr_t max_prologue_size = mutable_global_size + table_size;
|
||||
|
||||
static_assert(-cb_offset == EOS_VM_OC_CONTROL_BLOCK_OFFSET, "EOS VM OC control block offset has slid out of place somehow");
|
||||
// Changed from -cb_offset == EOS_VM_OC_CONTROL_BLOCK_OFFSET to get around
|
||||
// of compile warning about comparing integers of different signedness
|
||||
static_assert(EOS_VM_OC_CONTROL_BLOCK_OFFSET + cb_offset == 0, "EOS VM OC control block offset has slid out of place somehow");
|
||||
static_assert(stride == EOS_VM_OC_MEMORY_STRIDE, "EOS VM OC memory stride has slid out of place somehow");
|
||||
|
||||
private:
|
||||
|
||||
@@ -844,7 +844,7 @@ namespace webassembly {
|
||||
|
||||
/**
|
||||
* Find the table row in a primary 64-bit integer index table that matches the lowerbound condition for a given primary key.
|
||||
* Lowerbound record is the first nearest record which primary key is <= the given key.
|
||||
* Lowerbound record is the first nearest record which primary key is >= the given key.
|
||||
*
|
||||
* @ingroup database primary-index
|
||||
* @param code - the name of the owner of the table.
|
||||
@@ -954,7 +954,7 @@ namespace webassembly {
|
||||
|
||||
/**
|
||||
* Find the table row in a secondary 64-bit integer index table that matches the lowerbound condition for a given secondary key.
|
||||
* Lowerbound secondary index is the first secondary index which key is <= the given secondary index key.
|
||||
* Lowerbound secondary index is the first secondary index which key is >= the given secondary index key.
|
||||
*
|
||||
* @ingroup database uint64_t-secondary-index
|
||||
* @param code - the name of the owner of the table.
|
||||
@@ -1095,7 +1095,7 @@ namespace webassembly {
|
||||
|
||||
/**
|
||||
* Find the table row in a secondary 128-bit integer index table that matches the lowerbound condition for a given secondary key.
|
||||
* Lowerbound secondary index is the first secondary index which key is <= the given secondary index key.
|
||||
* Lowerbound secondary index is the first secondary index which key is >= the given secondary index key.
|
||||
*
|
||||
* @ingroup database uint128_t-secondary-index
|
||||
* @param code - the name of the owner of the table.
|
||||
@@ -1236,7 +1236,7 @@ namespace webassembly {
|
||||
|
||||
/**
|
||||
* Find the table row in a secondary 256-bit integer index table that matches the lowerbound condition for a given secondary key.
|
||||
* Lowerbound secondary index is the first secondary index which key is <= the given secondary index key.
|
||||
* Lowerbound secondary index is the first secondary index which key is >= the given secondary index key.
|
||||
*
|
||||
* @ingroup database 256-bit-secondary-index
|
||||
* @param code - the name of the owner of the table.
|
||||
@@ -1380,7 +1380,7 @@ namespace webassembly {
|
||||
|
||||
/**
|
||||
* Find the table row in a secondary double-precision floating-point index table that matches the lowerbound condition for a given secondary key.
|
||||
* Lowerbound secondary index is the first secondary index which key is <= the given secondary index key.
|
||||
* Lowerbound secondary index is the first secondary index which key is >= the given secondary index key.
|
||||
*
|
||||
* @ingroup database double-secondary-index
|
||||
* @param code - the name of the owner of the table.
|
||||
@@ -1524,7 +1524,7 @@ namespace webassembly {
|
||||
|
||||
/**
|
||||
* Find the table row in a secondary quadruple-precision floating-point index table that matches the lowerbound condition for a given secondary key.
|
||||
* Lowerbound secondary index is the first secondary index which key is <= the given secondary index key.
|
||||
* Lowerbound secondary index is the first secondary index which key is >= the given secondary index key.
|
||||
*
|
||||
* @ingroup database long-double-secondary-index
|
||||
* @param code - the name of the owner of the table.
|
||||
|
||||
@@ -32,7 +32,7 @@ bool is_canonical_right(const digest_type& val) {
|
||||
}
|
||||
|
||||
|
||||
digest_type merkle(vector<digest_type> ids) {
|
||||
digest_type merkle(deque<digest_type> ids) {
|
||||
if( 0 == ids.size() ) { return digest_type(); }
|
||||
|
||||
while( ids.size() > 1 ) {
|
||||
|
||||
@@ -28,6 +28,7 @@ platform_timer::platform_timer() {
|
||||
|
||||
if(refcount++ == 0) {
|
||||
std::promise<void> p;
|
||||
auto f = p.get_future();
|
||||
checktime_thread = std::thread([&p]() {
|
||||
fc::set_os_thread_name("checktime");
|
||||
checktime_ios = std::make_unique<boost::asio::io_service>();
|
||||
@@ -36,7 +37,7 @@ platform_timer::platform_timer() {
|
||||
|
||||
checktime_ios->run();
|
||||
});
|
||||
p.get_future().get();
|
||||
f.get();
|
||||
}
|
||||
|
||||
my->timer = std::make_unique<boost::asio::high_resolution_timer>(*checktime_ios);
|
||||
@@ -64,11 +65,12 @@ void platform_timer::start(fc::time_point tp) {
|
||||
else {
|
||||
#if 0
|
||||
std::promise<void> p;
|
||||
auto f = p.get_future();
|
||||
checktime_ios->post([&p,this]() {
|
||||
expired = 0;
|
||||
p.set_value();
|
||||
});
|
||||
p.get_future().get();
|
||||
f.get();
|
||||
#endif
|
||||
expired = 0;
|
||||
my->timer->expires_after(std::chrono::microseconds(x.count()));
|
||||
|
||||
@@ -418,7 +418,8 @@ std::pair<int64_t, bool> resource_limits_manager::get_account_cpu_limit( const a
|
||||
return {arl.available, greylisted};
|
||||
}
|
||||
|
||||
std::pair<account_resource_limit, bool> resource_limits_manager::get_account_cpu_limit_ex( const account_name& name, uint32_t greylist_limit ) const {
|
||||
std::pair<account_resource_limit, bool>
|
||||
resource_limits_manager::get_account_cpu_limit_ex( const account_name& name, uint32_t greylist_limit, const std::optional<block_timestamp_type>& current_time) const {
|
||||
|
||||
const auto& state = _db.get<resource_limits_state_object>();
|
||||
const auto& usage = _db.get<resource_usage_object, by_owner>(name);
|
||||
@@ -428,7 +429,7 @@ std::pair<account_resource_limit, bool> resource_limits_manager::get_account_cpu
|
||||
get_account_limits( name, x, y, cpu_weight );
|
||||
|
||||
if( cpu_weight < 0 || state.total_cpu_weight == 0 ) {
|
||||
return {{ -1, -1, -1 }, false};
|
||||
return {{ -1, -1, -1, block_timestamp_type(usage.cpu_usage.last_ordinal), -1 }, false};
|
||||
}
|
||||
|
||||
account_resource_limit arl;
|
||||
@@ -462,6 +463,15 @@ std::pair<account_resource_limit, bool> resource_limits_manager::get_account_cpu
|
||||
|
||||
arl.used = impl::downgrade_cast<int64_t>(cpu_used_in_window);
|
||||
arl.max = impl::downgrade_cast<int64_t>(max_user_use_in_window);
|
||||
arl.last_usage_update_time = block_timestamp_type(usage.cpu_usage.last_ordinal);
|
||||
arl.current_used = arl.used;
|
||||
if ( current_time ) {
|
||||
if (current_time->slot > usage.cpu_usage.last_ordinal) {
|
||||
auto history_usage = usage.cpu_usage;
|
||||
history_usage.add(0, current_time->slot, window_size);
|
||||
arl.current_used = impl::downgrade_cast<int64_t>(impl::integer_divide_ceil((uint128_t)history_usage.value_ex * window_size, (uint128_t)config::rate_limiting_precision));
|
||||
}
|
||||
}
|
||||
return {arl, greylisted};
|
||||
}
|
||||
|
||||
@@ -470,7 +480,8 @@ std::pair<int64_t, bool> resource_limits_manager::get_account_net_limit( const a
|
||||
return {arl.available, greylisted};
|
||||
}
|
||||
|
||||
std::pair<account_resource_limit, bool> resource_limits_manager::get_account_net_limit_ex( const account_name& name, uint32_t greylist_limit ) const {
|
||||
std::pair<account_resource_limit, bool>
|
||||
resource_limits_manager::get_account_net_limit_ex( const account_name& name, uint32_t greylist_limit, const std::optional<block_timestamp_type>& current_time) const {
|
||||
const auto& config = _db.get<resource_limits_config_object>();
|
||||
const auto& state = _db.get<resource_limits_state_object>();
|
||||
const auto& usage = _db.get<resource_usage_object, by_owner>(name);
|
||||
@@ -479,7 +490,7 @@ std::pair<account_resource_limit, bool> resource_limits_manager::get_account_net
|
||||
get_account_limits( name, x, net_weight, y );
|
||||
|
||||
if( net_weight < 0 || state.total_net_weight == 0) {
|
||||
return {{ -1, -1, -1 }, false};
|
||||
return {{ -1, -1, -1, block_timestamp_type(usage.net_usage.last_ordinal), -1 }, false};
|
||||
}
|
||||
|
||||
account_resource_limit arl;
|
||||
@@ -513,6 +524,15 @@ std::pair<account_resource_limit, bool> resource_limits_manager::get_account_net
|
||||
|
||||
arl.used = impl::downgrade_cast<int64_t>(net_used_in_window);
|
||||
arl.max = impl::downgrade_cast<int64_t>(max_user_use_in_window);
|
||||
arl.last_usage_update_time = block_timestamp_type(usage.net_usage.last_ordinal);
|
||||
arl.current_used = arl.used;
|
||||
if ( current_time ) {
|
||||
if (current_time->slot > usage.net_usage.last_ordinal) {
|
||||
auto history_usage = usage.net_usage;
|
||||
history_usage.add(0, current_time->slot, window_size);
|
||||
arl.current_used = impl::downgrade_cast<int64_t>(impl::integer_divide_ceil((uint128_t)history_usage.value_ex * window_size, (uint128_t)config::rate_limiting_precision));
|
||||
}
|
||||
}
|
||||
return {arl, greylisted};
|
||||
}
|
||||
|
||||
|
||||
+134
-49
@@ -1,6 +1,16 @@
|
||||
#define RAPIDJSON_NAMESPACE eosio_rapidjson // This is ABSOLUTELY necessary anywhere that is using eosio_rapidjson
|
||||
|
||||
#include <eosio/chain/snapshot.hpp>
|
||||
#include <eosio/chain/exceptions.hpp>
|
||||
#include <fc/scoped_exit.hpp>
|
||||
#include <fc/io/json.hpp>
|
||||
|
||||
#include <rapidjson/document.h>
|
||||
#include <rapidjson/filereadstream.h>
|
||||
#include <rapidjson/stringbuffer.h>
|
||||
#include <rapidjson/writer.h>
|
||||
|
||||
using namespace eosio_rapidjson;
|
||||
|
||||
namespace eosio { namespace chain {
|
||||
|
||||
@@ -76,17 +86,6 @@ void variant_snapshot_reader::validate() const {
|
||||
}
|
||||
}
|
||||
|
||||
bool variant_snapshot_reader::has_section( const string& section_name ) {
|
||||
const auto& sections = snapshot["sections"].get_array();
|
||||
for( const auto& section: sections ) {
|
||||
if (section["name"].as_string() == section_name) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void variant_snapshot_reader::set_section( const string& section_name ) {
|
||||
const auto& sections = snapshot["sections"].get_array();
|
||||
for( const auto& section: sections ) {
|
||||
@@ -190,6 +189,45 @@ void ostream_snapshot_writer::finalize() {
|
||||
snapshot.write((char*)&end_marker, sizeof(end_marker));
|
||||
}
|
||||
|
||||
ostream_json_snapshot_writer::ostream_json_snapshot_writer(std::ostream& snapshot)
|
||||
:snapshot(snapshot)
|
||||
,row_count(0)
|
||||
{
|
||||
snapshot << "{\n";
|
||||
// write magic number
|
||||
auto totem = magic_number;
|
||||
snapshot << "\"magic_number\":" << fc::json::to_string(totem, fc::time_point::maximum()) << "\n";
|
||||
|
||||
// write version
|
||||
auto version = current_snapshot_version;
|
||||
snapshot << ",\"version\":" << fc::json::to_string(version, fc::time_point::maximum()) << "\n";
|
||||
}
|
||||
|
||||
void ostream_json_snapshot_writer::write_start_section( const std::string& section_name )
|
||||
{
|
||||
row_count = 0;
|
||||
snapshot.inner << "," << fc::json::to_string(section_name, fc::time_point::maximum()) << ":{\n\"rows\":[\n";
|
||||
}
|
||||
|
||||
void ostream_json_snapshot_writer::write_row( const detail::abstract_snapshot_row_writer& row_writer ) {
|
||||
const auto yield = [&](size_t s) {};
|
||||
|
||||
if(row_count != 0) snapshot.inner << ",";
|
||||
snapshot.inner << fc::json::to_string(row_writer.to_variant(), yield) << "\n";
|
||||
++row_count;
|
||||
}
|
||||
|
||||
void ostream_json_snapshot_writer::write_end_section( ) {
|
||||
snapshot.inner << "],\n\"num_rows\":" << row_count << "\n}\n";
|
||||
row_count = 0;
|
||||
}
|
||||
|
||||
void ostream_json_snapshot_writer::finalize() {
|
||||
snapshot.inner << "}\n";
|
||||
snapshot.inner.flush();
|
||||
}
|
||||
|
||||
|
||||
istream_snapshot_reader::istream_snapshot_reader(std::istream& snapshot)
|
||||
:snapshot(snapshot)
|
||||
,header_pos(snapshot.tellg())
|
||||
@@ -246,44 +284,6 @@ bool istream_snapshot_reader::validate_section() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool istream_snapshot_reader::has_section( const string& section_name ) {
|
||||
auto restore_pos = fc::make_scoped_exit([this,pos=snapshot.tellg()](){
|
||||
snapshot.seekg(pos);
|
||||
});
|
||||
|
||||
const std::streamoff header_size = sizeof(ostream_snapshot_writer::magic_number) + sizeof(current_snapshot_version);
|
||||
|
||||
auto next_section_pos = header_pos + header_size;
|
||||
|
||||
while (true) {
|
||||
snapshot.seekg(next_section_pos);
|
||||
uint64_t section_size = 0;
|
||||
snapshot.read((char*)§ion_size,sizeof(section_size));
|
||||
if (section_size == std::numeric_limits<uint64_t>::max()) {
|
||||
break;
|
||||
}
|
||||
|
||||
next_section_pos = snapshot.tellg() + std::streamoff(section_size);
|
||||
|
||||
uint64_t ignore = 0;
|
||||
snapshot.read((char*)&ignore,sizeof(ignore));
|
||||
|
||||
bool match = true;
|
||||
for(auto c : section_name) {
|
||||
if(snapshot.get() != c) {
|
||||
match = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (match && snapshot.get() == 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void istream_snapshot_reader::set_section( const string& section_name ) {
|
||||
auto restore_pos = fc::make_scoped_exit([this,pos=snapshot.tellg()](){
|
||||
snapshot.seekg(pos);
|
||||
@@ -346,6 +346,91 @@ void istream_snapshot_reader::return_to_header() {
|
||||
clear_section();
|
||||
}
|
||||
|
||||
struct istream_json_snapshot_reader_impl {
|
||||
uint64_t num_rows;
|
||||
uint64_t cur_row;
|
||||
eosio_rapidjson::Document doc;
|
||||
std::string sec_name;
|
||||
};
|
||||
|
||||
istream_json_snapshot_reader::~istream_json_snapshot_reader() = default;
|
||||
|
||||
istream_json_snapshot_reader::istream_json_snapshot_reader(const fc::path& p)
|
||||
: impl{new istream_json_snapshot_reader_impl{0, 0, {}, {}}}
|
||||
{
|
||||
FILE* fp = fopen(p.string().c_str(), "rb");
|
||||
EOS_ASSERT(fp, snapshot_exception, "Failed to open JSON snapshot: ${file}", ("file", p));
|
||||
auto close = fc::make_scoped_exit( [&fp]() { fclose( fp ); } );
|
||||
char readBuffer[65536];
|
||||
eosio_rapidjson::FileReadStream is(fp, readBuffer, sizeof(readBuffer));
|
||||
impl->doc.ParseStream(is);
|
||||
}
|
||||
|
||||
void istream_json_snapshot_reader::validate() const {
|
||||
try {
|
||||
// validate totem
|
||||
auto expected_totem = ostream_json_snapshot_writer::magic_number;
|
||||
EOS_ASSERT(impl->doc.HasMember("magic_number"), snapshot_exception, "magic_number section not found" );
|
||||
auto actual_totem = impl->doc["magic_number"].GetUint();
|
||||
EOS_ASSERT( actual_totem == expected_totem, snapshot_exception, "JSON snapshot has unexpected magic number" );
|
||||
|
||||
// validate version
|
||||
auto expected_version = current_snapshot_version;
|
||||
EOS_ASSERT(impl->doc.HasMember("version"), snapshot_exception, "version section not found" );
|
||||
auto actual_version = impl->doc["version"].GetUint();
|
||||
EOS_ASSERT( actual_version == expected_version, snapshot_exception,
|
||||
"JSON snapshot is an unsupported version. Expected : ${expected}, Got: ${actual}",
|
||||
("expected", expected_version)( "actual", actual_version ) );
|
||||
|
||||
} catch( const std::exception& e ) { \
|
||||
snapshot_exception fce(FC_LOG_MESSAGE( warn, "JSON snapshot validation threw IO exception (${what})",("what",e.what())));
|
||||
throw fce;
|
||||
}
|
||||
}
|
||||
|
||||
bool istream_json_snapshot_reader::validate_section() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
void istream_json_snapshot_reader::set_section( const string& section_name ) {
|
||||
EOS_ASSERT( impl->doc.HasMember( section_name.c_str() ), snapshot_exception, "JSON snapshot has no section ${sec}", ("sec", section_name) );
|
||||
EOS_ASSERT( impl->doc[section_name.c_str()].HasMember( "num_rows" ), snapshot_exception, "JSON snapshot ${sec} num_rows not found", ("sec", section_name) );
|
||||
EOS_ASSERT( impl->doc[section_name.c_str()].HasMember( "rows" ), snapshot_exception, "JSON snapshot ${sec} rows not found", ("sec", section_name) );
|
||||
EOS_ASSERT( impl->doc[section_name.c_str()]["rows"].IsArray(), snapshot_exception, "JSON snapshot ${sec} rows is not an array", ("sec_name", section_name) );
|
||||
|
||||
impl->sec_name = section_name;
|
||||
impl->num_rows = impl->doc[section_name.c_str()]["num_rows"].GetInt();
|
||||
ilog( "reading ${section_name}, num_rows: ${num_rows}", ("section_name", section_name)( "num_rows", impl->num_rows ) );
|
||||
}
|
||||
|
||||
bool istream_json_snapshot_reader::read_row( detail::abstract_snapshot_row_reader& row_reader ) {
|
||||
EOS_ASSERT( impl->cur_row < impl->num_rows, snapshot_exception, "JSON snapshot ${sect}'s cur_row ${cur_row} >= num_rows ${num_rows}",
|
||||
("sect_name", impl->sec_name)( "cur_row", impl->cur_row )( "num_rows", impl->num_rows ) );
|
||||
|
||||
const eosio_rapidjson::Value& rows = impl->doc[impl->sec_name.c_str()]["rows"];
|
||||
eosio_rapidjson::StringBuffer buffer;
|
||||
eosio_rapidjson::Writer<eosio_rapidjson::StringBuffer> writer( buffer );
|
||||
rows[impl->cur_row].Accept( writer );
|
||||
|
||||
const auto& row = fc::json::from_string( buffer.GetString() );
|
||||
row_reader.provide( row );
|
||||
return ++impl->cur_row < impl->num_rows;
|
||||
}
|
||||
|
||||
bool istream_json_snapshot_reader::empty ( ) {
|
||||
return impl->num_rows == 0;
|
||||
}
|
||||
|
||||
void istream_json_snapshot_reader::clear_section() {
|
||||
impl->num_rows = 0;
|
||||
impl->cur_row = 0;
|
||||
impl->sec_name = "";
|
||||
}
|
||||
|
||||
void istream_json_snapshot_reader::return_to_header() {
|
||||
clear_section();
|
||||
}
|
||||
|
||||
integrity_hash_snapshot_writer::integrity_hash_snapshot_writer(fc::sha256::encoder& enc)
|
||||
:enc(enc)
|
||||
{
|
||||
|
||||
@@ -138,7 +138,7 @@ namespace eosio { namespace chain {
|
||||
initial_objective_duration_limit = objective_duration_limit;
|
||||
|
||||
if( explicit_billed_cpu_time )
|
||||
validate_cpu_usage_to_bill( billed_cpu_time_us, std::numeric_limits<int64_t>::max(), false ); // Fail early if the amount to be billed is too high
|
||||
validate_cpu_usage_to_bill( billed_cpu_time_us, std::numeric_limits<int64_t>::max(), false, subjective_cpu_bill_us); // Fail early if the amount to be billed is too high
|
||||
|
||||
// Record accounts to be billed for network and CPU usage
|
||||
if( control.is_builtin_activated(builtin_protocol_feature_t::only_bill_first_authorizer) ) {
|
||||
@@ -204,7 +204,7 @@ namespace eosio { namespace chain {
|
||||
if( validate_account_cpu_limit > 0 )
|
||||
validate_account_cpu_limit -= EOS_PERCENT( validate_account_cpu_limit, 10 * config::percent_1 );
|
||||
if( validate_account_cpu_limit < 0 ) validate_account_cpu_limit = 0;
|
||||
validate_account_cpu_usage_estimate( billed_cpu_time_us, validate_account_cpu_limit );
|
||||
validate_account_cpu_usage_estimate( billed_cpu_time_us, validate_account_cpu_limit, subjective_cpu_bill_us );
|
||||
}
|
||||
|
||||
eager_net_limit = (eager_net_limit/8)*8; // Round down to nearest multiple of word size (8 bytes) so check_net_usage can be efficient
|
||||
@@ -368,7 +368,7 @@ namespace eosio { namespace chain {
|
||||
|
||||
update_billed_cpu_time( now );
|
||||
|
||||
validate_cpu_usage_to_bill( billed_cpu_time_us, account_cpu_limit, true );
|
||||
validate_cpu_usage_to_bill( billed_cpu_time_us, account_cpu_limit, true, subjective_cpu_bill_us );
|
||||
|
||||
rl.add_transaction_usage( bill_to_accounts, static_cast<uint64_t>(billed_cpu_time_us), net_usage,
|
||||
block_timestamp_type(control.pending_block_time()).slot ); // Should never fail
|
||||
@@ -415,14 +415,19 @@ namespace eosio { namespace chain {
|
||||
"not enough time left in block to complete executing transaction ${billing_timer}us",
|
||||
("now", now)("deadline", _deadline)("start", start)("billing_timer", now - pseudo_start) );
|
||||
} else if( deadline_exception_code == tx_cpu_usage_exceeded::code_value ) {
|
||||
std::string assert_msg = "transaction was executing for too long ${billing_timer}us";
|
||||
if (subjective_cpu_bill_us > 0) {
|
||||
assert_msg += " with a subjective cpu of (${subjective} us)";
|
||||
}
|
||||
if (cpu_limit_due_to_greylist) {
|
||||
assert_msg = "greylisted " + assert_msg;
|
||||
EOS_THROW( greylist_cpu_usage_exceeded,
|
||||
"greylisted transaction was executing for too long ${billing_timer}us",
|
||||
("now", now)("deadline", _deadline)("start", start)("billing_timer", now - pseudo_start) );
|
||||
assert_msg,
|
||||
("now", now)("deadline", _deadline)("start", start)("billing_timer", now - pseudo_start)( "subjective", subjective_cpu_bill_us) );
|
||||
} else {
|
||||
EOS_THROW( tx_cpu_usage_exceeded,
|
||||
"transaction was executing for too long ${billing_timer}us",
|
||||
("now", now)("deadline", _deadline)("start", start)("billing_timer", now - pseudo_start) );
|
||||
assert_msg,
|
||||
("now", now)("deadline", _deadline)("start", start)("billing_timer", now - pseudo_start)("subjective", subjective_cpu_bill_us) );
|
||||
}
|
||||
} else if( deadline_exception_code == leeway_deadline_exception::code_value ) {
|
||||
EOS_THROW( leeway_deadline_exception,
|
||||
@@ -460,7 +465,7 @@ namespace eosio { namespace chain {
|
||||
transaction_timer.start(_deadline);
|
||||
}
|
||||
|
||||
void transaction_context::validate_cpu_usage_to_bill( int64_t billed_us, int64_t account_cpu_limit, bool check_minimum )const {
|
||||
void transaction_context::validate_cpu_usage_to_bill( int64_t billed_us, int64_t account_cpu_limit, bool check_minimum, int64_t subjective_billed_us )const {
|
||||
if (!control.skip_trx_checks()) {
|
||||
if( check_minimum ) {
|
||||
const auto& cfg = control.get_global_properties().configuration;
|
||||
@@ -470,11 +475,11 @@ namespace eosio { namespace chain {
|
||||
);
|
||||
}
|
||||
|
||||
validate_account_cpu_usage( billed_us, account_cpu_limit );
|
||||
validate_account_cpu_usage( billed_us, account_cpu_limit, subjective_billed_us );
|
||||
}
|
||||
}
|
||||
|
||||
void transaction_context::validate_account_cpu_usage( int64_t billed_us, int64_t account_cpu_limit )const {
|
||||
void transaction_context::validate_account_cpu_usage( int64_t billed_us, int64_t account_cpu_limit, int64_t subjective_billed_us )const {
|
||||
if( (billed_us > 0) && !control.skip_trx_checks() ) {
|
||||
const bool cpu_limited_by_account = (account_cpu_limit <= objective_duration_limit.count());
|
||||
|
||||
@@ -485,26 +490,33 @@ namespace eosio { namespace chain {
|
||||
("billed", billed_us)( "billable", objective_duration_limit.count() )
|
||||
);
|
||||
} else {
|
||||
if( cpu_limit_due_to_greylist && cpu_limited_by_account ) {
|
||||
EOS_ASSERT( billed_us <= account_cpu_limit,
|
||||
greylist_cpu_usage_exceeded,
|
||||
"billed CPU time (${billed} us) is greater than the maximum greylisted billable CPU time for the transaction (${billable} us)",
|
||||
("billed", billed_us)( "billable", account_cpu_limit )
|
||||
);
|
||||
} else {
|
||||
// exceeds trx.max_cpu_usage_ms or cfg.max_transaction_cpu_usage if objective_duration_limit is greater
|
||||
const int64_t cpu_limit = (cpu_limited_by_account ? account_cpu_limit : objective_duration_limit.count());
|
||||
EOS_ASSERT( billed_us <= cpu_limit,
|
||||
auto assert_msg = [&](bool graylisted, bool subjective) {
|
||||
std::string assert_msg = "billed CPU time (${billed} us) is greater than the maximum";
|
||||
assert_msg += graylisted ? " greylisted" : "";
|
||||
assert_msg += " billable CPU time for the transaction (${billable} us)";
|
||||
assert_msg += subjective ? " with a subjective cpu of (${subjective} us)" : "";
|
||||
return assert_msg;
|
||||
};
|
||||
auto graylisted = cpu_limit_due_to_greylist && cpu_limited_by_account;
|
||||
auto subjective = subjective_billed_us > 0;
|
||||
// exceeds trx.max_cpu_usage_ms or cfg.max_transaction_cpu_usage if objective_duration_limit is greater
|
||||
auto limit = graylisted ? account_cpu_limit : (cpu_limited_by_account ? account_cpu_limit : objective_duration_limit.count());
|
||||
|
||||
if (graylisted)
|
||||
EOS_ASSERT( billed_us <= limit,
|
||||
greylist_cpu_usage_exceeded,
|
||||
assert_msg(graylisted, subjective),
|
||||
("billed", billed_us)("billable", limit)("subjective", subjective_billed_us));
|
||||
else
|
||||
EOS_ASSERT( billed_us <= limit,
|
||||
tx_cpu_usage_exceeded,
|
||||
"billed CPU time (${billed} us) is greater than the maximum billable CPU time for the transaction (${billable} us)",
|
||||
("billed", billed_us)( "billable", cpu_limit )
|
||||
);
|
||||
}
|
||||
assert_msg(graylisted, subjective),
|
||||
("billed", billed_us)("billable", limit)("subjective", subjective_billed_us));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void transaction_context::validate_account_cpu_usage_estimate( int64_t prev_billed_us, int64_t account_cpu_limit )const {
|
||||
void transaction_context::validate_account_cpu_usage_estimate( int64_t prev_billed_us, int64_t account_cpu_limit, int64_t subjective_billed_us )const {
|
||||
// prev_billed_us can be 0, but so can account_cpu_limit
|
||||
if( (prev_billed_us >= 0) && !control.skip_trx_checks() ) {
|
||||
const bool cpu_limited_by_account = (account_cpu_limit <= objective_duration_limit.count());
|
||||
@@ -516,21 +528,28 @@ namespace eosio { namespace chain {
|
||||
("billed", prev_billed_us)( "billable", objective_duration_limit.count() )
|
||||
);
|
||||
} else {
|
||||
if( cpu_limit_due_to_greylist && cpu_limited_by_account ) {
|
||||
EOS_ASSERT( prev_billed_us < account_cpu_limit,
|
||||
greylist_cpu_usage_exceeded,
|
||||
"estimated CPU time (${billed} us) is not less than the maximum greylisted billable CPU time for the transaction (${billable} us)",
|
||||
("billed", prev_billed_us)( "billable", account_cpu_limit )
|
||||
);
|
||||
} else {
|
||||
// exceeds trx.max_cpu_usage_ms or cfg.max_transaction_cpu_usage if objective_duration_limit is greater
|
||||
const int64_t cpu_limit = (cpu_limited_by_account ? account_cpu_limit : objective_duration_limit.count());
|
||||
EOS_ASSERT( prev_billed_us < cpu_limit,
|
||||
auto assert_msg = [&](bool graylisted, bool subjective) {
|
||||
std::string assert_msg = "estimated CPU time (${billed} us) is not less than the maximum";
|
||||
assert_msg += graylisted ? " greylisted" : "";
|
||||
assert_msg += " billable CPU time for the transaction (${billable} us)";
|
||||
assert_msg += subjective ? " with a subjective cpu of (${subjective} us)" : "";
|
||||
return assert_msg;
|
||||
};
|
||||
auto graylisted = cpu_limit_due_to_greylist && cpu_limited_by_account;
|
||||
auto subjective = subjective_billed_us > 0;
|
||||
// exceeds trx.max_cpu_usage_ms or cfg.max_transaction_cpu_usage if objective_duration_limit is greater
|
||||
auto limit = graylisted ? account_cpu_limit : (cpu_limited_by_account ? account_cpu_limit : objective_duration_limit.count());
|
||||
|
||||
if (graylisted)
|
||||
EOS_ASSERT( prev_billed_us < limit,
|
||||
greylist_cpu_usage_exceeded,
|
||||
assert_msg(graylisted, subjective),
|
||||
("billed", prev_billed_us)("billable", limit)("subjective", subjective_billed_us));
|
||||
else
|
||||
EOS_ASSERT( prev_billed_us < limit,
|
||||
tx_cpu_usage_exceeded,
|
||||
"estimated CPU time (${billed} us) is not less than the maximum billable CPU time for the transaction (${billable} us)",
|
||||
("billed", prev_billed_us)( "billable", cpu_limit )
|
||||
);
|
||||
}
|
||||
assert_msg(graylisted, subjective),
|
||||
("billed", prev_billed_us)("billable", limit)("subjective", subjective_billed_us));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -721,12 +740,14 @@ namespace eosio { namespace chain {
|
||||
const auto& db = control.db();
|
||||
const auto& auth_manager = control.get_authorization_manager();
|
||||
|
||||
for( const auto& a : trx.context_free_actions ) {
|
||||
auto* code = db.find<account_object, by_name>(a.account);
|
||||
EOS_ASSERT( code != nullptr, transaction_exception,
|
||||
"action's code account '${account}' does not exist", ("account", a.account) );
|
||||
EOS_ASSERT( a.authorization.size() == 0, transaction_exception,
|
||||
"context-free actions cannot have authorizations" );
|
||||
if( !trx.context_free_actions.empty() && !control.skip_trx_checks() ) {
|
||||
for( const auto& a : trx.context_free_actions ) {
|
||||
auto* code = db.find<account_object, by_name>( a.account );
|
||||
EOS_ASSERT( code != nullptr, transaction_exception,
|
||||
"action's code account '${account}' does not exist", ("account", a.account) );
|
||||
EOS_ASSERT( a.authorization.size() == 0, transaction_exception,
|
||||
"context-free actions cannot have authorizations" );
|
||||
}
|
||||
}
|
||||
|
||||
flat_set<account_name> actors;
|
||||
|
||||
@@ -223,7 +223,7 @@ void executor::execute(const code_descriptor& code, memory& mem, apply_context&
|
||||
cb->bounce_buffers->clear();
|
||||
tt.set_expiration_callback(nullptr, nullptr);
|
||||
|
||||
uint64_t base_pages = mem.size_of_memory_slice_mapping()/memory::stride - 1;
|
||||
int64_t base_pages = mem.size_of_memory_slice_mapping()/memory::stride - 1;
|
||||
if(cb->current_linear_memory_pages > base_pages) {
|
||||
mprotect(mem.full_page_memory_base() + base_pages * eosio::chain::wasm_constraints::wasm_page_size,
|
||||
(cb->current_linear_memory_pages - base_pages) * eosio::chain::wasm_constraints::wasm_page_size, PROT_NONE);
|
||||
|
||||
@@ -25,7 +25,7 @@ memory::memory(uint64_t max_pages) {
|
||||
FC_ASSERT(mapbase != MAP_FAILED, "Failed to mmap memory");
|
||||
|
||||
uint8_t* next_slice = mapbase;
|
||||
uint8_t* last;
|
||||
uint8_t* last = nullptr;
|
||||
|
||||
for(unsigned int p = 0; p < number_slices; ++p) {
|
||||
last = (uint8_t*)mmap(next_slice, memory_prologue_size+64u*1024u*p, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_FIXED, fd, 0);
|
||||
@@ -33,6 +33,7 @@ memory::memory(uint64_t max_pages) {
|
||||
next_slice += total_memory_per_slice;
|
||||
}
|
||||
|
||||
FC_ASSERT(last != nullptr, "expected last not nullptr");
|
||||
zeropage_base = mapbase + memory_prologue_size;
|
||||
fullpage_base = last + memory_prologue_size;
|
||||
|
||||
|
||||
+1
-1
Submodule libraries/chainbase updated: dcd2a34391...62d3f99059
@@ -0,0 +1,2 @@
|
||||
add_library(leap-cli11 INTERFACE)
|
||||
target_include_directories(leap-cli11 INTERFACE include)
|
||||
@@ -0,0 +1,26 @@
|
||||
|
||||
## instructions for building custom leap-cli11 library
|
||||
|
||||
leap-cli11 interface only library created in order to simplify integration of modified version of command line parsing library cli11
|
||||
|
||||
to update included in this library include/cli11/CLI11.hpp file it needs to be (re)geenerated from repository containing forked/modified version of it, in particular:
|
||||
|
||||
|
||||
```bash
|
||||
git clone https://github.com/AntelopeIO/CLI11.git
|
||||
cd CLI11
|
||||
mkdir build
|
||||
cd build
|
||||
cmake -DCLI11_SINGLE_FILE=ON ..
|
||||
make -j
|
||||
```
|
||||
|
||||
Resulting single-header will be located in:
|
||||
|
||||
```cpp
|
||||
build/include/CLI11.hpp
|
||||
```
|
||||
|
||||
And is ready to be copied to include/cli11/CLI11.hpp of leap-cli11 library
|
||||
|
||||
Automated CLI11 subproject build / import of CLI11.hpp header will be added in future versions.
|
||||
@@ -0,0 +1,26 @@
|
||||
#/usr/bin/env bash
|
||||
|
||||
_cleos_complete()
|
||||
{
|
||||
# Get cmdline while ignoring the last word
|
||||
cmdline=${COMP_LINE}
|
||||
if [[ "${cmdline:(-1)}" != " " ]]; then
|
||||
cmdline=${COMP_WORDS[@]:0:${COMP_CWORD}}
|
||||
fi
|
||||
|
||||
# Get complete candidates
|
||||
words=$(${cmdline} --_autocomplete "${COMP_WORDS[${COMP_CWORD}]}")
|
||||
|
||||
# Remove candidates that begins with `-` if `-` is not passed as the first character
|
||||
# TODO: move this logic inside CLI11? including the compgen?
|
||||
if [[ ! ${COMP_WORDS[${COMP_CWORD}]} = -* ]]; then
|
||||
words=(${words})
|
||||
for index in "${!words[@]}" ; do [[ ${words[$index]} =~ ^- ]] && unset -v 'words[$index]' ; done
|
||||
words="${words[@]}"
|
||||
fi
|
||||
|
||||
# Get matches
|
||||
COMPREPLY=($(compgen -W "${words}" -- "${COMP_WORDS[${COMP_CWORD}]}"))
|
||||
}
|
||||
|
||||
complete -F _cleos_complete cleos
|
||||
@@ -0,0 +1,26 @@
|
||||
#/usr/bin/env bash
|
||||
|
||||
_leap_complete()
|
||||
{
|
||||
# Get cmdline while ignoring the last word
|
||||
cmdline=${COMP_LINE}
|
||||
if [[ "${cmdline:(-1)}" != " " ]]; then
|
||||
cmdline=${COMP_WORDS[@]:0:${COMP_CWORD}}
|
||||
fi
|
||||
|
||||
# Get complete candidates
|
||||
words=$(${cmdline} --_autocomplete "${COMP_WORDS[${COMP_CWORD}]}")
|
||||
|
||||
# Remove candidates that begins with `-` if `-` is not passed as the first character
|
||||
# TODO: move this logic inside CLI11? including the compgen?
|
||||
if [[ ! ${COMP_WORDS[${COMP_CWORD}]} = -* ]]; then
|
||||
words=(${words})
|
||||
for index in "${!words[@]}" ; do [[ ${words[$index]} =~ ^- ]] && unset -v 'words[$index]' ; done
|
||||
words="${words[@]}"
|
||||
fi
|
||||
|
||||
# Get matches
|
||||
COMPREPLY=($(compgen -W "${words}" -- "${COMP_WORDS[${COMP_CWORD}]}"))
|
||||
}
|
||||
|
||||
complete -F _leap_complete leap-util
|
||||
File diff suppressed because it is too large
Load Diff
-1
Submodule libraries/fc deleted from 35144b5563
@@ -0,0 +1,155 @@
|
||||
add_subdirectory( secp256k1 )
|
||||
|
||||
set( WITH_PROCPS OFF CACHE BOOL "" FORCE)
|
||||
set( CURVE "ALT_BN128" CACHE STRING "" FORCE)
|
||||
set( USE_ASM OFF CACHE BOOL "" FORCE)
|
||||
set( IS_LIBFF_PARENT OFF CACHE BOOL "" FORCE)
|
||||
set( FF_INSTALL_COMPONENT "${FC_INSTALL_COMPONENT}")
|
||||
add_subdirectory( libraries/ff )
|
||||
|
||||
set(CMAKE_THREAD_PREFER_PTHREAD TRUE)
|
||||
set(THREADS_PREFER_PTHREAD_FLAG TRUE)
|
||||
find_package(Threads)
|
||||
|
||||
find_package(OpenSSL REQUIRED)
|
||||
|
||||
set( fc_sources
|
||||
src/uint128.cpp
|
||||
src/real128.cpp
|
||||
src/variant.cpp
|
||||
src/exception.cpp
|
||||
src/variant_object.cpp
|
||||
src/string.cpp
|
||||
src/time.cpp
|
||||
src/mock_time.cpp
|
||||
src/utf8.cpp
|
||||
src/io/datastream.cpp
|
||||
src/io/json.cpp
|
||||
src/io/varint.cpp
|
||||
src/io/fstream.cpp
|
||||
src/io/console.cpp
|
||||
src/filesystem.cpp
|
||||
src/interprocess/file_mapping.cpp
|
||||
src/interprocess/mmap_struct.cpp
|
||||
src/log/log_message.cpp
|
||||
src/log/logger.cpp
|
||||
src/log/appender.cpp
|
||||
src/log/console_appender.cpp
|
||||
src/log/dmlog_appender.cpp
|
||||
src/log/logger_config.cpp
|
||||
src/crypto/_digest_common.cpp
|
||||
src/crypto/aes.cpp
|
||||
src/crypto/crc.cpp
|
||||
src/crypto/city.cpp
|
||||
# src/crypto/base32.cpp
|
||||
src/crypto/base36.cpp
|
||||
src/crypto/base58.cpp
|
||||
src/crypto/base64.cpp
|
||||
src/crypto/bigint.cpp
|
||||
src/crypto/hex.cpp
|
||||
src/crypto/sha1.cpp
|
||||
src/crypto/sha3.cpp
|
||||
src/crypto/ripemd160.cpp
|
||||
src/crypto/sha256.cpp
|
||||
src/crypto/sha224.cpp
|
||||
src/crypto/sha512.cpp
|
||||
src/crypto/dh.cpp
|
||||
src/crypto/blowfish.cpp
|
||||
src/crypto/elliptic_common.cpp
|
||||
src/crypto/elliptic_impl_priv.cpp
|
||||
src/crypto/elliptic_secp256k1.cpp
|
||||
src/crypto/elliptic_r1.cpp
|
||||
src/crypto/elliptic_webauthn.cpp
|
||||
src/crypto/rand.cpp
|
||||
src/crypto/public_key.cpp
|
||||
src/crypto/private_key.cpp
|
||||
src/crypto/signature.cpp
|
||||
src/crypto/alt_bn128.cpp
|
||||
src/crypto/modular_arithmetic.cpp
|
||||
src/crypto/blake2.cpp
|
||||
src/crypto/k1_recover.cpp
|
||||
src/network/ip.cpp
|
||||
src/network/platform_root_ca.cpp
|
||||
src/network/resolve.cpp
|
||||
src/network/udp_socket.cpp
|
||||
src/network/url.cpp
|
||||
src/network/http/http_client.cpp
|
||||
src/compress/smaz.cpp
|
||||
src/compress/zlib.cpp
|
||||
src/log/gelf_appender.cpp
|
||||
src/log/zipkin.cpp
|
||||
)
|
||||
|
||||
file( GLOB_RECURSE fc_headers ${CMAKE_CURRENT_SOURCE_DIR} *.hpp *.h )
|
||||
|
||||
add_library(fc ${fc_sources} ${fc_headers})
|
||||
|
||||
function(detect_thread_name)
|
||||
include(CheckSymbolExists)
|
||||
list(APPEND CMAKE_REQUIRED_DEFINITIONS -D_GNU_SOURCE)
|
||||
list(APPEND CMAKE_REQUIRED_LIBRARIES "-pthread")
|
||||
check_symbol_exists(pthread_setname_np pthread.h HAVE_PTHREAD_SETNAME_NP)
|
||||
if(HAVE_PTHREAD_SETNAME_NP)
|
||||
set_source_files_properties(src/log/logger_config.cpp PROPERTIES COMPILE_DEFINITIONS FC_USE_PTHREAD_NAME_NP)
|
||||
endif()
|
||||
endfunction()
|
||||
if(CMAKE_SYSTEM_NAME MATCHES "Linux")
|
||||
detect_thread_name()
|
||||
endif()
|
||||
|
||||
# Yuck: newer CMake files from boost iostreams will effectively target_link_libraries(Boost::iostreams z;bz2;lzma;zstd)
|
||||
# without first "finding" those libraries. This resolves to simple -lz -lbz2 etc: it'll look for those libraries in the linker's
|
||||
# library search path. This is most problematic on macOS where something like libzstd isn't in the standard search path. Historically
|
||||
# fc would just "-L/usr/local/lib" as a heavy handed way to make sure something like -lzstd can be found in brew's library path. But
|
||||
# that isn't sufficient for something like ARM homebrew. Let's just "null" these libraries out since we're already linking to zlib
|
||||
# explicitly anyways via a proper find_package(ZLIB) below.
|
||||
if(APPLE)
|
||||
add_library(z INTERFACE)
|
||||
add_library(bz2 INTERFACE)
|
||||
add_library(lzma INTERFACE)
|
||||
add_library(zstd INTERFACE)
|
||||
endif()
|
||||
|
||||
find_package(Boost 1.66 REQUIRED COMPONENTS
|
||||
date_time
|
||||
filesystem
|
||||
chrono
|
||||
unit_test_framework
|
||||
iostreams)
|
||||
|
||||
# fc picks up a dependency on zlib via Boost::iostreams, however in some versions of cmake/boost (depending on if CMake config
|
||||
# files are used) the Boost::iostreams target does not have a dependency on zlib itself so add it explicitly
|
||||
find_package(ZLIB REQUIRED)
|
||||
|
||||
target_include_directories(fc PUBLIC include)
|
||||
|
||||
# try and make this very clear that this json parser is intended only for webauthn parsing..
|
||||
if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.11.0)
|
||||
set_source_files_properties(src/crypto/elliptic_webauthn.cpp PROPERTIES INCLUDE_DIRECTORIES "${CMAKE_CURRENT_SOURCE_DIR}/include/fc/crypto/webauthn_json/include")
|
||||
else()
|
||||
set_source_files_properties(src/crypto/elliptic_webauthn.cpp PROPERTIES COMPILE_FLAGS "-I${CMAKE_CURRENT_SOURCE_DIR}/include/fc/crypto/webauthn_json/include")
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
target_link_libraries( fc PUBLIC ws2_32 mswsock userenv )
|
||||
endif()
|
||||
|
||||
if(APPLE)
|
||||
find_library(security_framework Security)
|
||||
find_library(corefoundation_framework CoreFoundation)
|
||||
endif()
|
||||
target_link_libraries( fc PUBLIC ff
|
||||
Boost::date_time Boost::filesystem Boost::chrono Boost::iostreams Threads::Threads
|
||||
OpenSSL::Crypto OpenSSL::SSL ZLIB::ZLIB ${PLATFORM_SPECIFIC_LIBS} ${CMAKE_DL_LIBS} secp256k1 ${security_framework} ${corefoundation_framework} )
|
||||
|
||||
# Critically, this ensures that OpenSSL 1.1 & 3.0 both have a variant of BN_zero() with void return value. But it also allows access
|
||||
# to some obsoleted AES functions in 3.0 too, since 3.0's API_COMPAT is effectively 3.0 by default
|
||||
target_compile_definitions(fc PUBLIC "OPENSSL_API_COMPAT=0x10100000L" "OPENSSL_NO_DEPRECATED")
|
||||
|
||||
add_subdirectory( test )
|
||||
|
||||
install(TARGETS fc
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR} COMPONENT dev EXCLUDE_FROM_ALL
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR} COMPONENT dev EXCLUDE_FROM_ALL)
|
||||
install(DIRECTORY include/fc DESTINATION ${CMAKE_INSTALL_FULL_INCLUDEDIR} COMPONENT dev EXCLUDE_FROM_ALL)
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
#pragma once
|
||||
#include <fc/api.hpp>
|
||||
#include <fc/thread/thread.hpp>
|
||||
|
||||
namespace fc {
|
||||
|
||||
namespace detail {
|
||||
struct actor_member {
|
||||
#if 1 // BOOST_NO_VARIADIC_TEMPLATES
|
||||
#define RPC_MEMBER_FUNCTOR(z,n,IS_CONST) \
|
||||
template<typename R, typename C, typename P BOOST_PP_ENUM_TRAILING_PARAMS( n, typename A)> \
|
||||
static std::function<fc::future<R>( BOOST_PP_ENUM_PARAMS(n,A) ) > \
|
||||
functor( P p, R (C::*mem_func)(BOOST_PP_ENUM_PARAMS(n,A)) IS_CONST, fc::thread* c = 0) { \
|
||||
return [=](BOOST_PP_ENUM_BINARY_PARAMS(n,A,a))->fc::future<R>{ \
|
||||
return c->async( [=](){ return (p->*mem_func)(BOOST_PP_ENUM_PARAMS(n,a)); } ); }; \
|
||||
}
|
||||
BOOST_PP_REPEAT( 8, RPC_MEMBER_FUNCTOR, const )
|
||||
BOOST_PP_REPEAT( 8, RPC_MEMBER_FUNCTOR, BOOST_PP_EMPTY() )
|
||||
#undef RPC_MEMBER_FUNCTOR
|
||||
|
||||
#else // g++ has a bug that prevents lambdas and varidic templates from working together (G++ Bug 41933)
|
||||
|
||||
template<typename R, typename C, typename P, typename... Args>
|
||||
static std::function<fc::future<R>(Args...)> functor( P&& p, R (C::*mem_func)(Args...), fc::thread* c ) {
|
||||
return [=](Args... args)->fc::future<R>{ c->async( [=]()->R { return p->*mem_func( fc::forward<Args>(args)... ); } ) };
|
||||
}
|
||||
template<typename R, typename C, typename P, typename... Args>
|
||||
static std::function<fc::future<R>(Args...)> functor( P&& p, R (C::*mem_func)(Args...)const, fc::thread* c ){
|
||||
return [=](Args... args)->fc::future<R>{ c->async( [=]()->R { return p->*mem_func( fc::forward<Args>(args)... ); } ) };
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
template<typename ThisPtr>
|
||||
struct actor_vtable_visitor {
|
||||
template<typename U>
|
||||
actor_vtable_visitor( fc::thread* t, U&& u ):_thread(t),_this( fc::forward<U>(u) ){}
|
||||
|
||||
template<typename Function, typename MemberPtr>
|
||||
void operator()( const char* name, Function& memb, MemberPtr m )const {
|
||||
memb = actor_member::functor( _this, m, _thread );
|
||||
}
|
||||
fc::thread* _thread;
|
||||
ThisPtr _this;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Posts all method calls to another thread and
|
||||
* returns a future.
|
||||
*/
|
||||
template<typename Interface>
|
||||
class actor : public api<Interface, detail::actor_member> {
|
||||
public:
|
||||
actor(){}
|
||||
|
||||
template<typename InterfaceType>
|
||||
actor( InterfaceType* p, fc::thread* t = &fc::thread::current() )
|
||||
{
|
||||
this->_vtable.reset(new detail::vtable<Interface,detail::actor_member>() );
|
||||
this->_vtable->template visit<InterfaceType>( detail::actor_vtable_visitor<InterfaceType*>(t, p) );
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace fc
|
||||
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
namespace fc {
|
||||
|
||||
template<unsigned int S, typename T=double>
|
||||
struct aligned {
|
||||
union {
|
||||
T _align;
|
||||
char _data[S];
|
||||
} _store;
|
||||
operator char*() { return _store._data; }
|
||||
operator const char*()const { return _store._data; }
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
#include <boost/any.hpp>
|
||||
|
||||
namespace fc {
|
||||
// TODO: define this without using boost
|
||||
typedef boost::any any;
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
#pragma once
|
||||
#include <fc/thread/future.hpp>
|
||||
#include <fc/any.hpp>
|
||||
#include <functional>
|
||||
#include <boost/config.hpp>
|
||||
|
||||
// ms visual c++ (as of 2013) doesn't accept the standard syntax for calling a
|
||||
// templated member function (foo->template bar();)
|
||||
#ifdef _MSC_VER
|
||||
# define FC_CALL_MEMBER_TEMPLATE_KEYWORD
|
||||
#else
|
||||
# define FC_CALL_MEMBER_TEMPLATE_KEYWORD template
|
||||
#endif
|
||||
|
||||
namespace fc {
|
||||
struct identity_member {
|
||||
template<typename R, typename C, typename P, typename... Args>
|
||||
static std::function<R(Args...)> functor( P&& p, R (C::*mem_func)(Args...) );
|
||||
template<typename R, typename C, typename P, typename... Args>
|
||||
static std::function<R(Args...)> functor( P&& p, R (C::*mem_func)(Args...)const );
|
||||
};
|
||||
|
||||
template< typename Interface, typename Transform >
|
||||
struct vtable : public std::enable_shared_from_this<vtable<Interface,Transform>>
|
||||
{ private: vtable(); };
|
||||
|
||||
template<typename OtherType>
|
||||
struct vtable_copy_visitor {
|
||||
typedef OtherType other_type;
|
||||
|
||||
vtable_copy_visitor( OtherType& s):_source( s ){}
|
||||
|
||||
template<typename R, typename MemberPtr, typename... Args>
|
||||
void operator()( const char* name, std::function<R(Args...)>& memb, MemberPtr m )const {
|
||||
OtherType* src = &_source;
|
||||
memb = [src,m]( Args... args ){ return (src->*m)(args...); };
|
||||
}
|
||||
OtherType& _source;
|
||||
};
|
||||
|
||||
template<typename Interface, typename Transform >
|
||||
class api;
|
||||
|
||||
class api_connection;
|
||||
|
||||
typedef uint32_t api_id_type;
|
||||
|
||||
class api_base
|
||||
{
|
||||
public:
|
||||
api_base() {}
|
||||
virtual ~api_base() {}
|
||||
|
||||
virtual uint64_t get_handle()const = 0;
|
||||
|
||||
virtual api_id_type register_api( api_connection& conn )const = 0;
|
||||
|
||||
// defined in api_connection.hpp
|
||||
template< typename T >
|
||||
api<T, identity_member> as();
|
||||
};
|
||||
typedef std::shared_ptr< api_base > api_ptr;
|
||||
|
||||
class api_connection;
|
||||
|
||||
template<typename Interface, typename Transform = identity_member >
|
||||
class api : public api_base {
|
||||
public:
|
||||
typedef vtable<Interface,Transform> vtable_type;
|
||||
|
||||
api():_vtable( std::make_shared<vtable_type>() ) {}
|
||||
|
||||
/** T is anything with pointer semantics */
|
||||
template<typename T >
|
||||
api( const T& p )
|
||||
:_vtable( std::make_shared<vtable_type>() )
|
||||
{
|
||||
_data = std::make_shared<fc::any>(p);
|
||||
T& ptr = boost::any_cast<T&>(*_data);
|
||||
auto& pointed_at = *ptr;
|
||||
typedef typename std::remove_reference<decltype(pointed_at)>::type source_vtable_type;
|
||||
_vtable->FC_CALL_MEMBER_TEMPLATE_KEYWORD visit_other( vtable_copy_visitor<source_vtable_type>(pointed_at) );
|
||||
}
|
||||
|
||||
api( const api& cpy ):_vtable(cpy._vtable),_data(cpy._data) {}
|
||||
virtual ~api() {}
|
||||
|
||||
friend bool operator == ( const api& a, const api& b ) { return a._data == b._data && a._vtable == b._vtable; }
|
||||
friend bool operator != ( const api& a, const api& b ) { return !(a._data == b._data && a._vtable == b._vtable); }
|
||||
virtual uint64_t get_handle()const override { return uint64_t(_data.get()); }
|
||||
virtual api_id_type register_api( api_connection& conn )const override; // defined in api_connection.hpp
|
||||
|
||||
vtable_type& operator*()const { FC_ASSERT( _vtable ); return *_vtable; }
|
||||
vtable_type* operator->()const { FC_ASSERT( _vtable ); return _vtable.get(); }
|
||||
|
||||
protected:
|
||||
std::shared_ptr<vtable_type> _vtable;
|
||||
std::shared_ptr<fc::any> _data;
|
||||
};
|
||||
|
||||
} // namespace fc
|
||||
|
||||
#include <boost/preprocessor/repeat.hpp>
|
||||
#include <boost/preprocessor/repetition/enum_binary_params.hpp>
|
||||
#include <boost/preprocessor/repetition/enum_params.hpp>
|
||||
#include <boost/preprocessor/repetition/enum_trailing_params.hpp>
|
||||
#include <boost/preprocessor/facilities/empty.hpp>
|
||||
#include <boost/preprocessor/seq/for_each.hpp>
|
||||
#include <boost/preprocessor/stringize.hpp>
|
||||
|
||||
#define FC_API_VTABLE_DEFINE_MEMBER( r, data, elem ) \
|
||||
decltype(Transform::functor( (data*)nullptr, &data::elem)) elem;
|
||||
#define FC_API_VTABLE_DEFINE_VISIT_OTHER( r, data, elem ) \
|
||||
{ typedef typename Visitor::other_type OtherType; \
|
||||
v( BOOST_PP_STRINGIZE(elem), elem, &OtherType::elem ); }
|
||||
#define FC_API_VTABLE_DEFINE_VISIT( r, data, elem ) \
|
||||
v( BOOST_PP_STRINGIZE(elem), elem );
|
||||
|
||||
#define FC_API( CLASS, METHODS ) \
|
||||
namespace fc { \
|
||||
template<typename Transform> \
|
||||
struct vtable<CLASS,Transform> : public std::enable_shared_from_this<vtable<CLASS,Transform>> { \
|
||||
BOOST_PP_SEQ_FOR_EACH( FC_API_VTABLE_DEFINE_MEMBER, CLASS, METHODS ) \
|
||||
template<typename Visitor> \
|
||||
void visit_other( Visitor&& v ){ \
|
||||
BOOST_PP_SEQ_FOR_EACH( FC_API_VTABLE_DEFINE_VISIT_OTHER, CLASS, METHODS ) \
|
||||
} \
|
||||
template<typename Visitor> \
|
||||
void visit( Visitor&& v ){ \
|
||||
BOOST_PP_SEQ_FOR_EACH( FC_API_VTABLE_DEFINE_VISIT, CLASS, METHODS ) \
|
||||
} \
|
||||
}; \
|
||||
}
|
||||
|
||||
@@ -0,0 +1,145 @@
|
||||
#pragma once
|
||||
#include <fc/crypto/base64.hpp>
|
||||
#include <fc/variant.hpp>
|
||||
#include <fc/reflect/reflect.hpp>
|
||||
#include <fc/exception/exception.hpp>
|
||||
|
||||
namespace fc {
|
||||
|
||||
/**
|
||||
* Provides a fixed size array that is easier for templates to specialize
|
||||
* against or overload than T[N].
|
||||
*/
|
||||
template<typename T, size_t N>
|
||||
class array {
|
||||
public:
|
||||
/**
|
||||
* Checked indexing (when in debug build) that also simplifies dereferencing
|
||||
* when you have an array<T,N>*.
|
||||
*/
|
||||
///@{
|
||||
T& at( size_t pos ) { FC_ASSERT( pos < N, "array out-of-bounds" ); return data[pos]; }
|
||||
const T& at( size_t pos )const { FC_ASSERT( pos < N, "array out-of-bounds" ); return data[pos]; }
|
||||
///@}
|
||||
|
||||
T& operator[]( size_t pos ) { FC_ASSERT( pos < N, "array out-of-bounds" ); return data[pos]; }
|
||||
const T& operator[]( size_t pos )const { FC_ASSERT( pos < N, "array out-of-bounds" ); return data[pos]; }
|
||||
|
||||
|
||||
const T* begin()const { return &data[0]; }
|
||||
const T* end()const { return &data[N]; }
|
||||
|
||||
T* begin() { return &data[0]; }
|
||||
T* end() { return &data[N]; }
|
||||
|
||||
size_t size()const { return N; }
|
||||
|
||||
T data[N];
|
||||
};
|
||||
|
||||
/** provided for default 0 init */
|
||||
template<size_t N>
|
||||
class array<unsigned char,N>
|
||||
{
|
||||
public:
|
||||
typedef unsigned char T;
|
||||
array(){ memset( data, 0, sizeof(data) ); }
|
||||
/**
|
||||
* Checked indexing (when in debug build) that also simplifies dereferencing
|
||||
* when you have an array<T,N>*.
|
||||
*/
|
||||
///@{
|
||||
T& at( size_t pos ) { FC_ASSERT( pos < N, "array out-of-bounds" ); return data[pos]; }
|
||||
const T& at( size_t pos )const { FC_ASSERT( pos < N, "array out-of-bounds" ); return data[pos]; }
|
||||
///@}
|
||||
|
||||
T* begin() { return &data[0]; }
|
||||
const T* begin()const { return &data[0]; }
|
||||
const T* end()const { return &data[N]; }
|
||||
|
||||
size_t size()const { return N; }
|
||||
|
||||
T data[N];
|
||||
};
|
||||
|
||||
/** provided for default 0 init */
|
||||
template<size_t N>
|
||||
class array<char,N>
|
||||
{
|
||||
public:
|
||||
typedef char T;
|
||||
array(){ memset( data, 0, sizeof(data) ); }
|
||||
/**
|
||||
* Checked indexing (when in debug build) that also simplifies dereferencing
|
||||
* when you have an array<T,N>*.
|
||||
*/
|
||||
///@{
|
||||
T& at( size_t pos ) { FC_ASSERT( pos < N, "array out-of-bounds" ); return data[pos]; }
|
||||
const T& at( size_t pos )const { FC_ASSERT( pos < N, "array out-of-bounds" ); return data[pos]; }
|
||||
///@}
|
||||
|
||||
T* begin() { return &data[0]; }
|
||||
const T* begin()const { return &data[0]; }
|
||||
const T* end()const { return &data[N]; }
|
||||
|
||||
size_t size()const { return N; }
|
||||
|
||||
T data[N];
|
||||
};
|
||||
|
||||
template<typename T, size_t N>
|
||||
bool operator == ( const array<T,N>& a, const array<T,N>& b )
|
||||
{ return 0 == memcmp( a.data, b.data, N*sizeof(T) ); }
|
||||
template<typename T, size_t N>
|
||||
bool operator < ( const array<T,N>& a, const array<T,N>& b )
|
||||
{ return memcmp( a.data, b.data, N*sizeof(T) ) < 0 ; }
|
||||
|
||||
template<typename T, size_t N>
|
||||
bool operator > ( const array<T,N>& a, const array<T,N>& b )
|
||||
{ return memcmp( a.data, b.data, N*sizeof(T) ) > 0 ; }
|
||||
|
||||
template<typename T, size_t N>
|
||||
bool operator != ( const array<T,N>& a, const array<T,N>& b )
|
||||
{ return 0 != memcmp( a.data, b.data, N*sizeof(T) ); }
|
||||
|
||||
template<typename T, size_t N>
|
||||
void to_variant( const array<T,N>& bi, variant& v )
|
||||
{
|
||||
v = std::vector<char>( (const char*)&bi, ((const char*)&bi) + sizeof(bi) );
|
||||
}
|
||||
template<typename T, size_t N>
|
||||
void from_variant( const variant& v, array<T,N>& bi )
|
||||
{
|
||||
std::vector<char> ve = v.as< std::vector<char> >();
|
||||
if( ve.size() )
|
||||
{
|
||||
memcpy(bi.begin(), ve.data(), fc::min<size_t>(ve.size(),sizeof(bi)) );
|
||||
}
|
||||
else
|
||||
memset( bi.begin(), char(0), sizeof(bi) );
|
||||
}
|
||||
|
||||
|
||||
template<typename T,size_t N> struct get_typename< fc::array<T,N> >
|
||||
{
|
||||
static const char* name()
|
||||
{
|
||||
static std::string _name = std::string("fc::array<")+std::string(fc::get_typename<T>::name())+","+ fc::to_string(N) + ">";
|
||||
return _name.c_str();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#include <unordered_map>
|
||||
#include <fc/crypto/city.hpp>
|
||||
namespace std
|
||||
{
|
||||
template<typename T, size_t N>
|
||||
struct hash<fc::array<T,N> >
|
||||
{
|
||||
size_t operator()( const fc::array<T,N>& e )const
|
||||
{
|
||||
return fc::city_hash_size_t( (char*)&e, sizeof(e) );
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
|
||||
namespace fc {
|
||||
|
||||
inline uint64_t endian_reverse_u64( uint64_t x )
|
||||
{
|
||||
return (((x >> 0x38) & 0xFF) )
|
||||
| (((x >> 0x30) & 0xFF) << 0x08)
|
||||
| (((x >> 0x28) & 0xFF) << 0x10)
|
||||
| (((x >> 0x20) & 0xFF) << 0x18)
|
||||
| (((x >> 0x18) & 0xFF) << 0x20)
|
||||
| (((x >> 0x10) & 0xFF) << 0x28)
|
||||
| (((x >> 0x08) & 0xFF) << 0x30)
|
||||
| (((x ) & 0xFF) << 0x38)
|
||||
;
|
||||
}
|
||||
|
||||
inline uint32_t endian_reverse_u32( uint32_t x )
|
||||
{
|
||||
return (((x >> 0x18) & 0xFF) )
|
||||
| (((x >> 0x10) & 0xFF) << 0x08)
|
||||
| (((x >> 0x08) & 0xFF) << 0x10)
|
||||
| (((x ) & 0xFF) << 0x18)
|
||||
;
|
||||
}
|
||||
|
||||
} // namespace fc
|
||||
@@ -0,0 +1,621 @@
|
||||
#pragma once
|
||||
|
||||
/*
|
||||
*********************************************************************
|
||||
* *
|
||||
* Open Bloom Filter *
|
||||
* *
|
||||
* Author: Arash Partow - 2000 *
|
||||
* URL: http://www.partow.net *
|
||||
* URL: http://www.partow.net/programming/hashfunctions/index.html *
|
||||
* *
|
||||
* Copyright notice: *
|
||||
* Free use of the Open Bloom Filter Library is permitted under the *
|
||||
* guidelines and in accordance with the most current version of the *
|
||||
* Common Public License. *
|
||||
* http://www.opensource.org/licenses/cpl1.0.php *
|
||||
* *
|
||||
*********************************************************************
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <cstddef>
|
||||
#include <iterator>
|
||||
#include <limits>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <fc/reflect/reflect.hpp>
|
||||
|
||||
namespace fc {
|
||||
|
||||
|
||||
static const std::size_t bits_per_char = 0x08; // 8 bits in 1 char(unsigned)
|
||||
static const unsigned char bit_mask[bits_per_char] = {
|
||||
0x01, //00000001
|
||||
0x02, //00000010
|
||||
0x04, //00000100
|
||||
0x08, //00001000
|
||||
0x10, //00010000
|
||||
0x20, //00100000
|
||||
0x40, //01000000
|
||||
0x80 //10000000
|
||||
};
|
||||
|
||||
class bloom_parameters
|
||||
{
|
||||
public:
|
||||
|
||||
bloom_parameters()
|
||||
: minimum_size(1),
|
||||
maximum_size(std::numeric_limits<unsigned long long int>::max()),
|
||||
minimum_number_of_hashes(1),
|
||||
maximum_number_of_hashes(std::numeric_limits<unsigned int>::max()),
|
||||
projected_element_count(10000),
|
||||
false_positive_probability(1.0 / projected_element_count),
|
||||
random_seed(0xA5A5A5A55A5A5A5AULL)
|
||||
{}
|
||||
|
||||
virtual ~bloom_parameters()
|
||||
{}
|
||||
|
||||
inline bool operator!()
|
||||
{
|
||||
return (minimum_size > maximum_size) ||
|
||||
(minimum_number_of_hashes > maximum_number_of_hashes) ||
|
||||
(minimum_number_of_hashes < 1) ||
|
||||
(0 == maximum_number_of_hashes) ||
|
||||
(0 == projected_element_count) ||
|
||||
(false_positive_probability < 0.0) ||
|
||||
(std::numeric_limits<double>::infinity() == std::abs(false_positive_probability)) ||
|
||||
(0 == random_seed) ||
|
||||
(0xFFFFFFFFFFFFFFFFULL == random_seed);
|
||||
}
|
||||
|
||||
//Allowed min/max size of the bloom filter in bits
|
||||
unsigned long long int minimum_size;
|
||||
unsigned long long int maximum_size;
|
||||
|
||||
//Allowed min/max number of hash functions
|
||||
unsigned int minimum_number_of_hashes;
|
||||
unsigned int maximum_number_of_hashes;
|
||||
|
||||
//The approximate number of elements to be inserted
|
||||
//into the bloom filter, should be within one order
|
||||
//of magnitude. The default is 10000.
|
||||
unsigned long long int projected_element_count;
|
||||
|
||||
//The approximate false positive probability expected
|
||||
//from the bloom filter. The default is the reciprocal
|
||||
//of the projected_element_count.
|
||||
double false_positive_probability;
|
||||
|
||||
unsigned long long int random_seed;
|
||||
|
||||
struct optimal_parameters_t
|
||||
{
|
||||
optimal_parameters_t()
|
||||
: number_of_hashes(0),
|
||||
table_size(0)
|
||||
{}
|
||||
|
||||
unsigned int number_of_hashes;
|
||||
unsigned long long int table_size;
|
||||
};
|
||||
|
||||
optimal_parameters_t optimal_parameters;
|
||||
|
||||
virtual bool compute_optimal_parameters()
|
||||
{
|
||||
/*
|
||||
Note:
|
||||
The following will attempt to find the number of hash functions
|
||||
and minimum amount of storage bits required to construct a bloom
|
||||
filter consistent with the user defined false positive probability
|
||||
and estimated element insertion count.
|
||||
*/
|
||||
|
||||
if (!(*this))
|
||||
return false;
|
||||
|
||||
double min_m = std::numeric_limits<double>::infinity();
|
||||
double min_k = 0.0;
|
||||
double curr_m = 0.0;
|
||||
double k = 1.0;
|
||||
|
||||
while (k < 1000.0)
|
||||
{
|
||||
double numerator = (- k * projected_element_count);
|
||||
double denominator = std::log(1.0 - std::pow(false_positive_probability, 1.0 / k));
|
||||
curr_m = numerator / denominator;
|
||||
if (curr_m < min_m)
|
||||
{
|
||||
min_m = curr_m;
|
||||
min_k = k;
|
||||
}
|
||||
k += 1.0;
|
||||
}
|
||||
|
||||
optimal_parameters_t& optp = optimal_parameters;
|
||||
|
||||
optp.number_of_hashes = static_cast<unsigned int>(min_k);
|
||||
optp.table_size = static_cast<unsigned long long int>(min_m);
|
||||
optp.table_size += (((optp.table_size % bits_per_char) != 0) ? (bits_per_char - (optp.table_size % bits_per_char)) : 0);
|
||||
|
||||
if (optp.number_of_hashes < minimum_number_of_hashes)
|
||||
optp.number_of_hashes = minimum_number_of_hashes;
|
||||
else if (optp.number_of_hashes > maximum_number_of_hashes)
|
||||
optp.number_of_hashes = maximum_number_of_hashes;
|
||||
|
||||
if (optp.table_size < minimum_size)
|
||||
optp.table_size = minimum_size;
|
||||
else if (optp.table_size > maximum_size)
|
||||
optp.table_size = maximum_size;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class bloom_filter
|
||||
{
|
||||
protected:
|
||||
|
||||
typedef unsigned int bloom_type;
|
||||
typedef unsigned char cell_type;
|
||||
|
||||
public:
|
||||
|
||||
bloom_filter()
|
||||
: salt_count_(0),
|
||||
table_size_(0),
|
||||
raw_table_size_(0),
|
||||
projected_element_count_(0),
|
||||
inserted_element_count_(0),
|
||||
random_seed_(0),
|
||||
desired_false_positive_probability_(0.0)
|
||||
{}
|
||||
|
||||
bloom_filter(const bloom_parameters& p)
|
||||
: projected_element_count_(p.projected_element_count),
|
||||
inserted_element_count_(0),
|
||||
random_seed_((p.random_seed * 0xA5A5A5A5) + 1),
|
||||
desired_false_positive_probability_(p.false_positive_probability)
|
||||
{
|
||||
salt_count_ = p.optimal_parameters.number_of_hashes;
|
||||
table_size_ = p.optimal_parameters.table_size;
|
||||
generate_unique_salt();
|
||||
raw_table_size_ = table_size_ / bits_per_char;
|
||||
|
||||
bit_table_.resize( static_cast<std::size_t>(raw_table_size_) );
|
||||
//bit_table_ = new cell_type[static_cast<std::size_t>(raw_table_size_)];
|
||||
std::fill_n(bit_table_.data(),raw_table_size_,0x00);
|
||||
}
|
||||
|
||||
bloom_filter(const bloom_filter& filter)
|
||||
{
|
||||
this->operator=(filter);
|
||||
}
|
||||
|
||||
inline bool operator == (const bloom_filter& f) const
|
||||
{
|
||||
if (this != &f)
|
||||
{
|
||||
return
|
||||
(salt_count_ == f.salt_count_) &&
|
||||
(table_size_ == f.table_size_) &&
|
||||
(raw_table_size_ == f.raw_table_size_) &&
|
||||
(projected_element_count_ == f.projected_element_count_) &&
|
||||
(inserted_element_count_ == f.inserted_element_count_) &&
|
||||
(random_seed_ == f.random_seed_) &&
|
||||
(desired_false_positive_probability_ == f.desired_false_positive_probability_) &&
|
||||
(salt_ == f.salt_) &&
|
||||
std::equal(f.bit_table_.data(),f.bit_table_.data() + raw_table_size_,bit_table_.data());
|
||||
}
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool operator != (const bloom_filter& f) const
|
||||
{
|
||||
return !operator==(f);
|
||||
}
|
||||
|
||||
inline bloom_filter& operator = (const bloom_filter& f)
|
||||
{
|
||||
if (this != &f)
|
||||
{
|
||||
salt_count_ = f.salt_count_;
|
||||
table_size_ = f.table_size_;
|
||||
raw_table_size_ = f.raw_table_size_;
|
||||
projected_element_count_ = f.projected_element_count_;
|
||||
inserted_element_count_ = f.inserted_element_count_;
|
||||
random_seed_ = f.random_seed_;
|
||||
desired_false_positive_probability_ = f.desired_false_positive_probability_;
|
||||
bit_table_.resize( raw_table_size_ );
|
||||
std::copy(f.bit_table_.data(),f.bit_table_.data() + raw_table_size_,bit_table_.data());
|
||||
salt_ = f.salt_;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
virtual ~bloom_filter()
|
||||
{
|
||||
}
|
||||
|
||||
inline bool operator!() const
|
||||
{
|
||||
return (0 == table_size_);
|
||||
}
|
||||
|
||||
inline void clear()
|
||||
{
|
||||
std::fill_n(bit_table_.data(),raw_table_size_,0x00);
|
||||
inserted_element_count_ = 0;
|
||||
}
|
||||
|
||||
inline void insert(const unsigned char* key_begin, const std::size_t& length)
|
||||
{
|
||||
std::size_t bit_index = 0;
|
||||
std::size_t bit = 0;
|
||||
for (std::size_t i = 0; i < salt_.size(); ++i)
|
||||
{
|
||||
compute_indices(hash_ap(key_begin,length,salt_[i]),bit_index,bit);
|
||||
bit_table_[bit_index / bits_per_char] |= bit_mask[bit];
|
||||
}
|
||||
++inserted_element_count_;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline void insert(const T& t)
|
||||
{
|
||||
// Note: T must be a C++ POD type.
|
||||
insert(reinterpret_cast<const unsigned char*>(&t),sizeof(T));
|
||||
}
|
||||
|
||||
inline void insert(const std::string& key)
|
||||
{
|
||||
insert(reinterpret_cast<const unsigned char*>(key.c_str()),key.size());
|
||||
}
|
||||
|
||||
inline void insert(const char* data, const std::size_t& length)
|
||||
{
|
||||
insert(reinterpret_cast<const unsigned char*>(data),length);
|
||||
}
|
||||
|
||||
template<typename InputIterator>
|
||||
inline void insert(const InputIterator begin, const InputIterator end)
|
||||
{
|
||||
InputIterator itr = begin;
|
||||
while (end != itr)
|
||||
{
|
||||
insert(*(itr++));
|
||||
}
|
||||
}
|
||||
|
||||
inline virtual bool contains(const unsigned char* key_begin, const std::size_t length) const
|
||||
{
|
||||
std::size_t bit_index = 0;
|
||||
std::size_t bit = 0;
|
||||
for (std::size_t i = 0; i < salt_.size(); ++i)
|
||||
{
|
||||
compute_indices(hash_ap(key_begin,length,salt_[i]),bit_index,bit);
|
||||
if ((bit_table_[bit_index / bits_per_char] & bit_mask[bit]) != bit_mask[bit])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline bool contains(const T& t) const
|
||||
{
|
||||
return contains(reinterpret_cast<const unsigned char*>(&t),static_cast<std::size_t>(sizeof(T)));
|
||||
}
|
||||
|
||||
inline bool contains(const std::string& key) const
|
||||
{
|
||||
return contains(reinterpret_cast<const unsigned char*>(key.c_str()),key.size());
|
||||
}
|
||||
|
||||
inline bool contains(const char* data, const std::size_t& length) const
|
||||
{
|
||||
return contains(reinterpret_cast<const unsigned char*>(data),length);
|
||||
}
|
||||
|
||||
template<typename InputIterator>
|
||||
inline InputIterator contains_all(const InputIterator begin, const InputIterator end) const
|
||||
{
|
||||
InputIterator itr = begin;
|
||||
while (end != itr)
|
||||
{
|
||||
if (!contains(*itr))
|
||||
{
|
||||
return itr;
|
||||
}
|
||||
++itr;
|
||||
}
|
||||
return end;
|
||||
}
|
||||
|
||||
template<typename InputIterator>
|
||||
inline InputIterator contains_none(const InputIterator begin, const InputIterator end) const
|
||||
{
|
||||
InputIterator itr = begin;
|
||||
while (end != itr)
|
||||
{
|
||||
if (contains(*itr))
|
||||
{
|
||||
return itr;
|
||||
}
|
||||
++itr;
|
||||
}
|
||||
return end;
|
||||
}
|
||||
|
||||
inline virtual unsigned long long int size() const
|
||||
{
|
||||
return table_size_;
|
||||
}
|
||||
|
||||
inline std::size_t element_count() const
|
||||
{
|
||||
return inserted_element_count_;
|
||||
}
|
||||
|
||||
inline double effective_fpp() const
|
||||
{
|
||||
/*
|
||||
Note:
|
||||
The effective false positive probability is calculated using the
|
||||
designated table size and hash function count in conjunction with
|
||||
the current number of inserted elements - not the user defined
|
||||
predicated/expected number of inserted elements.
|
||||
*/
|
||||
return std::pow(1.0 - std::exp(-1.0 * salt_.size() * inserted_element_count_ / size()), 1.0 * salt_.size());
|
||||
}
|
||||
|
||||
inline bloom_filter& operator &= (const bloom_filter& f)
|
||||
{
|
||||
/* intersection */
|
||||
if (
|
||||
(salt_count_ == f.salt_count_) &&
|
||||
(table_size_ == f.table_size_) &&
|
||||
(random_seed_ == f.random_seed_)
|
||||
)
|
||||
{
|
||||
for (std::size_t i = 0; i < raw_table_size_; ++i)
|
||||
{
|
||||
bit_table_[i] &= f.bit_table_[i];
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline bloom_filter& operator |= (const bloom_filter& f)
|
||||
{
|
||||
/* union */
|
||||
if (
|
||||
(salt_count_ == f.salt_count_) &&
|
||||
(table_size_ == f.table_size_) &&
|
||||
(random_seed_ == f.random_seed_)
|
||||
)
|
||||
{
|
||||
for (std::size_t i = 0; i < raw_table_size_; ++i)
|
||||
{
|
||||
bit_table_[i] |= f.bit_table_[i];
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline bloom_filter& operator ^= (const bloom_filter& f)
|
||||
{
|
||||
/* difference */
|
||||
if (
|
||||
(salt_count_ == f.salt_count_) &&
|
||||
(table_size_ == f.table_size_) &&
|
||||
(random_seed_ == f.random_seed_)
|
||||
)
|
||||
{
|
||||
for (std::size_t i = 0; i < raw_table_size_; ++i)
|
||||
{
|
||||
bit_table_[i] ^= f.bit_table_[i];
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline const cell_type* table() const
|
||||
{
|
||||
return bit_table_.data();
|
||||
}
|
||||
|
||||
inline std::size_t hash_count()
|
||||
{
|
||||
return salt_.size();
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
inline virtual void compute_indices(const bloom_type& hash, std::size_t& bit_index, std::size_t& bit) const
|
||||
{
|
||||
bit_index = hash % table_size_;
|
||||
bit = bit_index % bits_per_char;
|
||||
}
|
||||
|
||||
void generate_unique_salt()
|
||||
{
|
||||
/*
|
||||
Note:
|
||||
A distinct hash function need not be implementation-wise
|
||||
distinct. In the current implementation "seeding" a common
|
||||
hash function with different values seems to be adequate.
|
||||
*/
|
||||
const unsigned int predef_salt_count = 128;
|
||||
static const bloom_type predef_salt[predef_salt_count] =
|
||||
{
|
||||
0xAAAAAAAA, 0x55555555, 0x33333333, 0xCCCCCCCC,
|
||||
0x66666666, 0x99999999, 0xB5B5B5B5, 0x4B4B4B4B,
|
||||
0xAA55AA55, 0x55335533, 0x33CC33CC, 0xCC66CC66,
|
||||
0x66996699, 0x99B599B5, 0xB54BB54B, 0x4BAA4BAA,
|
||||
0xAA33AA33, 0x55CC55CC, 0x33663366, 0xCC99CC99,
|
||||
0x66B566B5, 0x994B994B, 0xB5AAB5AA, 0xAAAAAA33,
|
||||
0x555555CC, 0x33333366, 0xCCCCCC99, 0x666666B5,
|
||||
0x9999994B, 0xB5B5B5AA, 0xFFFFFFFF, 0xFFFF0000,
|
||||
0xB823D5EB, 0xC1191CDF, 0xF623AEB3, 0xDB58499F,
|
||||
0xC8D42E70, 0xB173F616, 0xA91A5967, 0xDA427D63,
|
||||
0xB1E8A2EA, 0xF6C0D155, 0x4909FEA3, 0xA68CC6A7,
|
||||
0xC395E782, 0xA26057EB, 0x0CD5DA28, 0x467C5492,
|
||||
0xF15E6982, 0x61C6FAD3, 0x9615E352, 0x6E9E355A,
|
||||
0x689B563E, 0x0C9831A8, 0x6753C18B, 0xA622689B,
|
||||
0x8CA63C47, 0x42CC2884, 0x8E89919B, 0x6EDBD7D3,
|
||||
0x15B6796C, 0x1D6FDFE4, 0x63FF9092, 0xE7401432,
|
||||
0xEFFE9412, 0xAEAEDF79, 0x9F245A31, 0x83C136FC,
|
||||
0xC3DA4A8C, 0xA5112C8C, 0x5271F491, 0x9A948DAB,
|
||||
0xCEE59A8D, 0xB5F525AB, 0x59D13217, 0x24E7C331,
|
||||
0x697C2103, 0x84B0A460, 0x86156DA9, 0xAEF2AC68,
|
||||
0x23243DA5, 0x3F649643, 0x5FA495A8, 0x67710DF8,
|
||||
0x9A6C499E, 0xDCFB0227, 0x46A43433, 0x1832B07A,
|
||||
0xC46AFF3C, 0xB9C8FFF0, 0xC9500467, 0x34431BDF,
|
||||
0xB652432B, 0xE367F12B, 0x427F4C1B, 0x224C006E,
|
||||
0x2E7E5A89, 0x96F99AA5, 0x0BEB452A, 0x2FD87C39,
|
||||
0x74B2E1FB, 0x222EFD24, 0xF357F60C, 0x440FCB1E,
|
||||
0x8BBE030F, 0x6704DC29, 0x1144D12F, 0x948B1355,
|
||||
0x6D8FD7E9, 0x1C11A014, 0xADD1592F, 0xFB3C712E,
|
||||
0xFC77642F, 0xF9C4CE8C, 0x31312FB9, 0x08B0DD79,
|
||||
0x318FA6E7, 0xC040D23D, 0xC0589AA7, 0x0CA5C075,
|
||||
0xF874B172, 0x0CF914D5, 0x784D3280, 0x4E8CFEBC,
|
||||
0xC569F575, 0xCDB2A091, 0x2CC016B4, 0x5C5F4421
|
||||
};
|
||||
|
||||
if (salt_count_ <= predef_salt_count)
|
||||
{
|
||||
std::copy(predef_salt,
|
||||
predef_salt + salt_count_,
|
||||
std::back_inserter(salt_));
|
||||
for (unsigned int i = 0; i < salt_.size(); ++i)
|
||||
{
|
||||
/*
|
||||
Note:
|
||||
This is done to integrate the user defined random seed,
|
||||
so as to allow for the generation of unique bloom filter
|
||||
instances.
|
||||
*/
|
||||
salt_[i] = salt_[i] * salt_[(i + 3) % salt_.size()] + static_cast<bloom_type>(random_seed_);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::copy(predef_salt,predef_salt + predef_salt_count,std::back_inserter(salt_));
|
||||
srand(static_cast<unsigned int>(random_seed_));
|
||||
while (salt_.size() < salt_count_)
|
||||
{
|
||||
bloom_type current_salt = static_cast<bloom_type>(rand()) * static_cast<bloom_type>(rand());
|
||||
if (0 == current_salt) continue;
|
||||
if (salt_.end() == std::find(salt_.begin(), salt_.end(), current_salt))
|
||||
{
|
||||
salt_.push_back(current_salt);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline bloom_type hash_ap(const unsigned char* begin, std::size_t remaining_length, bloom_type hash) const
|
||||
{
|
||||
const unsigned char* itr = begin;
|
||||
unsigned int loop = 0;
|
||||
while (remaining_length >= 8)
|
||||
{
|
||||
const unsigned int& i1 = *(reinterpret_cast<const unsigned int*>(itr)); itr += sizeof(unsigned int);
|
||||
const unsigned int& i2 = *(reinterpret_cast<const unsigned int*>(itr)); itr += sizeof(unsigned int);
|
||||
hash ^= (hash << 7) ^ i1 * (hash >> 3) ^
|
||||
(~((hash << 11) + (i2 ^ (hash >> 5))));
|
||||
remaining_length -= 8;
|
||||
}
|
||||
if (remaining_length)
|
||||
{
|
||||
if (remaining_length >= 4)
|
||||
{
|
||||
const unsigned int& i = *(reinterpret_cast<const unsigned int*>(itr));
|
||||
if (loop & 0x01)
|
||||
hash ^= (hash << 7) ^ i * (hash >> 3);
|
||||
else
|
||||
hash ^= (~((hash << 11) + (i ^ (hash >> 5))));
|
||||
++loop;
|
||||
remaining_length -= 4;
|
||||
itr += sizeof(unsigned int);
|
||||
}
|
||||
if (remaining_length >= 2)
|
||||
{
|
||||
const unsigned short& i = *(reinterpret_cast<const unsigned short*>(itr));
|
||||
if (loop & 0x01)
|
||||
hash ^= (hash << 7) ^ i * (hash >> 3);
|
||||
else
|
||||
hash ^= (~((hash << 11) + (i ^ (hash >> 5))));
|
||||
++loop;
|
||||
remaining_length -= 2;
|
||||
itr += sizeof(unsigned short);
|
||||
}
|
||||
if (remaining_length)
|
||||
{
|
||||
hash += ((*itr) ^ (hash * 0xA5A5A5A5)) + loop;
|
||||
}
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
public:
|
||||
std::vector<bloom_type> salt_;
|
||||
std::vector<unsigned char> bit_table_;
|
||||
unsigned int salt_count_;
|
||||
unsigned long long int table_size_;
|
||||
unsigned long long int raw_table_size_;
|
||||
unsigned long long int projected_element_count_;
|
||||
unsigned int inserted_element_count_;
|
||||
unsigned long long int random_seed_;
|
||||
double desired_false_positive_probability_;
|
||||
};
|
||||
|
||||
inline bloom_filter operator & (const bloom_filter& a, const bloom_filter& b)
|
||||
{
|
||||
bloom_filter result = a;
|
||||
result &= b;
|
||||
return result;
|
||||
}
|
||||
|
||||
inline bloom_filter operator | (const bloom_filter& a, const bloom_filter& b)
|
||||
{
|
||||
bloom_filter result = a;
|
||||
result |= b;
|
||||
return result;
|
||||
}
|
||||
|
||||
inline bloom_filter operator ^ (const bloom_filter& a, const bloom_filter& b)
|
||||
{
|
||||
bloom_filter result = a;
|
||||
result ^= b;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
} // namespace fc
|
||||
|
||||
|
||||
FC_REFLECT( fc::bloom_filter, (salt_)(bit_table_)(salt_count_)(table_size_)(raw_table_size_)(projected_element_count_)(inserted_element_count_)(random_seed_)(desired_false_positive_probability_) )
|
||||
FC_REFLECT( fc::bloom_parameters::optimal_parameters_t, (number_of_hashes)(table_size) )
|
||||
FC_REFLECT( fc::bloom_parameters, (minimum_size)(maximum_size)(minimum_number_of_hashes)(maximum_number_of_hashes)(projected_element_count)(false_positive_probability)(random_seed)(optimal_parameters) )
|
||||
|
||||
/*
|
||||
Note 1:
|
||||
If it can be guaranteed that bits_per_char will be of the form 2^n then
|
||||
the following optimization can be used:
|
||||
|
||||
hash_table[bit_index >> n] |= bit_mask[bit_index & (bits_per_char - 1)];
|
||||
|
||||
Note 2:
|
||||
For performance reasons where possible when allocating memory it should
|
||||
be aligned (aligned_alloc) according to the architecture being used.
|
||||
*/
|
||||
@@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
#include <string>
|
||||
|
||||
namespace fc {
|
||||
|
||||
std::string smaz_compress( const std::string& in );
|
||||
std::string smaz_decompress( const std::string& compressed );
|
||||
|
||||
} // namespace fc
|
||||
@@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include <fc/string.hpp>
|
||||
|
||||
namespace fc
|
||||
{
|
||||
|
||||
string zlib_compress(const string& in);
|
||||
|
||||
} // namespace fc
|
||||
@@ -0,0 +1,160 @@
|
||||
#pragma once
|
||||
|
||||
#include <fc/variant.hpp>
|
||||
#include <fc/io/raw_fwd.hpp>
|
||||
|
||||
namespace fc {
|
||||
|
||||
namespace raw {
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<template<typename...> class Set, typename Stream, typename T, typename... U>
|
||||
inline void pack_set( Stream& s, const Set<T, U...>& value ) {
|
||||
FC_ASSERT( value.size() <= MAX_NUM_ARRAY_ELEMENTS );
|
||||
pack( s, unsigned_int((uint32_t)value.size()) );
|
||||
for( const auto& item : value ) {
|
||||
pack( s, item );
|
||||
}
|
||||
}
|
||||
|
||||
template<template<typename...> class Set, typename Stream, typename T, typename... U>
|
||||
inline void unpack_set( Stream& s, Set<T, U...>& value ) {
|
||||
unsigned_int size; unpack( s, size );
|
||||
FC_ASSERT( size.value <= MAX_NUM_ARRAY_ELEMENTS );
|
||||
value.clear();
|
||||
for( uint32_t i = 0; i < size.value; ++i ) {
|
||||
auto tmp = ::fc::detail::construct_maybe_with_allocator<T>( value.get_allocator() );
|
||||
unpack( s, tmp );
|
||||
value.insert( value.end(), std::move(tmp) );
|
||||
}
|
||||
}
|
||||
|
||||
template<template<typename...> class Set, typename Stream, typename T, typename... U>
|
||||
inline void unpack_flat_set( Stream& s, Set<T, U...>& value ) {
|
||||
unsigned_int size; unpack( s, size );
|
||||
FC_ASSERT( size.value <= MAX_NUM_ARRAY_ELEMENTS );
|
||||
value.clear();
|
||||
value.reserve( size.value );
|
||||
for( uint32_t i = 0; i < size.value; ++i ) {
|
||||
auto tmp = ::fc::detail::construct_maybe_with_allocator<T>( value.get_allocator() );
|
||||
unpack( s, tmp );
|
||||
value.insert( value.end(), std::move(tmp) );
|
||||
}
|
||||
}
|
||||
|
||||
template<template<typename...> class Map, typename Stream, typename K, typename V, typename... U>
|
||||
inline void pack_map( Stream& s, const Map<K, V, U...>& value ) {
|
||||
FC_ASSERT( value.size() <= MAX_NUM_ARRAY_ELEMENTS );
|
||||
pack( s, unsigned_int((uint32_t)value.size()) );
|
||||
for( const auto& item : value ) {
|
||||
pack( s, item );
|
||||
}
|
||||
}
|
||||
|
||||
template<template<typename...> class Map, typename Stream, typename K, typename V, typename... U>
|
||||
inline void unpack_map( Stream& s, Map<K, V, U...>& value ) {
|
||||
unsigned_int size; unpack( s, size );
|
||||
FC_ASSERT( size.value <= MAX_NUM_ARRAY_ELEMENTS );
|
||||
value.clear();
|
||||
for( uint32_t i = 0; i < size.value; ++i ) {
|
||||
auto tmp = ::fc::detail::default_construct_pair_maybe_with_allocator<K, V>( value.get_allocator() );
|
||||
unpack( s, tmp );
|
||||
value.insert( value.end(), std::move(tmp) );
|
||||
}
|
||||
}
|
||||
|
||||
template<template<typename...> class Map, typename Stream, typename K, typename V, typename... U>
|
||||
inline void unpack_flat_map( Stream& s, Map<K, V, U...>& value ) {
|
||||
unsigned_int size; unpack( s, size );
|
||||
FC_ASSERT( size.value <= MAX_NUM_ARRAY_ELEMENTS );
|
||||
value.clear();
|
||||
value.reserve( size.value );
|
||||
for( uint32_t i = 0; i < size.value; ++i ) {
|
||||
auto tmp = ::fc::detail::default_construct_pair_maybe_with_allocator<K, V>( value.get_allocator() );
|
||||
unpack( s, tmp );
|
||||
value.insert( value.end(), std::move(tmp) );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<template<typename...> class Set, typename T, typename... U>
|
||||
void to_variant_from_set( const Set<T, U...>& s, fc::variant& vo ) {
|
||||
FC_ASSERT( s.size() <= MAX_NUM_ARRAY_ELEMENTS );
|
||||
variants vars;
|
||||
vars.reserve( s.size() );
|
||||
for( const auto& item : s ) {
|
||||
vars.emplace_back( item );
|
||||
}
|
||||
vo = std::move( vars );
|
||||
}
|
||||
|
||||
template<template<typename...> class Set, typename T, typename... U>
|
||||
void from_variant_to_set( const fc::variant& v, Set< T, U... >& s ) {
|
||||
const variants& vars = v.get_array();
|
||||
FC_ASSERT( vars.size() <= MAX_NUM_ARRAY_ELEMENTS );
|
||||
s.clear();
|
||||
for( const auto& var : vars ) {
|
||||
auto item = construct_maybe_with_allocator<T>( s.get_allocator() );
|
||||
var.as<T>( item );
|
||||
s.insert( s.end(), std::move(item) );
|
||||
}
|
||||
}
|
||||
|
||||
template<template<typename...> class Set, typename T, typename... U>
|
||||
void from_variant_to_flat_set( const fc::variant& v, Set< T, U... >& s ) {
|
||||
const variants& vars = v.get_array();
|
||||
FC_ASSERT( vars.size() <= MAX_NUM_ARRAY_ELEMENTS );
|
||||
s.clear();
|
||||
s.reserve( vars.size() );
|
||||
for( const auto& var : vars ) {
|
||||
auto item = construct_maybe_with_allocator<T>( s.get_allocator() );
|
||||
var.as<T>( item );
|
||||
s.insert( s.end(), std::move(item) );
|
||||
}
|
||||
}
|
||||
|
||||
template<template<typename...> class Map, typename K, typename V, typename... U >
|
||||
void to_variant_from_map( const Map< K, V, U... >& m, fc::variant& vo ) {
|
||||
FC_ASSERT( m.size() <= MAX_NUM_ARRAY_ELEMENTS );
|
||||
variants vars;
|
||||
vars.reserve( m.size() );
|
||||
for( const auto& item : m ) {
|
||||
vars.emplace_back( item );
|
||||
}
|
||||
vo = std::move( vars );
|
||||
}
|
||||
|
||||
template<template<typename...> class Map, typename K, typename V, typename... U>
|
||||
void from_variant_to_map( const variant& v, Map<K, V, U...>& m ) {
|
||||
const variants& vars = v.get_array();
|
||||
FC_ASSERT( vars.size() <= MAX_NUM_ARRAY_ELEMENTS );
|
||||
m.clear();
|
||||
for( const auto& var : vars ) {
|
||||
auto item = default_construct_pair_maybe_with_allocator<K, V>( m.get_allocator() );
|
||||
var.as< std::pair<K,V> >( item );
|
||||
m.insert( m.end(), std::move(item) );
|
||||
}
|
||||
}
|
||||
|
||||
template<template<typename...> class Map, typename K, typename V, typename... U>
|
||||
void from_variant_to_flat_map( const variant& v, Map<K, V, U...>& m ) {
|
||||
const variants& vars = v.get_array();
|
||||
FC_ASSERT( vars.size() <= MAX_NUM_ARRAY_ELEMENTS );
|
||||
m.clear();
|
||||
m.reserve( vars.size() );
|
||||
for( const auto& var : vars ) {
|
||||
auto item = default_construct_pair_maybe_with_allocator<K, V>( m.get_allocator() );
|
||||
var.as< std::pair<K,V> >( item );
|
||||
m.insert( m.end(), std::move(item) );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include <deque>
|
||||
#include <fc/io/raw.hpp>
|
||||
|
||||
namespace fc {
|
||||
namespace raw {
|
||||
|
||||
|
||||
} // namespace raw
|
||||
|
||||
} // namespace fc
|
||||
@@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include <deque>
|
||||
|
||||
namespace fc {
|
||||
|
||||
namespace raw {
|
||||
template<typename Stream, typename T>
|
||||
void pack( Stream& s, const std::deque<T>& value );
|
||||
template<typename Stream, typename T>
|
||||
void unpack( Stream& s, std::deque<T>& value );
|
||||
}
|
||||
} // namespace fc
|
||||
@@ -0,0 +1,186 @@
|
||||
#pragma once
|
||||
|
||||
#include <fc/container/flat_fwd.hpp>
|
||||
#include <fc/container/container_detail.hpp>
|
||||
#include <boost/container/flat_map.hpp>
|
||||
#include <boost/container/flat_set.hpp>
|
||||
#include <fc/crypto/hex.hpp>
|
||||
|
||||
namespace fc {
|
||||
|
||||
namespace raw {
|
||||
|
||||
template<typename Stream, typename T, typename A>
|
||||
void pack( Stream& s, const boost::container::vector<T, A>& value ) {
|
||||
FC_ASSERT( value.size() <= MAX_NUM_ARRAY_ELEMENTS );
|
||||
pack( s, unsigned_int((uint32_t)value.size()) );
|
||||
if( !std::is_fundamental<T>::value ) {
|
||||
for( const auto& item : value ) {
|
||||
pack( s, item );
|
||||
}
|
||||
} else if( value.size() ) {
|
||||
s.write( (const char*)value.data(), value.size() );
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Stream, typename T, typename A>
|
||||
void unpack( Stream& s, boost::container::vector<T, A>& value ) {
|
||||
unsigned_int size;
|
||||
unpack( s, size );
|
||||
FC_ASSERT( size.value <= MAX_NUM_ARRAY_ELEMENTS );
|
||||
value.clear();
|
||||
value.resize( size.value );
|
||||
if( !std::is_fundamental<T>::value ) {
|
||||
for( auto& item : value ) {
|
||||
unpack( s, item );
|
||||
}
|
||||
} else if( value.size() ) {
|
||||
s.read( (char*)value.data(), value.size() );
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Stream, typename A>
|
||||
void pack( Stream& s, const boost::container::vector<char, A>& value ) {
|
||||
FC_ASSERT( value.size() <= MAX_SIZE_OF_BYTE_ARRAYS );
|
||||
pack( s, unsigned_int((uint32_t)value.size()) );
|
||||
if( value.size() )
|
||||
s.write( (const char*)value.data(), value.size() );
|
||||
}
|
||||
|
||||
template<typename Stream, typename A>
|
||||
void unpack( Stream& s, boost::container::vector<char, A>& value ) {
|
||||
unsigned_int size;
|
||||
unpack( s, size );
|
||||
FC_ASSERT( size.value <= MAX_SIZE_OF_BYTE_ARRAYS );
|
||||
value.clear();
|
||||
value.resize( size.value );
|
||||
if( value.size() )
|
||||
s.read( (char*)value.data(), value.size() );
|
||||
}
|
||||
|
||||
template<typename Stream, typename T, typename... U>
|
||||
void pack( Stream& s, const flat_set<T, U...>& value ) {
|
||||
detail::pack_set( s, value );
|
||||
}
|
||||
|
||||
template<typename Stream, typename T, typename... U>
|
||||
void unpack( Stream& s, flat_set<T, U...>& value ) {
|
||||
detail::unpack_flat_set( s, value );
|
||||
}
|
||||
|
||||
template<typename Stream, typename T, typename... U>
|
||||
void pack( Stream& s, const flat_multiset<T, U...>& value ) {
|
||||
detail::pack_set( s, value );
|
||||
}
|
||||
|
||||
template<typename Stream, typename T, typename... U>
|
||||
void unpack( Stream& s, flat_multiset<T, U...>& value ) {
|
||||
detail::unpack_flat_set( s, value );
|
||||
}
|
||||
|
||||
template<typename Stream, typename K, typename V, typename... U>
|
||||
void pack( Stream& s, const flat_map<K, V, U...>& value ) {
|
||||
detail::pack_map( s, value );
|
||||
}
|
||||
|
||||
template<typename Stream, typename K, typename V, typename... U>
|
||||
void unpack( Stream& s, flat_map<K, V, U...>& value ) {
|
||||
detail::unpack_flat_map( s, value );
|
||||
}
|
||||
|
||||
template<typename Stream, typename K, typename V, typename... U>
|
||||
void pack( Stream& s, const flat_multimap<K, V, U...>& value ) {
|
||||
detail::pack_map( s, value );
|
||||
}
|
||||
|
||||
template<typename Stream, typename K, typename V, typename... U>
|
||||
void unpack( Stream& s, flat_multimap<K, V, U...>& value ) {
|
||||
detail::unpack_flat_map( s, value );
|
||||
}
|
||||
|
||||
} // namespace raw
|
||||
|
||||
template<typename T, typename... U>
|
||||
void to_variant( const boost::container::vector<T, U...>& vec, fc::variant& vo ) {
|
||||
FC_ASSERT( vec.size() <= MAX_NUM_ARRAY_ELEMENTS );
|
||||
variants vars;
|
||||
vars.reserve( vec.size() );
|
||||
for( const auto& item : vec ) {
|
||||
vars.emplace_back( item );
|
||||
}
|
||||
vo = std::move(vars);
|
||||
}
|
||||
|
||||
template<typename T, typename... U>
|
||||
void from_variant( const fc::variant& v, boost::container::vector<T, U...>& vec ) {
|
||||
const variants& vars = v.get_array();
|
||||
FC_ASSERT( vars.size() <= MAX_NUM_ARRAY_ELEMENTS );
|
||||
vec.clear();
|
||||
vec.resize( vars.size() );
|
||||
for( uint32_t i = 0; i < vars.size(); ++i ) {
|
||||
from_variant( vars[i], vec[i] );
|
||||
}
|
||||
}
|
||||
|
||||
template<typename... U>
|
||||
void to_variant( const boost::container::vector<char, U...>& vec, fc::variant& vo ) {
|
||||
FC_ASSERT( vec.size() <= MAX_SIZE_OF_BYTE_ARRAYS );
|
||||
if( vec.size() )
|
||||
vo = variant( fc::to_hex( vec.data(), vec.size() ) );
|
||||
else
|
||||
vo = "";
|
||||
}
|
||||
|
||||
template<typename... U>
|
||||
void from_variant( const fc::variant& v, boost::container::vector<char, U...>& vec )
|
||||
{
|
||||
const auto& str = v.get_string();
|
||||
FC_ASSERT( str.size() <= 2*MAX_SIZE_OF_BYTE_ARRAYS ); // Doubled because hex strings needs two characters per byte
|
||||
vec.resize( str.size() / 2 );
|
||||
if( vec.size() ) {
|
||||
size_t r = fc::from_hex( str, vec.data(), vec.size() );
|
||||
FC_ASSERT( r == vec.size() );
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T, typename... U>
|
||||
void to_variant( const flat_set< T, U... >& s, fc::variant& vo ) {
|
||||
detail::to_variant_from_set( s, vo );
|
||||
}
|
||||
|
||||
template<typename T, typename... U>
|
||||
void from_variant( const fc::variant& v, flat_set< T, U... >& s ) {
|
||||
detail::from_variant_to_flat_set( v, s );
|
||||
}
|
||||
|
||||
template<typename T, typename... U>
|
||||
void to_variant( const flat_multiset< T, U... >& s, fc::variant& vo ) {
|
||||
detail::to_variant_from_set( s, vo );
|
||||
}
|
||||
|
||||
template<typename T, typename... U>
|
||||
void from_variant( const fc::variant& v, flat_multiset< T, U... >& s ) {
|
||||
detail::from_variant_to_flat_set( v, s );
|
||||
}
|
||||
|
||||
template<typename K, typename V, typename... U >
|
||||
void to_variant( const flat_map< K, V, U... >& m, fc::variant& vo ) {
|
||||
detail::to_variant_from_map( m, vo );
|
||||
}
|
||||
|
||||
template<typename K, typename V, typename... U>
|
||||
void from_variant( const variant& v, flat_map<K, V, U...>& m ) {
|
||||
detail::from_variant_to_flat_map( v, m );
|
||||
}
|
||||
|
||||
template<typename K, typename V, typename... U >
|
||||
void to_variant( const flat_multimap< K, V, U... >& m, fc::variant& vo ) {
|
||||
detail::to_variant_from_map( m, vo );
|
||||
}
|
||||
|
||||
template<typename K, typename V, typename... U>
|
||||
void from_variant( const variant& v, flat_multimap<K, V, U...>& m ) {
|
||||
detail::from_variant_to_flat_map( v, m );
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
#pragma once
|
||||
|
||||
#include <boost/container/flat_map.hpp>
|
||||
#include <boost/container/flat_set.hpp>
|
||||
#include <boost/container/vector.hpp>
|
||||
|
||||
#include <boost/interprocess/containers/vector.hpp> // only added to maintain backwards compatibility with existing consumers of fc (can eventually remove)
|
||||
|
||||
namespace fc {
|
||||
|
||||
using boost::container::flat_set;
|
||||
using boost::container::flat_multiset;
|
||||
using boost::container::flat_map;
|
||||
using boost::container::flat_multimap;
|
||||
|
||||
namespace raw {
|
||||
|
||||
template<typename Stream, typename T, typename... U>
|
||||
void pack( Stream& s, const boost::container::vector<T, U...>& value );
|
||||
template<typename Stream, typename T, typename... U>
|
||||
void unpack( Stream& s, boost::container::vector<T, U...>& value );
|
||||
|
||||
template<typename Stream, typename T, typename... U>
|
||||
void pack( Stream& s, const flat_set<T, U...>& value );
|
||||
template<typename Stream, typename T, typename... U>
|
||||
void unpack( Stream& s, flat_set<T, U...>& value );
|
||||
|
||||
template<typename Stream, typename T, typename... U>
|
||||
void pack( Stream& s, const flat_multiset<T, U...>& value );
|
||||
template<typename Stream, typename T, typename... U>
|
||||
void unpack( Stream& s, flat_multiset<T, U...>& value );
|
||||
|
||||
template<typename Stream, typename K, typename V, typename... U>
|
||||
void pack( Stream& s, const flat_map<K, V, U...>& value );
|
||||
template<typename Stream, typename K, typename V, typename... U>
|
||||
void unpack( Stream& s, flat_map<K, V, U...>& value ) ;
|
||||
|
||||
template<typename Stream, typename K, typename V, typename... U>
|
||||
void pack( Stream& s, const flat_multimap<K, V, U...>& value );
|
||||
template<typename Stream, typename K, typename V, typename... U>
|
||||
void unpack( Stream& s, flat_multimap<K, V, U...>& value ) ;
|
||||
|
||||
} // namespace raw
|
||||
|
||||
} // fc
|
||||
@@ -0,0 +1,124 @@
|
||||
#pragma once
|
||||
#include <fc/exception/exception.hpp>
|
||||
#include <fc/io/cfile.hpp>
|
||||
#include <fc/io/datastream.hpp>
|
||||
#include <fc/io/fstream.hpp>
|
||||
#include <fc/io/raw.hpp>
|
||||
#include <fstream>
|
||||
|
||||
namespace fc {
|
||||
|
||||
/**
|
||||
* Specialize tracked::memory_size() if obj does not provide a memory_size() method that represents memory size.
|
||||
*/
|
||||
namespace tracked {
|
||||
template<typename T>
|
||||
size_t memory_size( const T& obj ) {
|
||||
return obj.memory_size();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @class tracked_storage
|
||||
* @brief tracks the size of storage allocated to its underlying multi_index
|
||||
*
|
||||
* This class wraps a multi_index container and tracks the memory allocated as
|
||||
* the container creates, modifies, and deletes. It also provides read and write
|
||||
* methods for persistence.
|
||||
*
|
||||
* Requires ContainerType::value_type to have a size() method that represents the
|
||||
* memory used for that object or specialized tracked::size() and is required to
|
||||
* be a pack/unpack-able type.
|
||||
*/
|
||||
|
||||
template <typename ContainerType>
|
||||
class tracked_storage {
|
||||
private:
|
||||
size_t _memory_size = 0;
|
||||
ContainerType _index;
|
||||
public:
|
||||
typedef typename ContainerType::template nth_index<0>::type primary_index_type;
|
||||
|
||||
tracked_storage() = default;
|
||||
|
||||
// read in the contents of a persisted tracked_storage and prevent reading in
|
||||
// more stored objects once max_memory is reached.
|
||||
// returns true if entire persisted tracked_storage was read
|
||||
bool read(fc::cfile_datastream& ds, size_t max_memory) {
|
||||
auto container_size = _index.size();
|
||||
fc::raw::unpack(ds, container_size);
|
||||
for (size_t i = 0; i < container_size; ++i) {
|
||||
if (memory_size() >= max_memory) {
|
||||
return false;
|
||||
}
|
||||
typename ContainerType::value_type v;
|
||||
fc::raw::unpack(ds, v);
|
||||
insert(std::move(v));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void write(fc::cfile& dat_content) const {
|
||||
const auto container_size = _index.size();
|
||||
dat_content.write( reinterpret_cast<const char*>(&container_size), sizeof(container_size) );
|
||||
|
||||
for (const auto& item : _index) {
|
||||
auto data = fc::raw::pack(item);
|
||||
dat_content.write(data.data(), data.size());
|
||||
}
|
||||
}
|
||||
|
||||
std::pair<typename primary_index_type::iterator, bool> insert(typename ContainerType::value_type obj) {
|
||||
const auto size = tracked::memory_size(obj);
|
||||
auto result = _index.insert(std::move(obj));
|
||||
if (result.second) {
|
||||
_memory_size += size;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename Key>
|
||||
typename primary_index_type::iterator find(const Key& key) {
|
||||
primary_index_type& primary_idx = _index.template get<0>();
|
||||
return primary_idx.find(key);
|
||||
}
|
||||
|
||||
template<typename Key>
|
||||
typename primary_index_type::const_iterator find(const Key& key) const {
|
||||
const primary_index_type& primary_idx = _index.template get<0>();
|
||||
return primary_idx.find(key);
|
||||
}
|
||||
|
||||
template<typename Lam>
|
||||
void modify(typename primary_index_type::iterator itr, Lam lam) {
|
||||
_memory_size -= tracked::memory_size(*itr);
|
||||
if (_index.modify( itr, std::move(lam))) {
|
||||
_memory_size += tracked::memory_size(*itr);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Key>
|
||||
void erase(const Key& key) {
|
||||
auto itr = _index.find(key);
|
||||
if (itr == _index.end())
|
||||
return;
|
||||
|
||||
_memory_size -= tracked::memory_size(*itr);
|
||||
_index.erase(itr);
|
||||
}
|
||||
|
||||
void erase(typename primary_index_type::iterator itr) {
|
||||
_memory_size -= tracked::memory_size(*itr);
|
||||
_index.erase(itr);
|
||||
}
|
||||
|
||||
size_t memory_size() const {
|
||||
return _memory_size;
|
||||
}
|
||||
|
||||
const ContainerType& index() const {
|
||||
return _index;
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
#pragma once
|
||||
#include <fc/crypto/sha512.hpp>
|
||||
#include <fc/crypto/sha256.hpp>
|
||||
#include <fc/uint128.hpp>
|
||||
#include <fc/fwd.hpp>
|
||||
#include <vector>
|
||||
|
||||
namespace fc {
|
||||
class path;
|
||||
|
||||
class aes_encoder
|
||||
{
|
||||
public:
|
||||
void init( const fc::sha256& key, const fc::uint128& init_value );
|
||||
uint32_t encode( const char* plaintxt, uint32_t len, char* ciphertxt );
|
||||
// uint32_t final_encode( char* ciphertxt );
|
||||
|
||||
private:
|
||||
struct impl;
|
||||
fc::fwd<impl,96> my;
|
||||
};
|
||||
class aes_decoder
|
||||
{
|
||||
public:
|
||||
void init( const fc::sha256& key, const fc::uint128& init_value );
|
||||
uint32_t decode( const char* ciphertxt, uint32_t len, char* plaintext );
|
||||
// uint32_t final_decode( char* plaintext );
|
||||
|
||||
private:
|
||||
struct impl;
|
||||
fc::fwd<impl,96> my;
|
||||
};
|
||||
|
||||
unsigned aes_encrypt(unsigned char *plaintext, int plaintext_len, unsigned char *key,
|
||||
unsigned char *iv, unsigned char *ciphertext);
|
||||
unsigned aes_decrypt(unsigned char *ciphertext, int ciphertext_len, unsigned char *key,
|
||||
unsigned char *iv, unsigned char *plaintext);
|
||||
unsigned aes_cfb_decrypt(unsigned char *ciphertext, int ciphertext_len, unsigned char *key,
|
||||
unsigned char *iv, unsigned char *plaintext);
|
||||
|
||||
std::vector<char> aes_encrypt( const fc::sha512& key, const std::vector<char>& plain_text );
|
||||
std::vector<char> aes_decrypt( const fc::sha512& key, const std::vector<char>& cipher_text );
|
||||
|
||||
/** encrypts plain_text and then includes a checksum that enables us to verify the integrety of
|
||||
* the file / key prior to decryption.
|
||||
*/
|
||||
void aes_save( const fc::path& file, const fc::sha512& key, std::vector<char> plain_text );
|
||||
|
||||
/**
|
||||
* recovers the plain_text saved via aes_save()
|
||||
*/
|
||||
std::vector<char> aes_load( const fc::path& file, const fc::sha512& key );
|
||||
|
||||
} // namespace fc
|
||||
@@ -0,0 +1,25 @@
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <cstdint>
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
#include <fc/utility.hpp>
|
||||
|
||||
namespace fc {
|
||||
using bytes = std::vector<char>;
|
||||
|
||||
enum class alt_bn128_error : int32_t {
|
||||
operand_component_invalid,
|
||||
operand_not_in_curve,
|
||||
pairing_list_size_error,
|
||||
operand_outside_g2,
|
||||
input_len_error,
|
||||
invalid_scalar_size
|
||||
};
|
||||
|
||||
std::variant<alt_bn128_error, bytes> alt_bn128_add(const bytes& op1, const bytes& op2);
|
||||
std::variant<alt_bn128_error, bytes> alt_bn128_mul(const bytes& g1_point, const bytes& scalar);
|
||||
std::variant<alt_bn128_error, bool> alt_bn128_pair(const bytes& g1_g2_pairs, const yield_function_t& yield);
|
||||
|
||||
} // fc
|
||||
@@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
#include <fc/vector.hpp>
|
||||
#include <fc/string.hpp>
|
||||
|
||||
namespace fc
|
||||
{
|
||||
std::vector<char> from_base32( const fc::string& b32 );
|
||||
fc::string to_base32( const std::vector<char>& vec );
|
||||
fc::string to_base32( const char* data, size_t len );
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
#include <fc/vector.hpp>
|
||||
#include <fc/string.hpp>
|
||||
|
||||
namespace fc
|
||||
{
|
||||
std::vector<char> from_base36( const fc::string& b36 );
|
||||
fc::string to_base36( const std::vector<char>& vec );
|
||||
fc::string to_base36( const char* data, size_t len );
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
#include <fc/string.hpp>
|
||||
#include <fc/time.hpp>
|
||||
#include <vector>
|
||||
|
||||
namespace fc {
|
||||
std::string to_base58( const char* d, size_t s, const fc::yield_function_t& yield );
|
||||
std::string to_base58( const std::vector<char>& data, const fc::yield_function_t& yield );
|
||||
std::vector<char> from_base58( const std::string& base58_str );
|
||||
size_t from_base58( const std::string& base58_str, char* out_data, size_t out_data_len );
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
#include <string>
|
||||
|
||||
namespace fc {
|
||||
std::string base64_encode(unsigned char const* bytes_to_encode, unsigned int in_len);
|
||||
inline std::string base64_encode(char const* bytes_to_encode, unsigned int in_len) { return base64_encode( (unsigned char const*)bytes_to_encode, in_len); }
|
||||
std::string base64_encode( const std::string& enc );
|
||||
std::string base64_decode( const std::string& encoded_string);
|
||||
|
||||
std::string base64url_encode(unsigned char const* bytes_to_encode, unsigned int in_len);
|
||||
inline std::string base64url_encode(char const* bytes_to_encode, unsigned int in_len) { return base64url_encode( (unsigned char const*)bytes_to_encode, in_len); }
|
||||
std::string base64url_encode( const std::string& enc );
|
||||
std::string base64url_decode( const std::string& encoded_string);
|
||||
} // namespace fc
|
||||
@@ -0,0 +1,76 @@
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
#include <fc/string.hpp>
|
||||
#include <fc/vector.hpp>
|
||||
|
||||
struct bignum_st;
|
||||
typedef bignum_st BIGNUM;
|
||||
|
||||
namespace fc {
|
||||
class bigint {
|
||||
public:
|
||||
bigint( const std::vector<char>& bige );
|
||||
bigint( const char* bige, uint32_t l );
|
||||
bigint(uint64_t value);
|
||||
bigint( );
|
||||
bigint( const bigint& c );
|
||||
bigint( bigint&& c );
|
||||
explicit bigint( BIGNUM* n );
|
||||
~bigint();
|
||||
|
||||
bigint& operator = ( const bigint& a );
|
||||
bigint& operator = ( bigint&& a );
|
||||
|
||||
explicit operator bool()const;
|
||||
|
||||
bool is_negative()const;
|
||||
int64_t to_int64()const;
|
||||
|
||||
int64_t log2()const;
|
||||
bigint exp( const bigint& c )const;
|
||||
|
||||
static bigint random( uint32_t bits, int t, int );
|
||||
|
||||
bool operator < ( const bigint& c )const;
|
||||
bool operator > ( const bigint& c )const;
|
||||
bool operator >= ( const bigint& c )const;
|
||||
bool operator == ( const bigint& c )const;
|
||||
bool operator != ( const bigint& c )const;
|
||||
|
||||
bigint operator + ( const bigint& a )const;
|
||||
bigint operator * ( const bigint& a )const;
|
||||
bigint operator / ( const bigint& a )const;
|
||||
bigint operator % ( const bigint& a )const;
|
||||
bigint operator /= ( const bigint& a );
|
||||
bigint operator *= ( const bigint& a );
|
||||
bigint& operator += ( const bigint& a );
|
||||
bigint& operator -= ( const bigint& a );
|
||||
bigint& operator <<= ( uint32_t i );
|
||||
bigint& operator >>= ( uint32_t i );
|
||||
bigint operator - ( const bigint& a )const;
|
||||
|
||||
|
||||
bigint operator++(int);
|
||||
bigint& operator++();
|
||||
bigint operator--(int);
|
||||
bigint& operator--();
|
||||
|
||||
operator fc::string()const;
|
||||
|
||||
// returns bignum as bigendian bytes
|
||||
operator std::vector<char>()const;
|
||||
|
||||
BIGNUM* dup()const;
|
||||
|
||||
BIGNUM* get()const { return n; }
|
||||
private:
|
||||
BIGNUM* n;
|
||||
};
|
||||
|
||||
class variant;
|
||||
/** encodes the big int as base64 string, or a number */
|
||||
void to_variant( const bigint& bi, variant& v );
|
||||
/** decodes the big int as base64 string, or a number */
|
||||
void from_variant( const variant& v, bigint& bi );
|
||||
} // namespace fc
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
// Snark - Wrapper for alt_bn128 add mul pair and modexp
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <cstdint>
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
#include <fc/utility.hpp>
|
||||
|
||||
namespace fc {
|
||||
using bytes = std::vector<char>;
|
||||
|
||||
enum class blake2b_error : int32_t {
|
||||
input_len_error
|
||||
};
|
||||
|
||||
std::variant<blake2b_error, bytes> blake2b(uint32_t _rounds, const bytes& _h, const bytes& _m, const bytes& _t0_offset, const bytes& _t1_offset, bool _f, const yield_function_t& yield);
|
||||
|
||||
struct blake2b_state {
|
||||
uint64_t h[8] = {0,0,0,0,0,0,0,0};
|
||||
uint64_t t[2] = {0,0};
|
||||
uint64_t f[1] = {0};
|
||||
};
|
||||
|
||||
class blake2b_wrapper {
|
||||
public:
|
||||
enum blake2b_constant { BLAKE2B_BLOCKBYTES = 128 };
|
||||
void blake2b_compress(blake2b_state *S, const uint8_t block[BLAKE2B_BLOCKBYTES], size_t r, const yield_function_t& yield );
|
||||
|
||||
private:
|
||||
uint64_t m[16];
|
||||
uint64_t v[16];
|
||||
size_t i;
|
||||
|
||||
inline void G(uint8_t r, uint8_t i, uint64_t& a, uint64_t& b, uint64_t& c, uint64_t& d) noexcept;
|
||||
inline void ROUND(uint8_t r) noexcept;
|
||||
|
||||
void blake2b_compress_init(blake2b_state *S, const uint8_t block[BLAKE2B_BLOCKBYTES], size_t r);
|
||||
void blake2b_compress_end(blake2b_state *S);
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,178 @@
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
///
|
||||
// Blowfish.h Header File
|
||||
//
|
||||
// BLOWFISH ENCRYPTION ALGORITHM
|
||||
//
|
||||
// encryption and decryption of Byte Strings using the Blowfish encryption Algorithm.
|
||||
// Blowfish is a block cipher that encrypts data in 8-byte blocks. The algorithm consists
|
||||
// of two parts: a key-expansion part and a data-ancryption part. Key expansion converts a
|
||||
// variable key of at least 1 and at most 56 bytes into several subkey arrays totaling
|
||||
// 4168 bytes. Blowfish has 16 rounds. Each round consists of a key-dependent permutation,
|
||||
// and a key and data-dependent substitution. All operations are XORs and additions on 32-bit words.
|
||||
// The only additional operations are four indexed array data lookups per round.
|
||||
// Blowfish uses a large number of subkeys. These keys must be precomputed before any data
|
||||
// encryption or decryption. The P-array consists of 18 32-bit subkeys: P0, P1,...,P17.
|
||||
// There are also four 32-bit S-boxes with 256 entries each: S0,0, S0,1,...,S0,255;
|
||||
// S1,0, S1,1,...,S1,255; S2,0, S2,1,...,S2,255; S3,0, S3,1,...,S3,255;
|
||||
//
|
||||
// The Electronic Code Book (ECB), Cipher Block Chaining (CBC) and Cipher Feedback modes
|
||||
// are used:
|
||||
//
|
||||
// In ECB mode if the same block is encrypted twice with the same key, the resulting
|
||||
// ciphertext blocks are the same.
|
||||
//
|
||||
// In CBC Mode a ciphertext block is obtained by first xoring the
|
||||
// plaintext block with the previous ciphertext block, and encrypting the resulting value.
|
||||
//
|
||||
// In CFB mode a ciphertext block is obtained by encrypting the previous ciphertext block
|
||||
// and xoring the resulting value with the plaintext
|
||||
//
|
||||
// The previous ciphertext block is usually stored in an Initialization Vector (IV).
|
||||
// An Initialization Vector of zero is commonly used for the first block, though other
|
||||
// arrangements are also in use.
|
||||
|
||||
/*
|
||||
http://www.counterpane.com/vectors.txt
|
||||
Test vectors by Eric Young. These tests all assume Blowfish with 16
|
||||
rounds.
|
||||
|
||||
All data is shown as a hex string with 012345 loading as
|
||||
data[0]=0x01;
|
||||
data[1]=0x23;
|
||||
data[2]=0x45;
|
||||
ecb test data (taken from the DES validation tests)
|
||||
|
||||
key bytes clear bytes cipher bytes
|
||||
0000000000000000 0000000000000000 4EF997456198DD78
|
||||
FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF 51866FD5B85ECB8A
|
||||
3000000000000000 1000000000000001 7D856F9A613063F2 ???
|
||||
1111111111111111 1111111111111111 2466DD878B963C9D
|
||||
0123456789ABCDEF 1111111111111111 61F9C3802281B096
|
||||
1111111111111111 0123456789ABCDEF 7D0CC630AFDA1EC7
|
||||
0000000000000000 0000000000000000 4EF997456198DD78
|
||||
FEDCBA9876543210 0123456789ABCDEF 0ACEAB0FC6A0A28D
|
||||
7CA110454A1A6E57 01A1D6D039776742 59C68245EB05282B
|
||||
0131D9619DC1376E 5CD54CA83DEF57DA B1B8CC0B250F09A0
|
||||
07A1133E4A0B2686 0248D43806F67172 1730E5778BEA1DA4
|
||||
3849674C2602319E 51454B582DDF440A A25E7856CF2651EB
|
||||
04B915BA43FEB5B6 42FD443059577FA2 353882B109CE8F1A
|
||||
0113B970FD34F2CE 059B5E0851CF143A 48F4D0884C379918
|
||||
0170F175468FB5E6 0756D8E0774761D2 432193B78951FC98
|
||||
43297FAD38E373FE 762514B829BF486A 13F04154D69D1AE5
|
||||
07A7137045DA2A16 3BDD119049372802 2EEDDA93FFD39C79
|
||||
04689104C2FD3B2F 26955F6835AF609A D887E0393C2DA6E3
|
||||
37D06BB516CB7546 164D5E404F275232 5F99D04F5B163969
|
||||
1F08260D1AC2465E 6B056E18759F5CCA 4A057A3B24D3977B
|
||||
584023641ABA6176 004BD6EF09176062 452031C1E4FADA8E
|
||||
025816164629B007 480D39006EE762F2 7555AE39F59B87BD
|
||||
49793EBC79B3258F 437540C8698F3CFA 53C55F9CB49FC019
|
||||
4FB05E1515AB73A7 072D43A077075292 7A8E7BFA937E89A3
|
||||
49E95D6D4CA229BF 02FE55778117F12A CF9C5D7A4986ADB5
|
||||
018310DC409B26D6 1D9D5C5018F728C2 D1ABB290658BC778
|
||||
1C587F1C13924FEF 305532286D6F295A 55CB3774D13EF201
|
||||
0101010101010101 0123456789ABCDEF FA34EC4847B268B2
|
||||
1F1F1F1F0E0E0E0E 0123456789ABCDEF A790795108EA3CAE
|
||||
E0FEE0FEF1FEF1FE 0123456789ABCDEF C39E072D9FAC631D
|
||||
0000000000000000 FFFFFFFFFFFFFFFF 014933E0CDAFF6E4
|
||||
FFFFFFFFFFFFFFFF 0000000000000000 F21E9A77B71C49BC
|
||||
0123456789ABCDEF 0000000000000000 245946885754369A
|
||||
FEDCBA9876543210 FFFFFFFFFFFFFFFF 6B5C5A9C5D9E0A5A
|
||||
|
||||
set_key test data
|
||||
data[8]= FEDCBA9876543210
|
||||
c=F9AD597C49DB005E k[ 1]=F0
|
||||
c=E91D21C1D961A6D6 k[ 2]=F0E1
|
||||
c=E9C2B70A1BC65CF3 k[ 3]=F0E1D2
|
||||
c=BE1E639408640F05 k[ 4]=F0E1D2C3
|
||||
c=B39E44481BDB1E6E k[ 5]=F0E1D2C3B4
|
||||
c=9457AA83B1928C0D k[ 6]=F0E1D2C3B4A5
|
||||
c=8BB77032F960629D k[ 7]=F0E1D2C3B4A596
|
||||
c=E87A244E2CC85E82 k[ 8]=F0E1D2C3B4A59687
|
||||
c=15750E7A4F4EC577 k[ 9]=F0E1D2C3B4A5968778
|
||||
c=122BA70B3AB64AE0 k[10]=F0E1D2C3B4A596877869
|
||||
c=3A833C9AFFC537F6 k[11]=F0E1D2C3B4A5968778695A
|
||||
c=9409DA87A90F6BF2 k[12]=F0E1D2C3B4A5968778695A4B
|
||||
c=884F80625060B8B4 k[13]=F0E1D2C3B4A5968778695A4B3C
|
||||
c=1F85031C19E11968 k[14]=F0E1D2C3B4A5968778695A4B3C2D
|
||||
c=79D9373A714CA34F k[15]=F0E1D2C3B4A5968778695A4B3C2D1E ???
|
||||
c=93142887EE3BE15C k[16]=F0E1D2C3B4A5968778695A4B3C2D1E0F
|
||||
c=03429E838CE2D14B k[17]=F0E1D2C3B4A5968778695A4B3C2D1E0F00
|
||||
c=A4299E27469FF67B k[18]=F0E1D2C3B4A5968778695A4B3C2D1E0F0011
|
||||
c=AFD5AED1C1BC96A8 k[19]=F0E1D2C3B4A5968778695A4B3C2D1E0F001122
|
||||
c=10851C0E3858DA9F k[20]=F0E1D2C3B4A5968778695A4B3C2D1E0F00112233
|
||||
c=E6F51ED79B9DB21F k[21]=F0E1D2C3B4A5968778695A4B3C2D1E0F0011223344
|
||||
c=64A6E14AFD36B46F k[22]=F0E1D2C3B4A5968778695A4B3C2D1E0F001122334455
|
||||
c=80C7D7D45A5479AD k[23]=F0E1D2C3B4A5968778695A4B3C2D1E0F00112233445566
|
||||
c=05044B62FA52D080 k[24]=F0E1D2C3B4A5968778695A4B3C2D1E0F0011223344556677
|
||||
|
||||
chaining mode test data
|
||||
key[16] = 0123456789ABCDEFF0E1D2C3B4A59687
|
||||
iv[8] = FEDCBA9876543210
|
||||
data[29] = "7654321 Now is the time for " (includes trailing '\0')
|
||||
data[29] = 37363534333231204E6F77206973207468652074696D6520666F722000
|
||||
cbc cipher text
|
||||
cipher[32]= 6B77B4D63006DEE605B156E27403979358DEB9E7154616D959F1652BD5FF92CC
|
||||
cfb64 cipher text cipher[29]=
|
||||
E73214A2822139CAF26ECF6D2EB9E76E3DA3DE04D1517200519D57A6C3
|
||||
ofb64 cipher text cipher[29]=
|
||||
E73214A2822139CA62B343CC5B65587310DD908D0C241B2263C2CF80DA
|
||||
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
|
||||
namespace fc {
|
||||
|
||||
//Block Structure
|
||||
struct sblock
|
||||
{
|
||||
//Constructors
|
||||
sblock(unsigned int l=0, unsigned int r=0) : m_uil(l), m_uir(r) {}
|
||||
//Copy Constructor
|
||||
sblock(const sblock& roBlock) : m_uil(roBlock.m_uil), m_uir(roBlock.m_uir) {}
|
||||
sblock& operator^=(sblock& b) { m_uil ^= b.m_uil; m_uir ^= b.m_uir; return *this; }
|
||||
unsigned int m_uil, m_uir;
|
||||
};
|
||||
|
||||
class blowfish
|
||||
{
|
||||
public:
|
||||
enum { ECB=0, CBC=1, CFB=2 };
|
||||
|
||||
//Constructor - Initialize the P and S boxes for a given Key
|
||||
blowfish();
|
||||
void start(unsigned char* ucKey, uint64_t n, const sblock& roChain = sblock(0UL,0UL));
|
||||
|
||||
//Resetting the chaining block
|
||||
void reset_chain() { m_oChain = m_oChain0; }
|
||||
|
||||
// encrypt/decrypt Buffer in Place
|
||||
void encrypt(unsigned char* buf, uint64_t n, int iMode=CFB);
|
||||
void decrypt(unsigned char* buf, uint64_t n, int iMode=CFB);
|
||||
|
||||
// encrypt/decrypt from Input Buffer to Output Buffer
|
||||
void encrypt(const unsigned char* in, unsigned char* out, uint64_t n, int iMode=CFB);
|
||||
void decrypt(const unsigned char* in, unsigned char* out, uint64_t n, int iMode=CFB);
|
||||
|
||||
//Private Functions
|
||||
private:
|
||||
unsigned int F(unsigned int ui);
|
||||
void encrypt(sblock&);
|
||||
void decrypt(sblock&);
|
||||
|
||||
private:
|
||||
//The Initialization Vector, by default {0, 0}
|
||||
sblock m_oChain0;
|
||||
sblock m_oChain;
|
||||
unsigned int m_auiP[18];
|
||||
unsigned int m_auiS[4][256];
|
||||
static const unsigned int scm_auiInitP[18];
|
||||
static const unsigned int scm_auiInitS[4][256];
|
||||
};
|
||||
|
||||
|
||||
} // namespace fc
|
||||
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
// Copyright (c) 2011 Google, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
// CityHash, by Geoff Pike and Jyrki Alakuijala
|
||||
//
|
||||
// This file provides a few functions for hashing strings. On x86-64
|
||||
// hardware in 2011, CityHash64() is faster than other high-quality
|
||||
// hash functions, such as Murmur. This is largely due to higher
|
||||
// instruction-level parallelism. CityHash64() and CityHash128() also perform
|
||||
// well on hash-quality tests.
|
||||
//
|
||||
// CityHash128() is optimized for relatively long strings and returns
|
||||
// a 128-bit hash. For strings more than about 2000 bytes it can be
|
||||
// faster than CityHash64().
|
||||
//
|
||||
// Functions in the CityHash family are not suitable for cryptography.
|
||||
//
|
||||
// WARNING: This code has not been tested on big-endian platforms!
|
||||
// It is known to work well on little-endian platforms that have a small penalty
|
||||
// for unaligned reads, such as current Intel and AMD moderate-to-high-end CPUs.
|
||||
//
|
||||
// By the way, for some hash functions, given strings a and b, the hash
|
||||
// of a+b is easily derived from the hashes of a and b. This property
|
||||
// doesn't hold for any hash functions in this file.
|
||||
#pragma once
|
||||
|
||||
#include <stdlib.h> // for size_t.
|
||||
#include <stdint.h>
|
||||
#include <utility>
|
||||
|
||||
namespace fc {
|
||||
|
||||
template<typename T, size_t N>
|
||||
class array;
|
||||
class uint128;
|
||||
|
||||
// Hash function for a byte array.
|
||||
uint64_t city_hash64(const char *buf, size_t len);
|
||||
|
||||
uint32_t city_hash32(const char *buf, size_t len);
|
||||
|
||||
#if SIZE_MAX > UINT32_MAX
|
||||
inline size_t city_hash_size_t(const char *buf, size_t len) { return city_hash64(buf, len); }
|
||||
#else
|
||||
inline size_t city_hash_size_t(const char *buf, size_t len) { return city_hash32(buf, len); }
|
||||
#endif
|
||||
|
||||
// Hash function for a byte array.
|
||||
uint128 city_hash128(const char *s, size_t len);
|
||||
|
||||
// Hash function for a byte array.
|
||||
uint64_t city_hash_crc_64(const char *buf, size_t len);
|
||||
|
||||
// Hash function for a byte array.
|
||||
uint128 city_hash_crc_128(const char *s, size_t len);
|
||||
array<uint64_t,4> city_hash_crc_256(const char *s, size_t len);
|
||||
|
||||
|
||||
} // namespace fc
|
||||
@@ -0,0 +1,198 @@
|
||||
#pragma once
|
||||
#include <fc/crypto/ripemd160.hpp>
|
||||
#include <fc/reflect/reflect.hpp>
|
||||
#include <fc/crypto/base58.hpp>
|
||||
#include <fc/io/raw.hpp>
|
||||
#include <fc/utility.hpp>
|
||||
#include <fc/static_variant.hpp>
|
||||
|
||||
namespace fc { namespace crypto {
|
||||
template<typename DataType>
|
||||
struct checksummed_data {
|
||||
checksummed_data() {}
|
||||
uint32_t check = 0;
|
||||
DataType data;
|
||||
|
||||
static auto calculate_checksum(const DataType& data, const char *prefix = nullptr) {
|
||||
auto encoder = ripemd160::encoder();
|
||||
raw::pack(encoder, data);
|
||||
|
||||
if (prefix != nullptr) {
|
||||
encoder.write(prefix, const_strlen(prefix));
|
||||
}
|
||||
return encoder.result()._hash[0];
|
||||
}
|
||||
};
|
||||
|
||||
inline bool prefix_matches(const char* prefix, const std::string& str) {
|
||||
auto prefix_len = const_strlen(prefix);
|
||||
return str.size() > prefix_len && str.substr(0, prefix_len).compare(prefix) == 0;
|
||||
}
|
||||
|
||||
template<typename, const char * const *, int, typename ...>
|
||||
struct base58_str_parser_impl;
|
||||
|
||||
template<typename Result, const char * const * Prefixes, int Position, typename KeyType, typename ...Rem>
|
||||
struct base58_str_parser_impl<Result, Prefixes, Position, KeyType, Rem...> {
|
||||
static Result apply(const std::string& prefix_str, const std::string& data_str)
|
||||
{
|
||||
using data_type = typename KeyType::data_type;
|
||||
using wrapper = checksummed_data<data_type>;
|
||||
constexpr auto prefix = Prefixes[Position];
|
||||
|
||||
if (prefix == prefix_str) {
|
||||
auto bin = fc::from_base58(data_str);
|
||||
fc::datastream<const char*> unpacker(bin.data(), bin.size());
|
||||
wrapper wrapped;
|
||||
fc::raw::unpack(unpacker, wrapped);
|
||||
FC_ASSERT(!unpacker.remaining(), "decoded base58 length too long");
|
||||
auto checksum = wrapper::calculate_checksum(wrapped.data, prefix);
|
||||
FC_ASSERT(checksum == wrapped.check);
|
||||
return Result(KeyType(wrapped.data));
|
||||
}
|
||||
|
||||
return base58_str_parser_impl<Result, Prefixes, Position + 1, Rem...>::apply(prefix_str, data_str);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Result, const char * const * Prefixes, int Position>
|
||||
struct base58_str_parser_impl<Result, Prefixes, Position> {
|
||||
static Result apply(const std::string& prefix_str, const std::string& data_str ) {
|
||||
FC_ASSERT(false, "No matching suite type for ${prefix}_${data}", ("prefix", prefix_str)("data",data_str));
|
||||
}
|
||||
};
|
||||
|
||||
template<typename, const char * const * Prefixes>
|
||||
struct base58_str_parser;
|
||||
|
||||
/**
|
||||
* Destructure a variant and call the parse_base58str on it
|
||||
* @tparam Ts
|
||||
* @param base58str
|
||||
* @return
|
||||
*/
|
||||
template<const char * const * Prefixes, typename ...Ts>
|
||||
struct base58_str_parser<std::variant<Ts...>, Prefixes> {
|
||||
static std::variant<Ts...> apply(const std::string& base58str) {
|
||||
const auto pivot = base58str.find('_');
|
||||
FC_ASSERT(pivot != std::string::npos, "No delimiter in data, cannot determine suite type: ${str}", ("str", base58str));
|
||||
|
||||
const auto prefix_str = base58str.substr(0, pivot);
|
||||
auto data_str = base58str.substr(pivot + 1);
|
||||
FC_ASSERT(!data_str.empty(), "Data only has suite type prefix: ${str}", ("str", base58str));
|
||||
|
||||
return base58_str_parser_impl<std::variant<Ts...>, Prefixes, 0, Ts...>::apply(prefix_str, data_str);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Storage, const char * const * Prefixes, int DefaultPosition = -1>
|
||||
struct base58str_visitor : public fc::visitor<std::string> {
|
||||
explicit base58str_visitor( const fc::yield_function_t& yield )
|
||||
: _yield(yield) {};
|
||||
template< typename KeyType >
|
||||
std::string operator()( const KeyType& key ) const {
|
||||
using data_type = typename KeyType::data_type;
|
||||
constexpr int position = fc::get_index<Storage, KeyType>();
|
||||
constexpr bool is_default = position == DefaultPosition;
|
||||
|
||||
checksummed_data<data_type> wrapper;
|
||||
wrapper.data = key.serialize();
|
||||
_yield();
|
||||
wrapper.check = checksummed_data<data_type>::calculate_checksum(wrapper.data, !is_default ? Prefixes[position] : nullptr);
|
||||
_yield();
|
||||
auto packed = raw::pack( wrapper );
|
||||
_yield();
|
||||
auto data_str = to_base58( packed.data(), packed.size(), _yield );
|
||||
_yield();
|
||||
if (!is_default) {
|
||||
data_str = string(Prefixes[position]) + "_" + data_str;
|
||||
}
|
||||
_yield();
|
||||
|
||||
return data_str;
|
||||
}
|
||||
const fc::yield_function_t _yield;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct eq_comparator {
|
||||
static bool apply(const T& a, const T& b) {
|
||||
return a.serialize() == b.serialize();
|
||||
}
|
||||
};
|
||||
|
||||
template<typename ... Ts>
|
||||
struct eq_comparator<std::variant<Ts...>> {
|
||||
using variant_type = std::variant<Ts...>;
|
||||
struct visitor : public fc::visitor<bool> {
|
||||
visitor(const variant_type &b)
|
||||
: _b(b) {}
|
||||
|
||||
template<typename KeyType>
|
||||
bool operator()(const KeyType &a) const {
|
||||
const auto &b = std::template get<KeyType>(_b);
|
||||
return eq_comparator<KeyType>::apply(a,b);
|
||||
}
|
||||
|
||||
const variant_type &_b;
|
||||
};
|
||||
|
||||
static bool apply(const variant_type& a, const variant_type& b) {
|
||||
return a.index() == b.index() && std::visit(visitor(b), a);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct less_comparator {
|
||||
static bool apply(const T& a, const T& b) {
|
||||
return a.serialize() < b.serialize();
|
||||
}
|
||||
};
|
||||
|
||||
template<typename ... Ts>
|
||||
struct less_comparator<std::variant<Ts...>> {
|
||||
using variant_type = std::variant<Ts...>;
|
||||
struct visitor : public fc::visitor<bool> {
|
||||
visitor(const variant_type &b)
|
||||
: _b(b) {}
|
||||
|
||||
template<typename KeyType>
|
||||
bool operator()(const KeyType &a) const {
|
||||
const auto &b = std::template get<KeyType>(_b);
|
||||
return less_comparator<KeyType>::apply(a,b);
|
||||
}
|
||||
|
||||
const variant_type &_b;
|
||||
};
|
||||
|
||||
static bool apply(const variant_type& a, const variant_type& b) {
|
||||
return a.index() < b.index() || (a.index() == b.index() && std::visit(visitor(b), a));
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Data>
|
||||
struct shim {
|
||||
using data_type = Data;
|
||||
|
||||
shim()
|
||||
{}
|
||||
|
||||
shim(data_type&& data)
|
||||
:_data(forward<data_type>(data))
|
||||
{}
|
||||
|
||||
shim(const data_type& data)
|
||||
:_data(data)
|
||||
{}
|
||||
|
||||
const data_type& serialize() const {
|
||||
return _data;
|
||||
}
|
||||
|
||||
data_type _data;
|
||||
};
|
||||
|
||||
} }
|
||||
|
||||
FC_REFLECT_TEMPLATE((typename T), fc::crypto::checksummed_data<T>, (data)(check) )
|
||||
FC_REFLECT_TEMPLATE((typename T), fc::crypto::shim<T>, (_data) )
|
||||
@@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
#include <fc/crypto/openssl.hpp>
|
||||
#include <vector>
|
||||
#include <stdint.h>
|
||||
|
||||
namespace fc {
|
||||
|
||||
struct diffie_hellman {
|
||||
diffie_hellman():valid(0),g(5){}
|
||||
bool generate_params( int s, uint8_t g );
|
||||
bool generate_pub_key();
|
||||
bool compute_shared_key( const char* buf, uint32_t s );
|
||||
bool compute_shared_key( const std::vector<char>& pubk);
|
||||
bool validate();
|
||||
|
||||
std::vector<char> p;
|
||||
std::vector<char> pub_key;
|
||||
std::vector<char> priv_key;
|
||||
std::vector<char> shared_key;
|
||||
bool valid;
|
||||
uint8_t g;
|
||||
};
|
||||
|
||||
} // namespace fc
|
||||
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
#include <fc/io/raw.hpp>
|
||||
#include <fc/reflect/reflect.hpp>
|
||||
#include <fc/crypto/sha256.hpp>
|
||||
|
||||
namespace fc {
|
||||
|
||||
template<typename T>
|
||||
fc::sha256 digest( const T& value )
|
||||
{
|
||||
fc::sha256::encoder enc;
|
||||
fc::raw::pack( enc, value );
|
||||
return enc.result();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,239 @@
|
||||
#pragma once
|
||||
#include <fc/crypto/bigint.hpp>
|
||||
#include <fc/crypto/common.hpp>
|
||||
#include <fc/crypto/openssl.hpp>
|
||||
#include <fc/crypto/sha256.hpp>
|
||||
#include <fc/crypto/sha512.hpp>
|
||||
#include <fc/fwd.hpp>
|
||||
#include <fc/array.hpp>
|
||||
#include <fc/io/raw_fwd.hpp>
|
||||
|
||||
namespace fc {
|
||||
|
||||
namespace ecc {
|
||||
namespace detail
|
||||
{
|
||||
class public_key_impl;
|
||||
class private_key_impl;
|
||||
}
|
||||
|
||||
typedef fc::sha256 blind_factor_type;
|
||||
typedef fc::array<char,33> commitment_type;
|
||||
typedef fc::array<char,33> public_key_data;
|
||||
typedef fc::sha256 private_key_secret;
|
||||
typedef fc::array<char,65> public_key_point_data; ///< the full non-compressed version of the ECC point
|
||||
typedef fc::array<char,72> signature;
|
||||
typedef fc::array<unsigned char,65> compact_signature;
|
||||
typedef fc::array<char,78> extended_key_data;
|
||||
typedef fc::sha256 blinded_hash;
|
||||
typedef fc::sha256 blind_signature;
|
||||
|
||||
/**
|
||||
* @class public_key
|
||||
* @brief contains only the public point of an elliptic curve key.
|
||||
*/
|
||||
class public_key
|
||||
{
|
||||
public:
|
||||
public_key();
|
||||
public_key(const public_key& k);
|
||||
~public_key();
|
||||
// bool verify( const fc::sha256& digest, const signature& sig );
|
||||
public_key_data serialize()const;
|
||||
public_key_point_data serialize_ecc_point()const;
|
||||
|
||||
operator public_key_data()const { return serialize(); }
|
||||
|
||||
|
||||
public_key( const public_key_data& v );
|
||||
public_key( const public_key_point_data& v );
|
||||
public_key( const compact_signature& c, const fc::sha256& digest, bool check_canonical = true );
|
||||
|
||||
public_key child( const fc::sha256& offset )const;
|
||||
|
||||
bool valid()const;
|
||||
|
||||
public_key( public_key&& pk );
|
||||
public_key& operator=( public_key&& pk );
|
||||
public_key& operator=( const public_key& pk );
|
||||
|
||||
inline friend bool operator==( const public_key& a, const public_key& b )
|
||||
{
|
||||
return a.serialize() == b.serialize();
|
||||
}
|
||||
inline friend bool operator!=( const public_key& a, const public_key& b )
|
||||
{
|
||||
return a.serialize() != b.serialize();
|
||||
}
|
||||
|
||||
/// Allows to convert current public key object into base58 number.
|
||||
std::string to_base58() const;
|
||||
static std::string to_base58( const public_key_data &key );
|
||||
static public_key from_base58( const std::string& b58 );
|
||||
|
||||
unsigned int fingerprint() const;
|
||||
|
||||
private:
|
||||
friend class private_key;
|
||||
static public_key from_key_data( const public_key_data& v );
|
||||
static bool is_canonical( const compact_signature& c );
|
||||
fc::fwd<detail::public_key_impl,33> my;
|
||||
};
|
||||
|
||||
/**
|
||||
* @class private_key
|
||||
* @brief an elliptic curve private key.
|
||||
*/
|
||||
class private_key
|
||||
{
|
||||
public:
|
||||
private_key();
|
||||
private_key( private_key&& pk );
|
||||
private_key( const private_key& pk );
|
||||
~private_key();
|
||||
|
||||
private_key& operator=( private_key&& pk );
|
||||
private_key& operator=( const private_key& pk );
|
||||
|
||||
static private_key generate();
|
||||
static private_key regenerate( const fc::sha256& secret );
|
||||
|
||||
private_key child( const fc::sha256& offset )const;
|
||||
|
||||
/**
|
||||
* This method of generation enables creating a new private key in a deterministic manner relative to
|
||||
* an initial seed. A public_key created from the seed can be multiplied by the offset to calculate
|
||||
* the new public key without having to know the private key.
|
||||
*/
|
||||
static private_key generate_from_seed( const fc::sha256& seed, const fc::sha256& offset = fc::sha256() );
|
||||
|
||||
private_key_secret get_secret()const; // get the private key secret
|
||||
|
||||
operator private_key_secret ()const { return get_secret(); }
|
||||
|
||||
/**
|
||||
* Given a public key, calculatse a 512 bit shared secret between that
|
||||
* key and this private key.
|
||||
*/
|
||||
fc::sha512 get_shared_secret( const public_key& pub )const;
|
||||
|
||||
// signature sign( const fc::sha256& digest )const;
|
||||
compact_signature sign_compact( const fc::sha256& digest, bool require_canonical = true )const;
|
||||
// bool verify( const fc::sha256& digest, const signature& sig );
|
||||
|
||||
public_key get_public_key()const;
|
||||
|
||||
inline friend bool operator==( const private_key& a, const private_key& b )
|
||||
{
|
||||
return a.get_secret() == b.get_secret();
|
||||
}
|
||||
inline friend bool operator!=( const private_key& a, const private_key& b )
|
||||
{
|
||||
return a.get_secret() != b.get_secret();
|
||||
}
|
||||
inline friend bool operator<( const private_key& a, const private_key& b )
|
||||
{
|
||||
return a.get_secret() < b.get_secret();
|
||||
}
|
||||
|
||||
unsigned int fingerprint() const { return get_public_key().fingerprint(); }
|
||||
|
||||
private:
|
||||
private_key( EC_KEY* k );
|
||||
static fc::sha256 get_secret( const EC_KEY * const k );
|
||||
fc::fwd<detail::private_key_impl,32> my;
|
||||
};
|
||||
|
||||
/**
|
||||
* Shims
|
||||
*/
|
||||
struct public_key_shim : public crypto::shim<public_key_data> {
|
||||
using crypto::shim<public_key_data>::shim;
|
||||
|
||||
bool valid()const {
|
||||
return public_key(_data).valid();
|
||||
}
|
||||
};
|
||||
|
||||
struct signature_shim : public crypto::shim<compact_signature> {
|
||||
using public_key_type = public_key_shim;
|
||||
using crypto::shim<compact_signature>::shim;
|
||||
|
||||
public_key_type recover(const sha256& digest, bool check_canonical) const {
|
||||
return public_key_type(public_key(_data, digest, check_canonical).serialize());
|
||||
}
|
||||
};
|
||||
|
||||
struct private_key_shim : public crypto::shim<private_key_secret> {
|
||||
using crypto::shim<private_key_secret>::shim;
|
||||
using signature_type = signature_shim;
|
||||
using public_key_type = public_key_shim;
|
||||
|
||||
signature_type sign( const sha256& digest, bool require_canonical = true ) const
|
||||
{
|
||||
return signature_type(private_key::regenerate(_data).sign_compact(digest, require_canonical));
|
||||
}
|
||||
|
||||
public_key_type get_public_key( ) const
|
||||
{
|
||||
return public_key_type(private_key::regenerate(_data).get_public_key().serialize());
|
||||
}
|
||||
|
||||
sha512 generate_shared_secret( const public_key_type &pub_key ) const
|
||||
{
|
||||
return private_key::regenerate(_data).get_shared_secret(public_key(pub_key.serialize()));
|
||||
}
|
||||
|
||||
static private_key_shim generate()
|
||||
{
|
||||
return private_key_shim(private_key::generate().get_secret());
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
} // namespace ecc
|
||||
void to_variant( const ecc::private_key& var, variant& vo );
|
||||
void from_variant( const variant& var, ecc::private_key& vo );
|
||||
void to_variant( const ecc::public_key& var, variant& vo );
|
||||
void from_variant( const variant& var, ecc::public_key& vo );
|
||||
|
||||
namespace raw
|
||||
{
|
||||
template<typename Stream>
|
||||
void unpack( Stream& s, fc::ecc::public_key& pk)
|
||||
{
|
||||
ecc::public_key_data ser;
|
||||
fc::raw::unpack(s,ser);
|
||||
pk = fc::ecc::public_key( ser );
|
||||
}
|
||||
|
||||
template<typename Stream>
|
||||
void pack( Stream& s, const fc::ecc::public_key& pk)
|
||||
{
|
||||
fc::raw::pack( s, pk.serialize() );
|
||||
}
|
||||
|
||||
template<typename Stream>
|
||||
void unpack( Stream& s, fc::ecc::private_key& pk)
|
||||
{
|
||||
fc::sha256 sec;
|
||||
unpack( s, sec );
|
||||
pk = ecc::private_key::regenerate(sec);
|
||||
}
|
||||
|
||||
template<typename Stream>
|
||||
void pack( Stream& s, const fc::ecc::private_key& pk)
|
||||
{
|
||||
fc::raw::pack( s, pk.get_secret() );
|
||||
}
|
||||
|
||||
} // namespace raw
|
||||
|
||||
} // namespace fc
|
||||
#include <fc/reflect/reflect.hpp>
|
||||
|
||||
FC_REFLECT_TYPENAME( fc::ecc::private_key )
|
||||
FC_REFLECT_TYPENAME( fc::ecc::public_key )
|
||||
FC_REFLECT_DERIVED( fc::ecc::public_key_shim, (fc::crypto::shim<fc::ecc::public_key_data>), BOOST_PP_SEQ_NIL )
|
||||
FC_REFLECT_DERIVED( fc::ecc::signature_shim, (fc::crypto::shim<fc::ecc::compact_signature>), BOOST_PP_SEQ_NIL )
|
||||
FC_REFLECT_DERIVED( fc::ecc::private_key_shim, (fc::crypto::shim<fc::ecc::private_key_secret>), BOOST_PP_SEQ_NIL )
|
||||
@@ -0,0 +1,228 @@
|
||||
#pragma once
|
||||
#include <fc/crypto/bigint.hpp>
|
||||
#include <fc/crypto/common.hpp>
|
||||
#include <fc/crypto/sha256.hpp>
|
||||
#include <fc/crypto/sha512.hpp>
|
||||
#include <fc/crypto/openssl.hpp>
|
||||
#include <fc/fwd.hpp>
|
||||
#include <fc/array.hpp>
|
||||
#include <fc/io/raw_fwd.hpp>
|
||||
|
||||
namespace fc {
|
||||
|
||||
namespace crypto { namespace r1 {
|
||||
namespace detail
|
||||
{
|
||||
class public_key_impl;
|
||||
class private_key_impl;
|
||||
}
|
||||
|
||||
typedef fc::array<char,33> public_key_data;
|
||||
typedef fc::sha256 private_key_secret;
|
||||
typedef fc::array<char,65> public_key_point_data; ///< the full non-compressed version of the ECC point
|
||||
typedef fc::array<char,72> signature;
|
||||
typedef fc::array<unsigned char,65> compact_signature;
|
||||
|
||||
int ECDSA_SIG_recover_key_GFp(EC_KEY *eckey, ECDSA_SIG *ecsig, const unsigned char *msg, int msglen, int recid, int check);
|
||||
|
||||
/**
|
||||
* @class public_key
|
||||
* @brief contains only the public point of an elliptic curve key.
|
||||
*/
|
||||
class public_key
|
||||
{
|
||||
public:
|
||||
public_key();
|
||||
public_key(const public_key& k);
|
||||
~public_key();
|
||||
bool verify( const fc::sha256& digest, const signature& sig );
|
||||
public_key_data serialize()const;
|
||||
|
||||
operator public_key_data()const { return serialize(); }
|
||||
|
||||
|
||||
public_key( const public_key_data& v );
|
||||
public_key( const public_key_point_data& v );
|
||||
public_key( const compact_signature& c, const fc::sha256& digest, bool check_canonical = true );
|
||||
|
||||
bool valid()const;
|
||||
public_key mult( const fc::sha256& offset );
|
||||
public_key add( const fc::sha256& offset )const;
|
||||
|
||||
public_key( public_key&& pk );
|
||||
public_key& operator=( public_key&& pk );
|
||||
public_key& operator=( const public_key& pk );
|
||||
|
||||
inline friend bool operator==( const public_key& a, const public_key& b )
|
||||
{
|
||||
return a.serialize() == b.serialize();
|
||||
}
|
||||
inline friend bool operator!=( const public_key& a, const public_key& b )
|
||||
{
|
||||
return a.serialize() != b.serialize();
|
||||
}
|
||||
|
||||
/// Allows to convert current public key object into base58 number.
|
||||
std::string to_base58() const;
|
||||
static public_key from_base58( const std::string& b58 );
|
||||
|
||||
private:
|
||||
friend class private_key;
|
||||
friend compact_signature signature_from_ecdsa(const EC_KEY* key, const public_key_data& pub_data, fc::ecdsa_sig& sig, const fc::sha256& d);
|
||||
fc::fwd<detail::public_key_impl,8> my;
|
||||
};
|
||||
|
||||
/**
|
||||
* @class private_key
|
||||
* @brief an elliptic curve private key.
|
||||
*/
|
||||
class private_key
|
||||
{
|
||||
public:
|
||||
private_key();
|
||||
private_key( private_key&& pk );
|
||||
private_key( const private_key& pk );
|
||||
~private_key();
|
||||
|
||||
private_key& operator=( private_key&& pk );
|
||||
private_key& operator=( const private_key& pk );
|
||||
|
||||
static private_key generate();
|
||||
static private_key regenerate( const fc::sha256& secret );
|
||||
|
||||
/**
|
||||
* This method of generation enables creating a new private key in a deterministic manner relative to
|
||||
* an initial seed. A public_key created from the seed can be multiplied by the offset to calculate
|
||||
* the new public key without having to know the private key.
|
||||
*/
|
||||
static private_key generate_from_seed( const fc::sha256& seed, const fc::sha256& offset = fc::sha256() );
|
||||
|
||||
private_key_secret get_secret()const; // get the private key secret
|
||||
|
||||
operator private_key_secret ()const { return get_secret(); }
|
||||
|
||||
/**
|
||||
* Given a public key, calculatse a 512 bit shared secret between that
|
||||
* key and this private key.
|
||||
*/
|
||||
fc::sha512 get_shared_secret( const public_key& pub )const;
|
||||
|
||||
signature sign( const fc::sha256& digest )const;
|
||||
compact_signature sign_compact( const fc::sha256& digest )const;
|
||||
bool verify( const fc::sha256& digest, const signature& sig );
|
||||
|
||||
public_key get_public_key()const;
|
||||
|
||||
inline friend bool operator==( const private_key& a, const private_key& b )
|
||||
{
|
||||
return a.get_secret() == b.get_secret();
|
||||
}
|
||||
inline friend bool operator!=( const private_key& a, const private_key& b )
|
||||
{
|
||||
return a.get_secret() != b.get_secret();
|
||||
}
|
||||
inline friend bool operator<( const private_key& a, const private_key& b )
|
||||
{
|
||||
return a.get_secret() < b.get_secret();
|
||||
}
|
||||
|
||||
private:
|
||||
fc::fwd<detail::private_key_impl,8> my;
|
||||
};
|
||||
|
||||
/**
|
||||
* Shims
|
||||
*/
|
||||
struct public_key_shim : public crypto::shim<public_key_data> {
|
||||
using crypto::shim<public_key_data>::shim;
|
||||
|
||||
bool valid()const {
|
||||
return public_key(_data).valid();
|
||||
}
|
||||
};
|
||||
|
||||
struct signature_shim : public crypto::shim<compact_signature> {
|
||||
using public_key_type = public_key_shim;
|
||||
using crypto::shim<compact_signature>::shim;
|
||||
|
||||
public_key_type recover(const sha256& digest, bool check_canonical) const {
|
||||
return public_key_type(public_key(_data, digest, check_canonical).serialize());
|
||||
}
|
||||
};
|
||||
|
||||
struct private_key_shim : public crypto::shim<private_key_secret> {
|
||||
using crypto::shim<private_key_secret>::shim;
|
||||
using signature_type = signature_shim;
|
||||
using public_key_type = public_key_shim;
|
||||
|
||||
signature_type sign( const sha256& digest, bool require_canonical = true ) const
|
||||
{
|
||||
return signature_type(private_key::regenerate(_data).sign_compact(digest));
|
||||
}
|
||||
|
||||
public_key_type get_public_key( ) const
|
||||
{
|
||||
return public_key_type(private_key::regenerate(_data).get_public_key().serialize());
|
||||
}
|
||||
|
||||
sha512 generate_shared_secret( const public_key_type &pub_key ) const
|
||||
{
|
||||
return private_key::regenerate(_data).get_shared_secret(public_key(pub_key.serialize()));
|
||||
}
|
||||
|
||||
static private_key_shim generate()
|
||||
{
|
||||
return private_key_shim(private_key::generate().get_secret());
|
||||
}
|
||||
};
|
||||
|
||||
//key here is just an optimization for getting the curve's parameters from an already constructed curve
|
||||
compact_signature signature_from_ecdsa(const EC_KEY* key, const public_key_data& pub, fc::ecdsa_sig& sig, const fc::sha256& d);
|
||||
|
||||
} // namespace r1
|
||||
} // namespace crypto
|
||||
void to_variant( const crypto::r1::private_key& var, variant& vo );
|
||||
void from_variant( const variant& var, crypto::r1::private_key& vo );
|
||||
void to_variant( const crypto::r1::public_key& var, variant& vo );
|
||||
void from_variant( const variant& var, crypto::r1::public_key& vo );
|
||||
|
||||
namespace raw
|
||||
{
|
||||
template<typename Stream>
|
||||
void unpack( Stream& s, fc::crypto::r1::public_key& pk)
|
||||
{
|
||||
crypto::r1::public_key_data ser;
|
||||
fc::raw::unpack(s,ser);
|
||||
pk = fc::crypto::r1::public_key( ser );
|
||||
}
|
||||
|
||||
template<typename Stream>
|
||||
void pack( Stream& s, const fc::crypto::r1::public_key& pk)
|
||||
{
|
||||
fc::raw::pack( s, pk.serialize() );
|
||||
}
|
||||
|
||||
template<typename Stream>
|
||||
void unpack( Stream& s, fc::crypto::r1::private_key& pk)
|
||||
{
|
||||
fc::sha256 sec;
|
||||
unpack( s, sec );
|
||||
pk = crypto::r1::private_key::regenerate(sec);
|
||||
}
|
||||
|
||||
template<typename Stream>
|
||||
void pack( Stream& s, const fc::crypto::r1::private_key& pk)
|
||||
{
|
||||
fc::raw::pack( s, pk.get_secret() );
|
||||
}
|
||||
|
||||
} // namespace raw
|
||||
|
||||
} // namespace fc
|
||||
#include <fc/reflect/reflect.hpp>
|
||||
|
||||
FC_REFLECT_TYPENAME( fc::crypto::r1::private_key )
|
||||
FC_REFLECT_TYPENAME( fc::crypto::r1::public_key )
|
||||
FC_REFLECT_DERIVED( fc::crypto::r1::public_key_shim, (fc::crypto::shim<fc::crypto::r1::public_key_data>), BOOST_PP_SEQ_NIL )
|
||||
FC_REFLECT_DERIVED( fc::crypto::r1::signature_shim, (fc::crypto::shim<fc::crypto::r1::compact_signature>), BOOST_PP_SEQ_NIL )
|
||||
FC_REFLECT_DERIVED( fc::crypto::r1::private_key_shim, (fc::crypto::shim<fc::crypto::r1::private_key_secret>), BOOST_PP_SEQ_NIL )
|
||||
@@ -0,0 +1,148 @@
|
||||
#pragma once
|
||||
#include <fc/crypto/bigint.hpp>
|
||||
#include <fc/crypto/common.hpp>
|
||||
#include <fc/crypto/sha256.hpp>
|
||||
#include <fc/crypto/elliptic_r1.hpp>
|
||||
#include <fc/crypto/openssl.hpp>
|
||||
#include <fc/fwd.hpp>
|
||||
#include <fc/array.hpp>
|
||||
#include <fc/io/raw_fwd.hpp>
|
||||
|
||||
namespace fc { namespace crypto { namespace webauthn {
|
||||
|
||||
class signature;
|
||||
|
||||
class public_key {
|
||||
public:
|
||||
using public_key_data_type = fc::array<char, 33>;
|
||||
|
||||
//Used for base58 de/serialization
|
||||
using data_type = public_key;
|
||||
public_key serialize() const { return *this; }
|
||||
|
||||
enum class user_presence_t : uint8_t {
|
||||
USER_PRESENCE_NONE,
|
||||
USER_PRESENCE_PRESENT,
|
||||
USER_PRESENCE_VERIFIED
|
||||
};
|
||||
|
||||
bool valid() const { return rpid.size(); }
|
||||
|
||||
public_key() {}
|
||||
public_key(const public_key_data_type& p, const user_presence_t& t, const std::string& s) :
|
||||
public_key_data(p), user_verification_type(t), rpid(s) {
|
||||
post_init();
|
||||
}
|
||||
public_key(const signature& c, const fc::sha256& digest, bool check_canonical = true);
|
||||
|
||||
bool operator==(const public_key& o) const {
|
||||
return public_key_data == o.public_key_data &&
|
||||
user_verification_type == o.user_verification_type &&
|
||||
rpid == o.rpid;
|
||||
}
|
||||
bool operator<(const public_key& o) const {
|
||||
return std::tie(public_key_data, user_verification_type, rpid) < std::tie(o.public_key_data, o.user_verification_type, o.rpid);
|
||||
}
|
||||
|
||||
template<typename Stream>
|
||||
friend Stream& operator<<(Stream& ds, const public_key& k) {
|
||||
fc::raw::pack(ds, k.public_key_data);
|
||||
fc::raw::pack(ds, static_cast<uint8_t>(k.user_verification_type));
|
||||
fc::raw::pack(ds, k.rpid);
|
||||
return ds;
|
||||
}
|
||||
|
||||
template<typename Stream>
|
||||
friend Stream& operator>>(Stream& ds, public_key& k) {
|
||||
fc::raw::unpack(ds, k.public_key_data);
|
||||
uint8_t t;
|
||||
fc::raw::unpack(ds, t);
|
||||
k.user_verification_type = static_cast<user_presence_t>(t);
|
||||
fc::raw::unpack(ds, k.rpid);
|
||||
k.post_init();
|
||||
return ds;
|
||||
}
|
||||
|
||||
private:
|
||||
public_key_data_type public_key_data;
|
||||
user_presence_t user_verification_type = user_presence_t::USER_PRESENCE_NONE;
|
||||
std::string rpid;
|
||||
|
||||
void post_init();
|
||||
};
|
||||
|
||||
class signature {
|
||||
public:
|
||||
//used for base58 de/serialization
|
||||
using data_type = signature;
|
||||
signature serialize()const { return *this; }
|
||||
|
||||
signature() {}
|
||||
signature(const fc::crypto::r1::compact_signature& s, const std::vector<uint8_t>& a, const std::string& j) :
|
||||
compact_signature(s), auth_data(a), client_json(j) {}
|
||||
|
||||
public_key recover(const sha256& digest, bool check_canonical) const {
|
||||
return public_key(*this, digest, check_canonical);
|
||||
}
|
||||
|
||||
size_t variable_size() const {
|
||||
return auth_data.size() + client_json.size();
|
||||
}
|
||||
|
||||
bool operator==(const signature& o) const {
|
||||
return compact_signature == o.compact_signature &&
|
||||
auth_data == o.auth_data &&
|
||||
client_json == o.client_json;
|
||||
}
|
||||
|
||||
bool operator<(const signature& o) const {
|
||||
return std::tie(compact_signature, auth_data, client_json) < std::tie(o.compact_signature, o.auth_data, o.client_json);
|
||||
}
|
||||
|
||||
//for container usage
|
||||
size_t get_hash() const {
|
||||
return *(size_t*)&compact_signature.data[32-sizeof(size_t)] + *(size_t*)&compact_signature.data[64-sizeof(size_t)];
|
||||
}
|
||||
|
||||
friend struct fc::reflector<signature>;
|
||||
friend class public_key;
|
||||
private:
|
||||
fc::crypto::r1::compact_signature compact_signature;
|
||||
std::vector<uint8_t> auth_data;
|
||||
std::string client_json;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
template<>
|
||||
struct eq_comparator<webauthn::signature> {
|
||||
static bool apply(const webauthn::signature& a, const webauthn::signature& b) {
|
||||
return a == b;
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct less_comparator<webauthn::signature> {
|
||||
static bool apply(const webauthn::signature& a, const webauthn::signature& b) {
|
||||
return a < b;
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct eq_comparator<webauthn::public_key> {
|
||||
static bool apply(const webauthn::public_key& a, const webauthn::public_key& b) {
|
||||
return a == b;
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct less_comparator<webauthn::public_key> {
|
||||
static bool apply(const webauthn::public_key& a, const webauthn::public_key& b) {
|
||||
return a < b;
|
||||
}
|
||||
};
|
||||
|
||||
}}
|
||||
#include <fc/reflect/reflect.hpp>
|
||||
|
||||
FC_REFLECT(fc::crypto::webauthn::signature, (compact_signature)(auth_data)(client_json))
|
||||
@@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
#include <fc/crypto/sha256.hpp>
|
||||
#include <fc/vector.hpp>
|
||||
|
||||
namespace fc { namespace equihash {
|
||||
|
||||
struct proof
|
||||
{
|
||||
uint32_t n;
|
||||
uint32_t k;
|
||||
sha256 seed;
|
||||
std::vector< uint32_t > inputs;
|
||||
|
||||
bool is_valid() const;
|
||||
|
||||
static proof hash( uint32_t n, uint32_t k, sha256 seed );
|
||||
};
|
||||
|
||||
} } // fc
|
||||
|
||||
FC_REFLECT( fc::equihash::proof, (n)(k)(seed)(inputs) )
|
||||
@@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
#include <fc/string.hpp>
|
||||
#include <fc/utility.hpp>
|
||||
#include <vector>
|
||||
|
||||
namespace fc {
|
||||
uint8_t from_hex( char c );
|
||||
fc::string to_hex( const char* d, uint32_t s );
|
||||
std::string to_hex( const std::vector<char>& data );
|
||||
|
||||
/**
|
||||
* @return the number of bytes decoded
|
||||
*/
|
||||
size_t from_hex( const fc::string& hex_str, char* out_data, size_t out_data_len );
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* File: hmac.hpp
|
||||
* Author: Peter Conrad
|
||||
*
|
||||
* Created on 1. Juli 2015, 21:48
|
||||
*/
|
||||
|
||||
#ifndef HMAC_HPP
|
||||
#define HMAC_HPP
|
||||
|
||||
#include <fc/crypto/sha224.hpp>
|
||||
#include <fc/crypto/sha256.hpp>
|
||||
#include <fc/crypto/sha512.hpp>
|
||||
|
||||
namespace fc {
|
||||
|
||||
template<typename H>
|
||||
class hmac
|
||||
{
|
||||
public:
|
||||
hmac() {}
|
||||
|
||||
H digest( const char* c, uint32_t c_len, const char* d, uint32_t d_len )
|
||||
{
|
||||
encoder.reset();
|
||||
add_key(c, c_len, 0x36);
|
||||
encoder.write( d, d_len );
|
||||
H intermediate = encoder.result();
|
||||
|
||||
encoder.reset();
|
||||
add_key(c, c_len, 0x5c);
|
||||
encoder.write( intermediate.data(), intermediate.data_size() );
|
||||
return encoder.result();
|
||||
}
|
||||
|
||||
private:
|
||||
void add_key( const char* c, const uint32_t c_len, char pad )
|
||||
{
|
||||
if ( c_len > internal_block_size() )
|
||||
{
|
||||
H hash = H::hash( c, c_len );
|
||||
add_key( hash.data(), hash.data_size(), pad );
|
||||
}
|
||||
else
|
||||
for (unsigned int i = 0; i < internal_block_size(); i++ )
|
||||
{
|
||||
encoder.put( pad ^ ((i < c_len) ? *c++ : 0) );
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int internal_block_size() const;
|
||||
|
||||
H dummy;
|
||||
typename H::encoder encoder;
|
||||
};
|
||||
|
||||
typedef hmac<fc::sha224> hmac_sha224;
|
||||
typedef hmac<fc::sha256> hmac_sha256;
|
||||
typedef hmac<fc::sha512> hmac_sha512;
|
||||
}
|
||||
|
||||
#endif /* HMAC_HPP */
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user