Compare commits
883 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| efd3086af2 | |||
| 30f69ec758 | |||
| c673e984b0 | |||
| 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 | |||
| 26b8e59066 | |||
| b8b0e75513 | |||
| 472ccc3929 | |||
| b16ed1de3b | |||
| 167f9216be | |||
| 1a9de428cb | |||
| 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 | |||
| eaeaf4ab3d | |||
| 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 | |||
| cf24fe9cbf | |||
| 08e0f22643 | |||
| d351840a70 | |||
| 78c6c77c00 | |||
| 46582601ea | |||
| cdb4156702 | |||
| 642653a37f | |||
| 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
|
||||
\#*
|
||||
|
||||
+15
-6
@@ -7,18 +7,27 @@
|
||||
[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
|
||||
[submodule "libraries/prometheus-cpp"]
|
||||
path = libraries/prometheus-cpp
|
||||
url = https://github.com/jupp0r/prometheus-cpp.git
|
||||
|
||||
+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 1)
|
||||
#set(VERSION_SUFFIX rc4)
|
||||
set(VERSION_MINOR 2)
|
||||
set(VERSION_PATCH 0)
|
||||
set(VERSION_SUFFIX dev)
|
||||
|
||||
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/fc 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
|
||||
@@ -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")
|
||||
@@ -44,3 +46,5 @@ set_property(GLOBAL PROPERTY CTEST_CUSTOM_TESTS_IGNORE
|
||||
"change_authkey import_ed decrypt_ec decrypt_rsa ssh logs generate_rsa import_ec echo\
|
||||
yubico_otp wrap_data wrap info import_rsa import_authkey generate_hmac generate_ec\
|
||||
attest pbkdf2 parsing ${_CTEST_CUSTOM_TESTS_IGNORE}")
|
||||
|
||||
add_subdirectory(prometheus)
|
||||
+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>&,
|
||||
|
||||
+118
-68
@@ -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.
|
||||
@@ -165,17 +166,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 +238,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 +403,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 +425,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 +441,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)}]() {} );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -569,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" );
|
||||
@@ -579,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) {
|
||||
@@ -612,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) {
|
||||
@@ -642,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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -696,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;
|
||||
@@ -715,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{} );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -723,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() {
|
||||
@@ -1077,18 +1099,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);
|
||||
};
|
||||
|
||||
@@ -1440,6 +1466,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;
|
||||
}
|
||||
|
||||
@@ -1692,7 +1721,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 +1756,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 +1792,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 +1817,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 +1980,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 +2028,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 )
|
||||
@@ -2016,10 +2063,13 @@ struct controller_impl {
|
||||
EOS_ASSERT( r == static_cast<const transaction_receipt_header&>(receipt),
|
||||
block_validate_exception, "receipt does not match, ${lhs} != ${rhs}",
|
||||
("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;
|
||||
if( trace ) {
|
||||
br.total_net_usage += trace->net_usage;
|
||||
if( trace->receipt ) br.total_cpu_usage_us += trace->receipt->cpu_usage_us;
|
||||
br.total_elapsed_time += trace->elapsed;
|
||||
}
|
||||
}
|
||||
|
||||
finalize_block();
|
||||
|
||||
@@ -2040,6 +2090,7 @@ struct controller_impl {
|
||||
pending->_block_stage = completed_block{ bsp };
|
||||
|
||||
commit_block(false);
|
||||
br.total_time = fc::time_point::now() - start;
|
||||
return;
|
||||
} catch ( const std::bad_alloc& ) {
|
||||
throw;
|
||||
@@ -2091,7 +2142,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 +2173,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 +2217,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 +2233,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 +2276,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 +2309,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 +2327,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 +2337,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() );
|
||||
|
||||
@@ -2804,7 +2858,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 +2870,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 +3031,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 +3518,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();
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -168,12 +170,20 @@ namespace eosio { namespace chain {
|
||||
|
||||
std::future<block_state_ptr> create_block_state_future( const block_id_type& id, const signed_block_ptr& b );
|
||||
|
||||
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{};
|
||||
};
|
||||
/**
|
||||
* @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 +240,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.
|
||||
*/
|
||||
|
||||
@@ -111,9 +111,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;
|
||||
|
||||
@@ -129,7 +129,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
|
||||
@@ -370,7 +370,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
|
||||
@@ -417,14 +417,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,
|
||||
@@ -462,7 +467,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;
|
||||
@@ -472,11 +477,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());
|
||||
|
||||
@@ -487,26 +492,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());
|
||||
@@ -518,21 +530,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));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -723,12 +742,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 */
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
// Snark - Wrapper for alt_bn128 add mul pair and modexp
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
|
||||
namespace fc {
|
||||
using bytes = std::vector<char>;
|
||||
|
||||
enum class k1_recover_error : int32_t {
|
||||
init_error,
|
||||
input_error,
|
||||
invalid_signature,
|
||||
recover_error,
|
||||
};
|
||||
|
||||
std::variant<k1_recover_error, bytes> k1_recover(const bytes& signature, const bytes& digest);
|
||||
} // fc
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user