forked from such-gitea/wownero
Compare commits
1094 Commits
v0.4.0.0
...
release-v0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
19466231e8 | ||
|
|
abf9c1a58e | ||
|
|
ab19a0ae15 | ||
|
|
a8be4465d9 | ||
|
|
bfd7154cbb | ||
|
|
8d00a34b2c | ||
|
|
fa50d74571 | ||
|
|
7c7f8647ca | ||
|
|
5b19c9a7b7 | ||
|
|
586b32a7ca | ||
|
|
09bf93a931 | ||
|
|
7b06d497f4 | ||
|
|
95a6414342 | ||
|
|
d6422cc81c | ||
|
|
661e3841fb | ||
|
|
ce3c9b1119 | ||
|
|
05e391fc54 | ||
|
|
d77ac12218 | ||
|
|
87d457d4ac | ||
|
|
0dbbd13baa | ||
|
|
dee662ce10 | ||
|
|
0742c615e2 | ||
|
|
8058facbb3 | ||
|
|
2e06575559 | ||
|
|
bbf8d72e18 | ||
|
|
d6c12cd641 | ||
|
|
f84028f88c | ||
|
|
2fbe9f7730 | ||
|
|
2b1829f649 | ||
|
|
3cfc60d416 | ||
|
|
9b19be69a1 | ||
|
|
6e093aa478 | ||
|
|
eaaa1e5a35 | ||
|
|
1ff89b1364 | ||
|
|
9acb635efd | ||
|
|
5fd8022721 | ||
|
|
385f232f5e | ||
|
|
41f7e77ca5 | ||
|
|
fb4c29b960 | ||
|
|
8aee860157 | ||
|
|
1c745c3b04 | ||
|
|
7e9ecf35dd | ||
|
|
b4a6c93d94 | ||
|
|
eaa36e8f26 | ||
|
|
1e5f2e4c58 | ||
|
|
39875ebdd4 | ||
|
|
72a1b05c13 | ||
|
|
9fad3c060b | ||
|
|
b117840c81 | ||
|
|
0622741c03 | ||
|
|
362ecad06c | ||
|
|
b45b4e58f4 | ||
|
|
4bcb105e6c | ||
|
|
7553fdcbb3 | ||
|
|
32745e0696 | ||
|
|
56b6e9a89f | ||
|
|
b91d510669 | ||
|
|
93c2e6f521 | ||
|
|
0470ea5ac0 | ||
|
|
f94c615fc3 | ||
|
|
ebb1580493 | ||
|
|
d2abdff997 | ||
|
|
baf9984f32 | ||
|
|
356ea85da7 | ||
|
|
e1b8e3d7b4 | ||
|
|
d56c1d68f9 | ||
|
|
6314a4e78a | ||
|
|
02db718dfe | ||
|
|
a315729e98 | ||
|
|
423cf4406d | ||
|
|
33a76e92f4 | ||
|
|
7ad2500f68 | ||
|
|
7057806c49 | ||
|
|
b5c9aed261 | ||
|
|
817be97f39 | ||
|
|
73574c7380 | ||
|
|
2a616c8b15 | ||
|
|
8fdc0d4cb3 | ||
|
|
66d1424200 | ||
|
|
3974e40efa | ||
|
|
ad6a732f24 | ||
|
|
abb4728cf7 | ||
|
|
51a7dd045e | ||
|
|
7942e862b8 | ||
|
|
eb982caad1 | ||
|
|
eb5a2cbdd2 | ||
|
|
cdf2e30825 | ||
|
|
7eab7b6a72 | ||
|
|
bc19bcb2f6 | ||
|
|
3353e6e784 | ||
|
|
eaf602bceb | ||
|
|
d48a44d161 | ||
|
|
d5c079ef1e | ||
|
|
ba1fd08e41 | ||
|
|
6246aada9d | ||
|
|
18683acc84 | ||
|
|
89c74b5710 | ||
|
|
650594ab63 | ||
|
|
7e669f2d43 | ||
|
|
586e9189a6 | ||
|
|
e776762bf6 | ||
|
|
13edabb3e6 | ||
|
|
d1d21b0378 | ||
|
|
0bed77b72e | ||
|
|
627c303c2f | ||
|
|
b26d373800 | ||
|
|
5ebebc1420 | ||
|
|
4fccdaea6a | ||
|
|
01a67e96b1 | ||
|
|
72f5fb8019 | ||
|
|
2777f8c421 | ||
|
|
154c7abdb3 | ||
|
|
83aa5c70d0 | ||
|
|
6834ce6de2 | ||
|
|
8beb3cd2a1 | ||
|
|
dc24639e64 | ||
|
|
92f42b1e81 | ||
|
|
29d7ef0fe0 | ||
|
|
a9504f7001 | ||
|
|
3c36a6a227 | ||
|
|
b215ea9f56 | ||
|
|
067e232b19 | ||
|
|
d7f3805d2e | ||
|
|
a04d68f698 | ||
|
|
3b04e2e3d4 | ||
|
|
e25d21a788 | ||
|
|
2509717b11 | ||
|
|
77ef8c1839 | ||
|
|
e0f4606a72 | ||
|
|
d7d6d23867 | ||
|
|
1b9e6861b7 | ||
|
|
cc33d3b2de | ||
|
|
d8f95843c4 | ||
|
|
e16982617b | ||
|
|
eca27122df | ||
|
|
4b609dede3 | ||
|
|
5209bbd0c5 | ||
|
|
161fd13768 | ||
|
|
49c11b2248 | ||
|
|
f5df0e272e | ||
|
|
34da7d852b | ||
|
|
84cc3b916e | ||
|
|
24e519b9b6 | ||
|
|
3512eb5e68 | ||
|
|
42545e9adc | ||
|
|
9d97ffb804 | ||
|
|
71b9dd96ca | ||
|
|
b63f1ea637 | ||
|
|
5f83ec59ca | ||
|
|
b26ab0b580 | ||
|
|
17ab6fdd5a | ||
|
|
a2cd4f2cc7 | ||
|
|
9556ba0d66 | ||
|
|
b8cee6bf9e | ||
|
|
5adbede27f | ||
|
|
735a33e8d8 | ||
|
|
e037534f44 | ||
|
|
9570081ae5 | ||
|
|
e0fa7fa384 | ||
|
|
9c426a30f9 | ||
|
|
ca9b2493ee | ||
|
|
cf436cde1a | ||
|
|
b99e670f84 | ||
|
|
88a0985104 | ||
|
|
4701a78ad1 | ||
|
|
861895e92d | ||
|
|
5fc4d57ee5 | ||
|
|
efbd42f9d9 | ||
|
|
4cbaa6e43d | ||
|
|
f0b3bbf808 | ||
|
|
33aa05678f | ||
|
|
37252f6aec | ||
|
|
67e6c4370b | ||
|
|
a5476f82ca | ||
|
|
50f9472911 | ||
|
|
bf6388e4d4 | ||
|
|
05c942aba8 | ||
|
|
735de189ab | ||
|
|
931e7faa0b | ||
|
|
559a0cfc92 | ||
|
|
52b639bcd0 | ||
|
|
1011142868 | ||
|
|
3d8f54daad | ||
|
|
86a137aff3 | ||
|
|
acc9b32749 | ||
|
|
9d0b177720 | ||
|
|
0d062bacfb | ||
|
|
7340300460 | ||
|
|
83debef99e | ||
|
|
7dd11711b0 | ||
|
|
bcf3f6afdd | ||
|
|
3ebd05d4e5 | ||
|
|
a093092ef7 | ||
|
|
1eebb82bcc | ||
|
|
fb6a363050 | ||
|
|
2e2139ffb7 | ||
|
|
0749a8bd3c | ||
|
|
1b0afeeb1c | ||
|
|
418a993618 | ||
|
|
ea7f954381 | ||
|
|
6e8554221f | ||
|
|
53df2deb36 | ||
|
|
e67016ddb4 | ||
|
|
661439f4e0 | ||
|
|
5fdcda50ee | ||
|
|
921b0fb11b | ||
|
|
7ece1550e1 | ||
|
|
85318e7800 | ||
|
|
a085da3247 | ||
|
|
d8b1ec8b8b | ||
|
|
02563bf4b9 | ||
|
|
c57a65b246 | ||
|
|
06d05c21eb | ||
|
|
b2972927ea | ||
|
|
17142ec9bb | ||
|
|
6a78140863 | ||
|
|
69da14e105 | ||
|
|
fe1256471a | ||
|
|
558da3684c | ||
|
|
6f5360b3c6 | ||
|
|
3882b30076 | ||
|
|
cf470bf3d6 | ||
|
|
174f31bf7d | ||
|
|
8bf5a00564 | ||
|
|
f2eee1eb8c | ||
|
|
e350cc5ad5 | ||
|
|
bf9a0f4c65 | ||
|
|
45683ee02c | ||
|
|
689758d691 | ||
|
|
13d9bdb849 | ||
|
|
5c234cbdcb | ||
|
|
295bae10ba | ||
|
|
e67789d075 | ||
|
|
0d206dccda | ||
|
|
cd8c7f6e78 | ||
|
|
d2f9a4c584 | ||
|
|
c1182e433e | ||
|
|
78fd2599c2 | ||
|
|
c39ad0cd72 | ||
|
|
89288863a4 | ||
|
|
357441a2fa | ||
|
|
936e22a9b5 | ||
|
|
50981c40ce | ||
|
|
59024a9e88 | ||
|
|
bb6e3bbc0f | ||
|
|
b35beaa8d6 | ||
|
|
5c637c7910 | ||
|
|
1dd5c73f62 | ||
|
|
a69271faf7 | ||
|
|
92d1da28ef | ||
|
|
d9f666d78c | ||
|
|
6e270fbd29 | ||
|
|
a21da9058b | ||
|
|
0f4f873bf3 | ||
|
|
6b1b4e83dd | ||
|
|
6f153533e2 | ||
|
|
8a61f669a9 | ||
|
|
c05f98d4c3 | ||
|
|
fb47963e09 | ||
|
|
7964d4f8ea | ||
|
|
83907f8829 | ||
|
|
f3cd51a12b | ||
|
|
bf1e1d979c | ||
|
|
4d0a8db06d | ||
|
|
7aa5112280 | ||
|
|
e03402b0c7 | ||
|
|
b65e236fda | ||
|
|
de5631c6be | ||
|
|
85110b42ab | ||
|
|
fd74815f65 | ||
|
|
93f473e9f8 | ||
|
|
aa1d321e5f | ||
|
|
63eeb9df80 | ||
|
|
37a306370d | ||
|
|
bc208be63d | ||
|
|
14ab2e4db1 | ||
|
|
85d731c66d | ||
|
|
4a652d6b52 | ||
|
|
0645dcdbdb | ||
|
|
b88bbf59c3 | ||
|
|
dc9a69d980 | ||
|
|
629db71593 | ||
|
|
a059bcd74e | ||
|
|
d6893aedf6 | ||
|
|
90d1a00c10 | ||
|
|
bb3ff2bb36 | ||
|
|
7a056f4425 | ||
|
|
43a06350cf | ||
|
|
8db2d8d416 | ||
|
|
bce474be7d | ||
|
|
a2505c2fcc | ||
|
|
bad2c7cf31 | ||
|
|
2371a814cf | ||
|
|
68dcf73de2 | ||
|
|
535bd0eb7e | ||
|
|
08f0c60ffc | ||
|
|
df98bc50a6 | ||
|
|
f9d97f3fec | ||
|
|
9d0565615c | ||
|
|
7781675f22 | ||
|
|
0ff0850545 | ||
|
|
7ab49f96ad | ||
|
|
22a6591a70 | ||
|
|
4a1744e93e | ||
|
|
3cfa45cc7d | ||
|
|
e468d541b4 | ||
|
|
580497d5f9 | ||
|
|
b174527f1d | ||
|
|
b4a9ebad6c | ||
|
|
728a947646 | ||
|
|
9c40bc62fc | ||
|
|
669019010e | ||
|
|
8cd9840859 | ||
|
|
4ed30bab50 | ||
|
|
24f5239693 | ||
|
|
52e19d6955 | ||
|
|
0c77523d61 | ||
|
|
423973596b | ||
|
|
f77ce675cb | ||
|
|
a06d2581c3 | ||
|
|
9bf0105e25 | ||
|
|
a4065bf267 | ||
|
|
ecaf5b3feb | ||
|
|
ba8dd3479d | ||
|
|
b766014933 | ||
|
|
e9bce045a4 | ||
|
|
05edc969c0 | ||
|
|
6e6ffc0650 | ||
|
|
6dbbc69055 | ||
|
|
27af46c930 | ||
|
|
c336d0f217 | ||
|
|
bb30a72367 | ||
|
|
4cb1d879f6 | ||
|
|
ff72200d0a | ||
|
|
9bdc9109fb | ||
|
|
db3db0930e | ||
|
|
b1f05f589e | ||
|
|
f9b22a7b01 | ||
|
|
d743994086 | ||
|
|
44259e560e | ||
|
|
fd194aaa4d | ||
|
|
7850541074 | ||
|
|
b182dc8262 | ||
|
|
dd2fc3afe3 | ||
|
|
1396b65bbc | ||
|
|
7addabce8f | ||
|
|
5f9374c735 | ||
|
|
9f24e57dc2 | ||
|
|
15570f9a8f | ||
|
|
3584a852a3 | ||
|
|
53a99ca112 | ||
|
|
239a7e10ff | ||
|
|
be001326d1 | ||
|
|
1c36fcf886 | ||
|
|
20087b3a9d | ||
|
|
c6f57d9db4 | ||
|
|
c74d9057f8 | ||
|
|
885d3d5a99 | ||
|
|
fa53b76129 | ||
|
|
466f079586 | ||
|
|
438781afc4 | ||
|
|
d794abb8c5 | ||
|
|
e8049be955 | ||
|
|
5fe6aa19f6 | ||
|
|
249feda4e1 | ||
|
|
607301bf6d | ||
|
|
ac9346637a | ||
|
|
4d52ec0ca4 | ||
|
|
2ace509a78 | ||
|
|
b4679f37f4 | ||
|
|
4f81cd3a3c | ||
|
|
1660b0e72c | ||
|
|
cd236aebca | ||
|
|
55c7cd1458 | ||
|
|
b2bb9312a7 | ||
|
|
befdcbf4be | ||
|
|
67a56a9f8b | ||
|
|
56b50faab2 | ||
|
|
07ec748c82 | ||
|
|
11dbfbc5b3 | ||
|
|
157690caaa | ||
|
|
bcda7adcd4 | ||
|
|
e6d36c1701 | ||
|
|
9137ad2c63 | ||
|
|
ac4f71c200 | ||
|
|
8f418a6db0 | ||
|
|
2bf636503f | ||
|
|
044dff5a30 | ||
|
|
c83012c476 | ||
|
|
ce0c743205 | ||
|
|
1224e53b74 | ||
|
|
0e6ed559c6 | ||
|
|
463434d1f7 | ||
|
|
d0a0565f7d | ||
|
|
6526d87f17 | ||
|
|
a129bbd944 | ||
|
|
7ed496cc78 | ||
|
|
d1591853bf | ||
|
|
61632dc166 | ||
|
|
a4317e61b5 | ||
|
|
7434df1cc6 | ||
|
|
0825e97436 | ||
|
|
a1359ad43c | ||
|
|
fe0fa3b9c5 | ||
|
|
5ffb2ff9b7 | ||
|
|
869b3bf824 | ||
|
|
c429176248 | ||
|
|
1569717718 | ||
|
|
0b05a0fa74 | ||
|
|
51eb3bdcd6 | ||
|
|
b17b8db3f5 | ||
|
|
7314d919e7 | ||
|
|
d126a02b5d | ||
|
|
263431c486 | ||
|
|
1ed0ed4de4 | ||
|
|
1b867e7f40 | ||
|
|
ef56529f93 | ||
|
|
3011178021 | ||
|
|
c444b1b229 | ||
|
|
7e67c52fa2 | ||
|
|
2a8fcb421b | ||
|
|
126196b017 | ||
|
|
71d67bda74 | ||
|
|
cb9ecab197 | ||
|
|
bacf0a1e2f | ||
|
|
e895c3def1 | ||
|
|
7f48bf05d7 | ||
|
|
9ce9f8caf6 | ||
|
|
f34e2e20bd | ||
|
|
0793184bd0 | ||
|
|
939bc22332 | ||
|
|
9ff6e6a0a7 | ||
|
|
e9164bb38b | ||
|
|
112f32f068 | ||
|
|
f5d7b9933a | ||
|
|
8f4ce989c2 | ||
|
|
1aa10c4364 | ||
|
|
aacfd6e370 | ||
|
|
cb1cc757ba | ||
|
|
f0ab4dc7b2 | ||
|
|
cbbf4d241b | ||
|
|
db5715468a | ||
|
|
f0ba19fde5 | ||
|
|
ab85b924c9 | ||
|
|
cfb3046222 | ||
|
|
5f7da005a3 | ||
|
|
d6b9bdd322 | ||
|
|
56b6e41ea7 | ||
|
|
46bcd91db4 | ||
|
|
29311fd140 | ||
|
|
8db3d5731b | ||
|
|
0806a23a6e | ||
|
|
36d7b1b67c | ||
|
|
55b9acfce5 | ||
|
|
26971d46fc | ||
|
|
7a76354c8b | ||
|
|
89202ce462 | ||
|
|
e774f2498a | ||
|
|
a54dbaee08 | ||
|
|
44439c3208 | ||
|
|
5fd83c13fb | ||
|
|
8501b8dffb | ||
|
|
03c07b167d | ||
|
|
0664a98421 | ||
|
|
4bce935b40 | ||
|
|
b66ba78306 | ||
|
|
639a3c019c | ||
|
|
eb8a51be68 | ||
|
|
d6d276c604 | ||
|
|
2b2a681b01 | ||
|
|
80e4fef3c6 | ||
|
|
4801d6b514 | ||
|
|
846190fd18 | ||
|
|
daa6cc7d73 | ||
|
|
50cb370d5b | ||
|
|
347bba9dd1 | ||
|
|
7418aa6005 | ||
|
|
4469b0c41e | ||
|
|
df0e7c2feb | ||
|
|
97764bae3a | ||
|
|
cd647612b0 | ||
|
|
6929b52426 | ||
|
|
54b859bea5 | ||
|
|
e611728228 | ||
|
|
fad88e18a9 | ||
|
|
e98e03566a | ||
|
|
ca4e477dc2 | ||
|
|
6cc1ed8dc1 | ||
|
|
7c8f95d3e2 | ||
|
|
39bcb974c4 | ||
|
|
03738fdde1 | ||
|
|
0722287774 | ||
|
|
b2038e24f0 | ||
|
|
77ed11e627 | ||
|
|
59e6fb06f9 | ||
|
|
5f1bbe3bce | ||
|
|
ad5aabc85a | ||
|
|
085b6ba98e | ||
|
|
8bbae77134 | ||
|
|
e4378ed8aa | ||
|
|
59dc37a1b0 | ||
|
|
6d4d4ddb68 | ||
|
|
88e5ed0072 | ||
|
|
46d8bc2a33 | ||
|
|
5f8f56315c | ||
|
|
20171746de | ||
|
|
be6acfd5be | ||
|
|
88fbc4a567 | ||
|
|
93e7627d5a | ||
|
|
45c85c89de | ||
|
|
4e1e9a607e | ||
|
|
9a66d9f48b | ||
|
|
76f95f052e | ||
|
|
f0bc684ccd | ||
|
|
2c636e45f2 | ||
|
|
5083614ffa | ||
|
|
8eab6147f4 | ||
|
|
5019852adc | ||
|
|
2af1ec3af7 | ||
|
|
9d6539923e | ||
|
|
67666b14ba | ||
|
|
91c7d68b2d | ||
|
|
fa7cdd6420 | ||
|
|
ce63d5634e | ||
|
|
c955257c4a | ||
|
|
d2e26c23f3 | ||
|
|
8ca1215f25 | ||
|
|
510dbf3329 | ||
|
|
1db7a29e12 | ||
|
|
04845b1868 | ||
|
|
2e7bfd0de5 | ||
|
|
ec6982f8eb | ||
|
|
e07ace0896 | ||
|
|
1eed62c618 | ||
|
|
b0c00b0752 | ||
|
|
3f662876e6 | ||
|
|
4e6187faf3 | ||
|
|
17eefe7928 | ||
|
|
89645ec86e | ||
|
|
a5d21be843 | ||
|
|
0d415ff638 | ||
|
|
4a4ea78ecd | ||
|
|
6e8e4fb3b7 | ||
|
|
7e4507a048 | ||
|
|
140eb78231 | ||
|
|
1eebb3d8fc | ||
|
|
13a34faeb0 | ||
|
|
68813d2694 | ||
|
|
339a23a85e | ||
|
|
6fcdc9e0b2 | ||
|
|
62511df622 | ||
|
|
b219c24c3a | ||
|
|
5b6bcca32a | ||
|
|
fa814af969 | ||
|
|
620105ecaf | ||
|
|
2bc977bab9 | ||
|
|
2a100fd81f | ||
|
|
48a7bc4280 | ||
|
|
76ac5a8fbe | ||
|
|
dc6c0696fd | ||
|
|
76affd941b | ||
|
|
11c6718865 | ||
|
|
3d5abbe86b | ||
|
|
29dea03091 | ||
|
|
1f2409e9e2 | ||
|
|
82d1b74500 | ||
|
|
ab74dc277a | ||
|
|
70271fa788 | ||
|
|
e9ffa91257 | ||
|
|
ea37614efe | ||
|
|
b780cf4db1 | ||
|
|
a64f57fe42 | ||
|
|
4d66939791 | ||
|
|
41e583b0a2 | ||
|
|
e69e0e9e34 | ||
|
|
1c55a3756b | ||
|
|
05485bd1c5 | ||
|
|
8d2e454929 | ||
|
|
b82bcdea2d | ||
|
|
0415863747 | ||
|
|
7aa2030cee | ||
|
|
b531858c02 | ||
|
|
2102e6c738 | ||
|
|
a68143bc52 | ||
|
|
564e9c3b5f | ||
|
|
8c4b3f3736 | ||
|
|
01475c36c0 | ||
|
|
fd3b71129b | ||
|
|
2530dc6710 | ||
|
|
e7328ed5b7 | ||
|
|
5e795ee7af | ||
|
|
2a44c2defd | ||
|
|
dc7dd56867 | ||
|
|
88369c6685 | ||
|
|
5295e4eb82 | ||
|
|
1d2c08610b | ||
|
|
3b409a3b8a | ||
|
|
ad13b6d25a | ||
|
|
017e07a035 | ||
|
|
dd966c8a3a | ||
|
|
b586ae1310 | ||
|
|
dd8354aa08 | ||
|
|
4745e3be22 | ||
|
|
4cde4cb946 | ||
|
|
4e081001c0 | ||
|
|
0c8d8f6b2e | ||
|
|
5ed6669130 | ||
|
|
c3c14f3083 | ||
|
|
b21fdaa874 | ||
|
|
d6fc870d04 | ||
|
|
de905d4b48 | ||
|
|
10475ab23f | ||
|
|
77655b0a0e | ||
|
|
ac09cfa6be | ||
|
|
4307489147 | ||
|
|
bc8cbdb25d | ||
|
|
b278b83860 | ||
|
|
95766fe878 | ||
|
|
83f5587167 | ||
|
|
361513ac81 | ||
|
|
ce9457a379 | ||
|
|
13a43fcf0b | ||
|
|
a4d2d84209 | ||
|
|
289880d82d | ||
|
|
5dd03846b6 | ||
|
|
bcab579864 | ||
|
|
9e6c7784ea | ||
|
|
3e914ad831 | ||
|
|
96c1de979a | ||
|
|
2fd9be1646 | ||
|
|
c5e2aee961 | ||
|
|
26a42fe54a | ||
|
|
37f0799284 | ||
|
|
b0b6959c1d | ||
|
|
3411326a04 | ||
|
|
4616cf2641 | ||
|
|
8439306212 | ||
|
|
1c6cfd34f4 | ||
|
|
9127a8b79f | ||
|
|
43f71100bc | ||
|
|
628428a0df | ||
|
|
2382484dcd | ||
|
|
888324fa57 | ||
|
|
0f757177fe | ||
|
|
4520cfd978 | ||
|
|
a3fe1c56ee | ||
|
|
f13c7a8263 | ||
|
|
5860611afa | ||
|
|
c8226ad1f7 | ||
|
|
0dddfeacc9 | ||
|
|
21b1fa1c35 | ||
|
|
ff01c3ade4 | ||
|
|
f739a3cbb8 | ||
|
|
dda05f357a | ||
|
|
8eb5b0be36 | ||
|
|
3fde902394 | ||
|
|
92b5d6c204 | ||
|
|
b293c487fb | ||
|
|
262e391fb1 | ||
|
|
e7c0fcd8f3 | ||
|
|
c24a0af9f1 | ||
|
|
ff37bd00bc | ||
|
|
3940e12933 | ||
|
|
3a4c3ac891 | ||
|
|
ed7825dc0c | ||
|
|
68b1197f5d | ||
|
|
5e675de7c2 | ||
|
|
8e24533a7f | ||
|
|
be02eb9389 | ||
|
|
0496c7c91a | ||
|
|
704b60caf0 | ||
|
|
7db7ec8591 | ||
|
|
702a41034d | ||
|
|
5c102c60dc | ||
|
|
61eea83978 | ||
|
|
9474567d76 | ||
|
|
f6d7e87b67 | ||
|
|
326437c5ff | ||
|
|
5fad1c505a | ||
|
|
be81a27fa4 | ||
|
|
173f7b8f42 | ||
|
|
69502c4040 | ||
|
|
007b835daa | ||
|
|
5cade94189 | ||
|
|
94ed562148 | ||
|
|
9315e12d34 | ||
|
|
cff15e4123 | ||
|
|
3235abc184 | ||
|
|
138aefd0e7 | ||
|
|
2e4653c077 | ||
|
|
d14a074055 | ||
|
|
3e026ff6ed | ||
|
|
21afa71ba6 | ||
|
|
d518dae4bf | ||
|
|
025187e6c9 | ||
|
|
33122ab8a6 | ||
|
|
f2e65c6e50 | ||
|
|
fead7ebab0 | ||
|
|
d6440ab319 | ||
|
|
7f8bdeb35c | ||
|
|
63e342be84 | ||
|
|
979105b298 | ||
|
|
45e419bd5c | ||
|
|
2951436704 | ||
|
|
ee31383a52 | ||
|
|
8d578f1f2d | ||
|
|
7d2d8055ac | ||
|
|
2790ebc9f0 | ||
|
|
fc39d3b23c | ||
|
|
8c0523771f | ||
|
|
639ca3b1fa | ||
|
|
20eb192162 | ||
|
|
4e409be887 | ||
|
|
78a6690a6f | ||
|
|
e2311db717 | ||
|
|
ebf2818ab5 | ||
|
|
e647922080 | ||
|
|
61caab8a8c | ||
|
|
96f8c62dc4 | ||
|
|
eed4dba880 | ||
|
|
0a4a7da35c | ||
|
|
42f3b7cbca | ||
|
|
9c211b50de | ||
|
|
2241114965 | ||
|
|
34d4b798d4 | ||
|
|
40f85f478e | ||
|
|
c58758a016 | ||
|
|
d1f102626c | ||
|
|
82c39355ac | ||
|
|
f449dbe8eb | ||
|
|
94803bad01 | ||
|
|
97f5a130d6 | ||
|
|
21807217e2 | ||
|
|
e451c76181 | ||
|
|
27ca6ca594 | ||
|
|
58cceaad71 | ||
|
|
318fb23d7a | ||
|
|
a4272de797 | ||
|
|
d6d78f157b | ||
|
|
909398efc7 | ||
|
|
8c4db68ff7 | ||
|
|
d95bc44c6b | ||
|
|
dead780f8a | ||
|
|
207b66ecc2 | ||
|
|
9e1403e155 | ||
|
|
34cb6b4b70 | ||
|
|
aa0ea0aafc | ||
|
|
438d52deaf | ||
|
|
ef649f998d | ||
|
|
3474154b75 | ||
|
|
a9b83f5a6e | ||
|
|
65c09beaf7 | ||
|
|
8b18401ea0 | ||
|
|
49dc78d99b | ||
|
|
29254fc06e | ||
|
|
ba0a7294d0 | ||
|
|
4c6de54ee2 | ||
|
|
008b9036a3 | ||
|
|
0c76dbdd00 | ||
|
|
4510f417f9 | ||
|
|
3d623a86d1 | ||
|
|
59de6f8d99 | ||
|
|
1d176473e9 | ||
|
|
9a39b7dd7f | ||
|
|
84d9e7faec | ||
|
|
9b38551c3c | ||
|
|
2329d2f4c8 | ||
|
|
8a27caeb22 | ||
|
|
9453573581 | ||
|
|
c28a2b0d7d | ||
|
|
5eb2e01216 | ||
|
|
cbfa0a2a7e | ||
|
|
87d7612311 | ||
|
|
3ad4ecd4ff | ||
|
|
dcbc17e97e | ||
|
|
2d92fa5d69 | ||
|
|
a844844cda | ||
|
|
13851b28c7 | ||
|
|
80d7c6c730 | ||
|
|
e6f4d4acf0 | ||
|
|
0e4c7d0fae | ||
|
|
2771a18e85 | ||
|
|
2704624eae | ||
|
|
5d3e70229e | ||
|
|
dcfd299239 | ||
|
|
ef2cb63287 | ||
|
|
f025ae9760 | ||
|
|
41be339655 | ||
|
|
f7f1917ed4 | ||
|
|
ba8331ce41 | ||
|
|
31a895e876 | ||
|
|
57ea90285c | ||
|
|
a830db2577 | ||
|
|
ed2c81ed95 | ||
|
|
209ec963b5 | ||
|
|
6795bd0d4e | ||
|
|
a2b557fe5c | ||
|
|
50af3579ee | ||
|
|
31f47d72fe | ||
|
|
14372ca95a | ||
|
|
ab7ab29fc0 | ||
|
|
c0c6102260 | ||
|
|
a2b08db9c9 | ||
|
|
b1be364f08 | ||
|
|
3afaedf365 | ||
|
|
89b99ef2d8 | ||
|
|
8fad35f8e2 | ||
|
|
66212837ab | ||
|
|
506be80601 | ||
|
|
741a773025 | ||
|
|
ea1d54aeb7 | ||
|
|
26562e9f3c | ||
|
|
c3ec5373b3 | ||
|
|
473d984d88 | ||
|
|
1eddabf0a4 | ||
|
|
ff7dc087ae | ||
|
|
87e158b5b9 | ||
|
|
41b4bf9d6d | ||
|
|
7cdd147da5 | ||
|
|
34de7bc267 | ||
|
|
41e9cab4e1 | ||
|
|
3b4dec2d12 | ||
|
|
9d7f6e6089 | ||
|
|
df9d50a8a4 | ||
|
|
d45cd37c53 | ||
|
|
3e46db97e5 | ||
|
|
46e90b7780 | ||
|
|
248310de06 | ||
|
|
8fc0cdb96f | ||
|
|
66df13a58b | ||
|
|
e5592c4bab | ||
|
|
ffab67004c | ||
|
|
7bf99a2376 | ||
|
|
9a3712541e | ||
|
|
34c57d071f | ||
|
|
0a24673fef | ||
|
|
3721298cf6 | ||
|
|
306365d4e6 | ||
|
|
7935bc5f6b | ||
|
|
9eb51887b0 | ||
|
|
5a221c0e48 | ||
|
|
81a2ff768b | ||
|
|
c678413a89 | ||
|
|
51cdd76bbd | ||
|
|
034b0c7adb | ||
|
|
17fd575fe4 | ||
|
|
36aeaa7545 | ||
|
|
70f932fe0a | ||
|
|
4aa832e534 | ||
|
|
0c4148845b | ||
|
|
bd9e4e3149 | ||
|
|
2a19697bd4 | ||
|
|
896512b2b6 | ||
|
|
cb130c7590 | ||
|
|
26dd216c67 | ||
|
|
9a3bd88b9f | ||
|
|
61f3916b4a | ||
|
|
1db8cf0db9 | ||
|
|
d841339b09 | ||
|
|
50bc95519e | ||
|
|
f62399b88d | ||
|
|
1a526ed571 | ||
|
|
09f43b9a6b | ||
|
|
5a2864c1fb | ||
|
|
6cb97076ce | ||
|
|
cfd66dae4b | ||
|
|
5b5828fcec | ||
|
|
9226acca4b | ||
|
|
fceb774344 | ||
|
|
4e7897e57c | ||
|
|
e3012444fb | ||
|
|
7af0b7fffc | ||
|
|
fb2b16f10a | ||
|
|
abfff766e5 | ||
|
|
b3363e8e0a | ||
|
|
42e7f31613 | ||
|
|
53b5d03b82 | ||
|
|
6447dc72e9 | ||
|
|
aada0670ba | ||
|
|
26c569d6f6 | ||
|
|
b85acb4cb8 | ||
|
|
bc443494f3 | ||
|
|
149da420e9 | ||
|
|
8db23df581 | ||
|
|
b43b9a1304 | ||
|
|
63d0ab09b5 | ||
|
|
798dfcfe79 | ||
|
|
62f3f0480a | ||
|
|
a915d49307 | ||
|
|
6be2516140 | ||
|
|
41d04a87b2 | ||
|
|
ed139efc5d | ||
|
|
0a5292c339 | ||
|
|
25c15dca5c | ||
|
|
2d10830cfb | ||
|
|
b628503bad | ||
|
|
0cf80baea4 | ||
|
|
08b85a8e00 | ||
|
|
55c7fb87a9 | ||
|
|
362f5e6eb8 | ||
|
|
03096150c6 | ||
|
|
2d5921eefa | ||
|
|
1789b76b5d | ||
|
|
87665281ea | ||
|
|
4ecf71405f | ||
|
|
f4e329583e | ||
|
|
948c48271a | ||
|
|
25e7a7d96f | ||
|
|
9ddb07fcc4 | ||
|
|
f61fe2ef28 | ||
|
|
284fe6438d | ||
|
|
2619d966c6 | ||
|
|
13d73d9ed6 | ||
|
|
6884db7b31 | ||
|
|
00635bd68b | ||
|
|
112f3678bc | ||
|
|
22c8730261 | ||
|
|
5321769b65 | ||
|
|
9e5f2738fd | ||
|
|
03b4cca6c2 | ||
|
|
5bfe03804c | ||
|
|
8a1f0d7d13 | ||
|
|
48fcf76be9 | ||
|
|
e1a940806a | ||
|
|
1af890287b | ||
|
|
e69849e979 | ||
|
|
2bb2c1b9d7 | ||
|
|
d7a6b72c15 | ||
|
|
c367609447 | ||
|
|
8cc46069ac | ||
|
|
bf26920f27 | ||
|
|
f24cbc5245 | ||
|
|
62c8c07c47 | ||
|
|
01cc978722 | ||
|
|
4764929ecb | ||
|
|
d81e042306 | ||
|
|
2b3357ee98 | ||
|
|
941a608d52 | ||
|
|
8962f0032f | ||
|
|
2861289efd | ||
|
|
5f00df3cf9 | ||
|
|
ace2edacb6 | ||
|
|
afed9787cd | ||
|
|
f2cb56a2eb | ||
|
|
9c2a7b4638 | ||
|
|
f0322a083a | ||
|
|
95ccf508cd | ||
|
|
827ca3fd3b | ||
|
|
2b0c632f32 | ||
|
|
4f3a4fb701 | ||
|
|
5db9e3c28e | ||
|
|
f8dd433110 | ||
|
|
ab87e7fdae | ||
|
|
6b8568e9a1 | ||
|
|
8a7b3ff138 | ||
|
|
503d2693fd | ||
|
|
3ee6a1b706 | ||
|
|
b6eb7484d1 | ||
|
|
40dd59fb8e | ||
|
|
737712c0c6 | ||
|
|
c8378933ae | ||
|
|
3a373c3d3a | ||
|
|
64adb566e5 | ||
|
|
9fde7aafe8 | ||
|
|
d3447364d0 | ||
|
|
f80b1571c6 | ||
|
|
f17383afc2 | ||
|
|
1aae39dff2 | ||
|
|
14f0d38cd6 | ||
|
|
0da5d37bf3 | ||
|
|
9bc8f76924 | ||
|
|
882ce8f7b1 | ||
|
|
f0f3157183 | ||
|
|
f03bf36c85 | ||
|
|
d735f9b24a | ||
|
|
daeb3a974c | ||
|
|
a7ea14dc6a | ||
|
|
4267a0bb51 | ||
|
|
b665bab1d6 | ||
|
|
e09710f76e | ||
|
|
66f4700f57 | ||
|
|
b26cd26333 | ||
|
|
0321d1ac79 | ||
|
|
98cf62cc45 | ||
|
|
7e30eadb32 | ||
|
|
a79fc219b7 | ||
|
|
c534fe8d19 | ||
|
|
c4907d24cb | ||
|
|
8e1b322a15 | ||
|
|
ed72f35e9a | ||
|
|
764340d112 | ||
|
|
5b189ce2a8 | ||
|
|
08819705fc | ||
|
|
91663fcc00 | ||
|
|
5a412b7a3f | ||
|
|
e942d34d54 | ||
|
|
740da1ba95 | ||
|
|
a6b8d3fee1 | ||
|
|
dfd36bbebb | ||
|
|
4d15864728 | ||
|
|
885a117ddb | ||
|
|
6a58c88e2d | ||
|
|
a87980f6c2 | ||
|
|
de1ffe07b1 | ||
|
|
8a6c081df7 | ||
|
|
b9389e582e | ||
|
|
45975fd8eb | ||
|
|
6715c90667 | ||
|
|
49f4645f1d | ||
|
|
bdf5a3ad3f | ||
|
|
a2cef8cba4 | ||
|
|
0889d2f85e | ||
|
|
64f82e0481 | ||
|
|
f794d3b3df | ||
|
|
e6d45d2db6 | ||
|
|
709658d166 | ||
|
|
4dae04dde2 | ||
|
|
d6cefbd1b8 | ||
|
|
2a1e23e087 | ||
|
|
5f8ffca34d | ||
|
|
2f5506daf8 | ||
|
|
73a45e98ad | ||
|
|
791da4343c | ||
|
|
2906a24179 | ||
|
|
ed22abb798 | ||
|
|
81db197383 | ||
|
|
ff31611a32 | ||
|
|
18761b372f | ||
|
|
3147468d35 | ||
|
|
ce173cbb5b | ||
|
|
db55263b4c | ||
|
|
cb9c7972b6 | ||
|
|
d44d19ca79 | ||
|
|
29fbaeaae5 | ||
|
|
16e209e08d | ||
|
|
a2566db09e | ||
|
|
558d05b47e | ||
|
|
b88c9a003e | ||
|
|
a5c98609a1 | ||
|
|
89e51ecd38 | ||
|
|
9317bce9ca | ||
|
|
4a72d595a6 | ||
|
|
f357210c00 | ||
|
|
4b728d7dd4 | ||
|
|
a58d9738c9 | ||
|
|
b5cb1bc403 | ||
|
|
ce63ab09db | ||
|
|
261ee5628b | ||
|
|
52f6b33890 | ||
|
|
18cd6837b6 | ||
|
|
9705032618 | ||
|
|
a7ce392eef | ||
|
|
b6a76f76e7 | ||
|
|
eb9f3a3294 | ||
|
|
6f9260e38e | ||
|
|
872cb4efd8 | ||
|
|
4812c062c5 | ||
|
|
7ed94d3122 | ||
|
|
5f19384729 | ||
|
|
b13bddc3c9 | ||
|
|
fa0839f2f5 | ||
|
|
1590183965 | ||
|
|
d9d002c3c1 | ||
|
|
9cc0d4220f | ||
|
|
099bb830cf | ||
|
|
b21bc00704 | ||
|
|
3ca267b546 | ||
|
|
efcecb42f3 | ||
|
|
6b13976330 | ||
|
|
f36132a837 | ||
|
|
6f36cf02e7 | ||
|
|
e2b75586fb | ||
|
|
c1bda097c1 | ||
|
|
8787fd899b | ||
|
|
4c00a4d31e | ||
|
|
6a61f520e2 | ||
|
|
54d9fffa10 | ||
|
|
90a16b119f | ||
|
|
372ffeba21 | ||
|
|
353e9c0c90 | ||
|
|
6fc97c97eb | ||
|
|
66a659bb03 | ||
|
|
52a4b70afd | ||
|
|
5a96056600 | ||
|
|
47fdb74273 | ||
|
|
a0a810ccd4 | ||
|
|
c8cb5fca5e | ||
|
|
8df202ec79 | ||
|
|
3f5fb6fe6d | ||
|
|
ad19f8679e | ||
|
|
3b941befae | ||
|
|
a6a54fa883 | ||
|
|
b55c14cd1f | ||
|
|
80d2f8007c |
12
.travis.yml
12
.travis.yml
@@ -23,15 +23,17 @@ env:
|
||||
- DOCKER_PACKAGES="build-essential libtool cmake autotools-dev automake pkg-config bsdmainutils curl git ca-certificates ccache"
|
||||
matrix:
|
||||
# ARM v7
|
||||
- HOST=arm-linux-gnueabihf PACKAGES="g++-arm-linux-gnueabihf"
|
||||
- HOST=arm-linux-gnueabihf PACKAGES="gperf g++-arm-linux-gnueabihf"
|
||||
# ARM v8
|
||||
- HOST=aarch64-linux-gnu PACKAGES="g++-aarch64-linux-gnu"
|
||||
- HOST=aarch64-linux-gnu PACKAGES="gperf g++-aarch64-linux-gnu"
|
||||
# i686 Win
|
||||
- HOST=i686-w64-mingw32 PACKAGES="python3 nsis g++-mingw-w64-i686"
|
||||
# i686 Linux
|
||||
- HOST=i686-pc-linux-gnu PACKAGES="cmake g++-multilib bc python3-zmq" RUN_TESTS=true
|
||||
- HOST=i686-pc-linux-gnu PACKAGES="gperf cmake g++-multilib bc python3-zmq" RUN_TESTS=true
|
||||
# Win64
|
||||
- HOST=x86_64-w64-mingw32 PACKAGES="cmake python3 nsis g++-mingw-w64-x86-64 wine-binfmt wine64 bc" RUN_TESTS=true
|
||||
# x86_64 Linux
|
||||
- HOST=x86_64-unknown-linux-gnu PACKAGES="cmake python3-zmq protobuf-compiler libdbus-1-dev libharfbuzz-dev libprotobuf-dev" RUN_TESTS=true
|
||||
- HOST=x86_64-unknown-linux-gnu PACKAGES="gperf cmake python3-zmq protobuf-compiler libdbus-1-dev libharfbuzz-dev libprotobuf-dev" RUN_TESTS=true
|
||||
# Cross-Mac
|
||||
- HOST=x86_64-apple-darwin11 PACKAGES="cmake imagemagick libcap-dev librsvg2-bin libz-dev libbz2-dev libtiff-tools python-dev python3-setuptools-git" OSX_SDK=10.11
|
||||
|
||||
@@ -56,7 +58,7 @@ script:
|
||||
- export TRAVIS_COMMIT_LOG=`git log --format=fuller -1`
|
||||
- OUTDIR=$BASE_OUTDIR/$TRAVIS_PULL_REQUEST/$TRAVIS_JOB_NUMBER-$HOST
|
||||
- if [ -z "$NO_DEPENDS" ]; then $DOCKER_EXEC ccache --max-size=$CCACHE_SIZE; fi
|
||||
- $DOCKER_EXEC bash -c "mkdir build && cd build && cmake -DCMAKE_TOOLCHAIN_FILE=$TRAVIS_BUILD_DIR/contrib/depends/$HOST/share/toolchain.cmake .. && make $MAKEJOBS"
|
||||
- $DOCKER_EXEC bash -c "mkdir build && cd build && cmake -DCMAKE_TOOLCHAIN_FILE=$TRAVIS_BUILD_DIR/contrib/depends/$HOST/share/toolchain.cmake -DTRAVIS=true .. && make $MAKEJOBS"
|
||||
- export LD_LIBRARY_PATH=$TRAVIS_BUILD_DIR/contrib/depends/$HOST/lib
|
||||
after_script:
|
||||
- echo $TRAVIS_COMMIT_RANGE
|
||||
|
||||
177
CMakeLists.txt
177
CMakeLists.txt
@@ -40,6 +40,7 @@ if (IOS)
|
||||
endif()
|
||||
|
||||
cmake_minimum_required(VERSION 2.8.7)
|
||||
message(STATUS "CMake version ${CMAKE_VERSION}")
|
||||
|
||||
project(monero)
|
||||
|
||||
@@ -112,6 +113,9 @@ string(TOLOWER ${CMAKE_BUILD_TYPE} CMAKE_BUILD_TYPE_LOWER)
|
||||
# to identify the target architecture, to direct logic in this cmake script.
|
||||
# Since ARCH is a cached variable, it will not be set on first cmake invocation.
|
||||
if (NOT ARCH OR ARCH STREQUAL "" OR ARCH STREQUAL "native" OR ARCH STREQUAL "default")
|
||||
if(CMAKE_SYSTEM_PROCESSOR STREQUAL "")
|
||||
set(CMAKE_SYSTEM_PROCESSOR ${CMAKE_HOST_SYSTEM_PROCESSOR})
|
||||
endif()
|
||||
set(ARCH_ID "${CMAKE_SYSTEM_PROCESSOR}")
|
||||
else()
|
||||
set(ARCH_ID "${ARCH}")
|
||||
@@ -137,9 +141,27 @@ endif()
|
||||
|
||||
if(ARCH_ID STREQUAL "ppc64le")
|
||||
set(PPC64LE 1)
|
||||
set(PPC64 0)
|
||||
set(PPC 0)
|
||||
endif()
|
||||
|
||||
if(WIN32 OR ARM)
|
||||
if(ARCH_ID STREQUAL "powerpc64" OR ARCH_ID STREQUAL "ppc64")
|
||||
set(PPC64LE 0)
|
||||
set(PPC64 1)
|
||||
set(PPC 0)
|
||||
endif()
|
||||
|
||||
if(ARCH_ID STREQUAL "powerpc")
|
||||
set(PPC64LE 0)
|
||||
set(PPC64 0)
|
||||
set(PPC 1)
|
||||
endif()
|
||||
|
||||
if(ARCH_ID STREQUAL "s390x")
|
||||
set(S390X 1)
|
||||
endif()
|
||||
|
||||
if(WIN32 OR ARM OR PPC64LE OR PPC64 OR PPC)
|
||||
set(OPT_FLAGS_RELEASE "-O2")
|
||||
else()
|
||||
set(OPT_FLAGS_RELEASE "-Ofast")
|
||||
@@ -162,6 +184,25 @@ if(NOT MANUAL_SUBMODULES)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(NOT MANUAL_SUBMODULES)
|
||||
find_package(Git)
|
||||
if(GIT_FOUND)
|
||||
message(STATUS "Checking submodules")
|
||||
execute_process(COMMAND bash -c "cd ${CMAKE_CURRENT_SOURCE_DIR}/external/miniupnp && git rev-parse HEAD" OUTPUT_VARIABLE miniupnpLocalHead WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
|
||||
execute_process(COMMAND bash -c "cd ${CMAKE_CURRENT_SOURCE_DIR}/external/unbound && git rev-parse HEAD" OUTPUT_VARIABLE unboundLocalHead WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
|
||||
execute_process(COMMAND bash -c "cd ${CMAKE_CURRENT_SOURCE_DIR}/external/rapidjson && git rev-parse HEAD" OUTPUT_VARIABLE rapidjsonLocalHead WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
|
||||
execute_process(COMMAND bash -c "git ls-tree HEAD ${CMAKE_CURRENT_SOURCE_DIR}/external/miniupnp | awk '{print $3}'" OUTPUT_VARIABLE miniupnpCheckedHead WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
|
||||
execute_process(COMMAND bash -c "git ls-tree HEAD ${CMAKE_CURRENT_SOURCE_DIR}/external/unbound | awk '{print $3}'" OUTPUT_VARIABLE unboundCheckedHead WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
|
||||
execute_process(COMMAND bash -c "git ls-tree HEAD ${CMAKE_CURRENT_SOURCE_DIR}/external/rapidjson | awk '{print $3}'" OUTPUT_VARIABLE rapidjsonCheckedHead WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
|
||||
string(COMPARE EQUAL "${miniupnpLocalHead}" "${miniupnpCheckedHead}" miniupnpUpToDate)
|
||||
string(COMPARE EQUAL "${unboundLocalHead}" "${unboundCheckedHead}" unboundUpToDate)
|
||||
string(COMPARE EQUAL "${rapidjsonLocalHead}" "${rapidjsonCheckedHead}" rapidjsonUpToDate)
|
||||
if (NOT miniupnpUpToDate OR NOT unboundUpToDate OR NOT rapidjsonUpToDate)
|
||||
message(FATAL_ERROR "Submodules not up to date. Please update with git submodule init && git submodule update, or run cmake with -DMANUAL_SUBMODULES=1")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(CMAKE_C_FLAGS_RELEASE "-DNDEBUG ${OPT_FLAGS_RELEASE}")
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "-DNDEBUG ${OPT_FLAGS_RELEASE}")
|
||||
|
||||
@@ -204,7 +245,7 @@ endif()
|
||||
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
|
||||
enable_testing()
|
||||
|
||||
option(BUILD_DOCUMENTATION "Build the Doxygen documentation." ON)
|
||||
option(BUILD_DOCUMENTATION "Build the Doxygen documentation." OFF)
|
||||
option(BUILD_TESTS "Build tests." OFF)
|
||||
|
||||
# Check whether we're on a 32-bit or 64-bit system
|
||||
@@ -399,6 +440,8 @@ if (UNIX AND NOT APPLE)
|
||||
# Note that at the time of this writing the -Wstrict-prototypes flag added below will make this fail
|
||||
set(THREADS_PREFER_PTHREAD_FLAG ON)
|
||||
find_package(Threads)
|
||||
add_c_flag_if_supported(-pthread CMAKE_C_FLAGS)
|
||||
add_cxx_flag_if_supported(-pthread CMAKE_CXX_FLAGS)
|
||||
endif()
|
||||
|
||||
# Handle OpenSSL, used for sha256sum on binary updates and light wallet ssl http
|
||||
@@ -425,7 +468,7 @@ if(STATIC AND NOT IOS)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
find_package(PCSC)
|
||||
find_package(HIDAPI)
|
||||
|
||||
add_definition_if_library_exists(c memset_s "string.h" HAVE_MEMSET_S)
|
||||
add_definition_if_library_exists(c explicit_bzero "strings.h" HAVE_EXPLICIT_BZERO)
|
||||
@@ -446,6 +489,14 @@ ExternalProject_Add(generate_translations_header
|
||||
include_directories("${CMAKE_CURRENT_BINARY_DIR}/translations")
|
||||
add_subdirectory(external)
|
||||
|
||||
# Final setup for miniupnpc
|
||||
if(UPNP_STATIC OR IOS)
|
||||
add_definitions("-DUPNP_STATIC")
|
||||
else()
|
||||
add_definitions("-DUPNP_DYNAMIC")
|
||||
include_directories(${UPNP_INCLUDE})
|
||||
endif()
|
||||
|
||||
# Final setup for libunbound
|
||||
include_directories(${UNBOUND_INCLUDE})
|
||||
link_directories(${UNBOUND_LIBRARY_DIRS})
|
||||
@@ -466,14 +517,14 @@ endif()
|
||||
include_directories(${LIBUNWIND_INCLUDE})
|
||||
link_directories(${LIBUNWIND_LIBRARY_DIRS})
|
||||
|
||||
# Final setup for libpcsc
|
||||
if (PCSC_FOUND)
|
||||
message(STATUS "Using PCSC include dir at ${PCSC_INCLUDE_DIR}")
|
||||
add_definitions(-DHAVE_PCSC)
|
||||
include_directories(${PCSC_INCLUDE_DIR})
|
||||
link_directories(${LIBPCSC_LIBRARY_DIRS})
|
||||
else (PCSC_FOUND)
|
||||
message(STATUS "Could not find PCSC")
|
||||
# Final setup for hid
|
||||
if (HIDAPI_FOUND)
|
||||
message(STATUS "Using HIDAPI include dir at ${HIDAPI_INCLUDE_DIR}")
|
||||
add_definitions(-DHAVE_HIDAPI)
|
||||
include_directories(${HIDAPI_INCLUDE_DIR})
|
||||
link_directories(${LIBHIDAPI_LIBRARY_DIRS})
|
||||
else (HIDAPI_FOUND)
|
||||
message(STATUS "Could not find HIDAPI")
|
||||
endif()
|
||||
|
||||
if(MSVC)
|
||||
@@ -488,16 +539,18 @@ if(MSVC)
|
||||
include_directories(SYSTEM src/platform/msc)
|
||||
else()
|
||||
include(TestCXXAcceptsFlag)
|
||||
if (NOT ARM6)
|
||||
if(NOT DEPENDS OR DEPENDS AND NOT ARM)
|
||||
set(ARCH native CACHE STRING "CPU to build for: -march value or 'default' to not pass -march at all")
|
||||
endif()
|
||||
if (NOT ARCH)
|
||||
set(ARCH native CACHE STRING "CPU to build for: -march value or 'default' to not pass -march at all")
|
||||
endif()
|
||||
message(STATUS "Building on ${CMAKE_SYSTEM_PROCESSOR} for ${ARCH}")
|
||||
if(ARCH STREQUAL "default")
|
||||
set(ARCH_FLAG "")
|
||||
elseif(PPC64LE)
|
||||
set(ARCH_FLAG "-mcpu=${ARCH}")
|
||||
set(ARCH_FLAG "-mcpu=power8")
|
||||
elseif(PPC64)
|
||||
set(ARCH_FLAG "-mcpu=970")
|
||||
elseif(PPC)
|
||||
set(ARCH_FLAG "-mcpu=7400")
|
||||
elseif(IOS AND ARCH STREQUAL "arm64")
|
||||
message(STATUS "IOS: Changing arch from arm64 to armv8")
|
||||
set(ARCH_FLAG "-march=armv8")
|
||||
@@ -515,6 +568,40 @@ else()
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
option(NO_AES "Explicitly disable AES support" ${NO_AES})
|
||||
|
||||
if(NO_AES)
|
||||
message(STATUS "AES support explicitly disabled")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DNO_AES")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DNO_AES")
|
||||
elseif(NOT ARM AND NOT PPC64LE AND NOT PPC64 AND NOT PPC AND NOT S390X)
|
||||
message(STATUS "AES support enabled")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -maes")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -maes")
|
||||
elseif(PPC64LE OR PPC64 OR PPC)
|
||||
message(STATUS "AES support not available on POWER")
|
||||
elseif(S390X)
|
||||
message(STATUS "AES support not available on s390x")
|
||||
elseif(ARM6)
|
||||
message(STATUS "AES support not available on ARMv6")
|
||||
elseif(ARM7)
|
||||
message(STATUS "AES support not available on ARMv7")
|
||||
elseif(ARM8)
|
||||
CHECK_CXX_ACCEPTS_FLAG("-march=${ARCH}+crypto" ARCH_PLUS_CRYPTO)
|
||||
if(ARCH_PLUS_CRYPTO)
|
||||
message(STATUS "Crypto extensions enabled for ARMv8")
|
||||
set(ARCH_FLAG "-march=${ARCH}+crypto")
|
||||
else()
|
||||
message(STATUS "Crypto extensions unavailable on your ARMv8 device")
|
||||
endif()
|
||||
else()
|
||||
message(STATUS "AES support disabled")
|
||||
endif()
|
||||
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${ARCH_FLAG}")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${ARCH_FLAG}")
|
||||
|
||||
set(WARNINGS "-Wall -Wextra -Wpointer-arith -Wundef -Wvla -Wwrite-strings -Wno-error=extra -Wno-error=deprecated-declarations -Wno-unused-parameter -Wno-unused-variable -Wno-error=unused-variable -Wno-error=undef -Wno-error=uninitialized")
|
||||
if(NOT MINGW)
|
||||
set(WARNINGS_AS_ERRORS_FLAG "-Werror")
|
||||
@@ -586,6 +673,14 @@ else()
|
||||
add_cxx_flag_if_supported(-fstack-protector-strong CXX_SECURITY_FLAGS)
|
||||
endif()
|
||||
|
||||
# New in GCC 8.2
|
||||
if (NOT WIN32)
|
||||
add_c_flag_if_supported(-fcf-protection=full C_SECURITY_FLAGS)
|
||||
add_cxx_flag_if_supported(-fcf-protection=full CXX_SECURITY_FLAGS)
|
||||
add_c_flag_if_supported(-fstack-clash-protection C_SECURITY_FLAGS)
|
||||
add_cxx_flag_if_supported(-fstack-clash-protection CXX_SECURITY_FLAGS)
|
||||
endif()
|
||||
|
||||
add_c_flag_if_supported(-mmitigate-rop C_SECURITY_FLAGS)
|
||||
add_cxx_flag_if_supported(-mmitigate-rop CXX_SECURITY_FLAGS)
|
||||
|
||||
@@ -617,36 +712,8 @@ else()
|
||||
message(STATUS "Using C++ security hardening flags: ${CXX_SECURITY_FLAGS}")
|
||||
message(STATUS "Using linker security hardening flags: ${LD_SECURITY_FLAGS}")
|
||||
|
||||
option(NO_AES "Explicitly disable AES support" ${NO_AES})
|
||||
|
||||
if(NO_AES)
|
||||
message(STATUS "AES support explicitly disabled")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DNO_AES")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DNO_AES")
|
||||
elseif(NOT ARM AND NOT PPC64LE)
|
||||
message(STATUS "AES support enabled")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -maes")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -maes")
|
||||
elseif(PPC64LE)
|
||||
message(STATUS "AES support not available on ppc64le")
|
||||
elseif(ARM6)
|
||||
message(STATUS "AES support not available on ARMv6")
|
||||
elseif(ARM7)
|
||||
message(STATUS "AES support not available on ARMv7")
|
||||
elseif(ARM8)
|
||||
CHECK_CXX_ACCEPTS_FLAG("-march=${ARCH}+crypto" ARCH_PLUS_CRYPTO)
|
||||
if(ARCH_PLUS_CRYPTO)
|
||||
message(STATUS "Crypto extensions enabled for ARMv8")
|
||||
set(ARCH_FLAG "-march=${ARCH}+crypto")
|
||||
else()
|
||||
message(STATUS "Crypto extensions unavailable on your ARMv8 device")
|
||||
endif()
|
||||
else()
|
||||
message(STATUS "AES support disabled")
|
||||
endif()
|
||||
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c11 -D_GNU_SOURCE ${MINGW_FLAG} ${STATIC_ASSERT_FLAG} ${WARNINGS} ${C_WARNINGS} ${ARCH_FLAG} ${COVERAGE_FLAGS} ${PIC_FLAG} ${C_SECURITY_FLAGS}")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -D_GNU_SOURCE ${MINGW_FLAG} ${STATIC_ASSERT_CPP_FLAG} ${WARNINGS} ${CXX_WARNINGS} ${ARCH_FLAG} ${COVERAGE_FLAGS} ${PIC_FLAG} ${CXX_SECURITY_FLAGS}")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c11 -D_GNU_SOURCE ${MINGW_FLAG} ${STATIC_ASSERT_FLAG} ${WARNINGS} ${C_WARNINGS} ${COVERAGE_FLAGS} ${PIC_FLAG} ${C_SECURITY_FLAGS}")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -D_GNU_SOURCE ${MINGW_FLAG} ${STATIC_ASSERT_CPP_FLAG} ${WARNINGS} ${CXX_WARNINGS} ${COVERAGE_FLAGS} ${PIC_FLAG} ${CXX_SECURITY_FLAGS}")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${LD_SECURITY_FLAGS}")
|
||||
|
||||
# With GCC 6.1.1 the compiled binary malfunctions due to aliasing. Until that
|
||||
@@ -745,7 +812,7 @@ else()
|
||||
endif()
|
||||
|
||||
if(APPLE)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden -DGTEST_HAS_TR1_TUPLE=0")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=default -DGTEST_HAS_TR1_TUPLE=0")
|
||||
endif()
|
||||
|
||||
set(DEBUG_FLAGS "-g3")
|
||||
@@ -857,6 +924,22 @@ endif()
|
||||
|
||||
list(APPEND EXTRA_LIBRARIES ${CMAKE_DL_LIBS})
|
||||
|
||||
if (HIDAPI_FOUND)
|
||||
if (APPLE)
|
||||
if(DEPENDS)
|
||||
list(APPEND EXTRA_LIBRARIES "-framework Foundation -framework IOKit")
|
||||
else()
|
||||
find_library(COREFOUNDATION CoreFoundation)
|
||||
find_library(IOKIT IOKit)
|
||||
list(APPEND EXTRA_LIBRARIES ${IOKIT})
|
||||
list(APPEND EXTRA_LIBRARIES ${COREFOUNDATION})
|
||||
endif()
|
||||
endif()
|
||||
if (WIN32)
|
||||
list(APPEND EXTRA_LIBRARIES setupapi)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
option(USE_READLINE "Build with GNU readline support." ON)
|
||||
if(USE_READLINE)
|
||||
find_package(Readline)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Contributing to Monero
|
||||
|
||||
A good way to help is to test, and report bugs. See
|
||||
[How to Report Bugs Effectively (by Simon Tatham)](http://www.chiark.greenend.org.uk/~sgtatham/bugs.html)
|
||||
[How to Report Bugs Effectively (by Simon Tatham)](https://www.chiark.greenend.org.uk/~sgtatham/bugs.html)
|
||||
if you want to help that way. Testing is invaluable in making a piece
|
||||
of software solid and usable.
|
||||
|
||||
|
||||
17
Dockerfile
17
Dockerfile
@@ -23,9 +23,9 @@ RUN set -ex && \
|
||||
WORKDIR /usr/local
|
||||
|
||||
#Cmake
|
||||
ARG CMAKE_VERSION=3.11.4
|
||||
ARG CMAKE_VERSION_DOT=v3.11
|
||||
ARG CMAKE_HASH=8f864e9f78917de3e1483e256270daabc4a321741592c5b36af028e72bff87f5
|
||||
ARG CMAKE_VERSION=3.12.1
|
||||
ARG CMAKE_VERSION_DOT=v3.12
|
||||
ARG CMAKE_HASH=c53d5c2ce81d7a957ee83e3e635c8cda5dfe20c9d501a4828ee28e1615e57ab2
|
||||
RUN set -ex \
|
||||
&& curl -s -O https://cmake.org/files/${CMAKE_VERSION_DOT}/cmake-${CMAKE_VERSION}.tar.gz \
|
||||
&& echo "${CMAKE_HASH} cmake-${CMAKE_VERSION}.tar.gz" | sha256sum -c \
|
||||
@@ -36,9 +36,9 @@ RUN set -ex \
|
||||
&& make install
|
||||
|
||||
## Boost
|
||||
ARG BOOST_VERSION=1_67_0
|
||||
ARG BOOST_VERSION_DOT=1.67.0
|
||||
ARG BOOST_HASH=2684c972994ee57fc5632e03bf044746f6eb45d4920c343937a465fd67a5adba
|
||||
ARG BOOST_VERSION=1_68_0
|
||||
ARG BOOST_VERSION_DOT=1.68.0
|
||||
ARG BOOST_HASH=7f6130bc3cf65f56a618888ce9d5ea704fa10b462be126ad053e80e553d6d8b7
|
||||
RUN set -ex \
|
||||
&& curl -s -L -o boost_${BOOST_VERSION}.tar.bz2 https://dl.bintray.com/boostorg/release/${BOOST_VERSION_DOT}/source/boost_${BOOST_VERSION}.tar.bz2 \
|
||||
&& echo "${BOOST_HASH} boost_${BOOST_VERSION}.tar.bz2" | sha256sum -c \
|
||||
@@ -112,8 +112,10 @@ RUN set -ex \
|
||||
WORKDIR /src
|
||||
COPY . .
|
||||
|
||||
ENV USE_SINGLE_BUILDDIR=1
|
||||
ARG NPROC
|
||||
RUN set -ex && \
|
||||
git submodule init && git submodule update && \
|
||||
rm -rf build && \
|
||||
if [ -z "$NPROC" ] ; \
|
||||
then make -j$(nproc) release-static ; \
|
||||
@@ -128,8 +130,7 @@ RUN set -ex && \
|
||||
apt-get --no-install-recommends --yes install ca-certificates && \
|
||||
apt-get clean && \
|
||||
rm -rf /var/lib/apt
|
||||
|
||||
COPY --from=builder /src/build/release/bin/* /usr/local/bin/
|
||||
COPY --from=builder /src/build/release/bin /usr/local/bin/
|
||||
|
||||
# Contains the blockchain
|
||||
VOLUME /root/.bitmonero
|
||||
|
||||
50
Doxyfile
50
Doxyfile
@@ -20,7 +20,7 @@
|
||||
# This tag specifies the encoding used for all characters in the config file
|
||||
# that follow. The default is UTF-8 which is also the encoding used for all text
|
||||
# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv
|
||||
# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv
|
||||
# built into libc) for the transcoding. See https://www.gnu.org/software/libiconv
|
||||
# for the list of possible encodings.
|
||||
# The default value is: UTF-8.
|
||||
|
||||
@@ -285,7 +285,7 @@ EXTENSION_MAPPING =
|
||||
|
||||
# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
|
||||
# according to the Markdown format, which allows for more readable
|
||||
# documentation. See http://daringfireball.net/projects/markdown/ for details.
|
||||
# documentation. See https://daringfireball.net/projects/markdown/ for details.
|
||||
# The output of markdown processing is further processed by doxygen, so you can
|
||||
# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
|
||||
# case of backward compatibilities issues.
|
||||
@@ -318,7 +318,7 @@ BUILTIN_STL_SUPPORT = NO
|
||||
CPP_CLI_SUPPORT = NO
|
||||
|
||||
# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
|
||||
# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen
|
||||
# https://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen
|
||||
# will parse them like normal C++ but will assume all classes use public instead
|
||||
# of private inheritance when no explicit protection keyword is present.
|
||||
# The default value is: NO.
|
||||
@@ -677,7 +677,7 @@ LAYOUT_FILE =
|
||||
# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
|
||||
# the reference definitions. This must be a list of .bib files. The .bib
|
||||
# extension is automatically appended if omitted. This requires the bibtex tool
|
||||
# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info.
|
||||
# to be installed. See also https://en.wikipedia.org/wiki/BibTeX for more info.
|
||||
# For LaTeX the style of the bibliography can be controlled using
|
||||
# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
|
||||
# search path. Do not use file names with spaces, bibtex cannot handle them. See
|
||||
@@ -759,7 +759,7 @@ INPUT = src
|
||||
# This tag can be used to specify the character encoding of the source files
|
||||
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
|
||||
# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
|
||||
# documentation (see: http://www.gnu.org/software/libiconv) for the list of
|
||||
# documentation (see: https://www.gnu.org/software/libiconv) for the list of
|
||||
# possible encodings.
|
||||
# The default value is: UTF-8.
|
||||
|
||||
@@ -951,7 +951,7 @@ SOURCE_TOOLTIPS = YES
|
||||
# If the USE_HTAGS tag is set to YES then the references to source code will
|
||||
# point to the HTML generated by the htags(1) tool instead of doxygen built-in
|
||||
# source browser. The htags tool is part of GNU's global source tagging system
|
||||
# (see http://www.gnu.org/software/global/global.html). You will need version
|
||||
# (see https://www.gnu.org/software/global/global.html). You will need version
|
||||
# 4.8.6 or higher.
|
||||
#
|
||||
# To use it do the following:
|
||||
@@ -1094,7 +1094,7 @@ HTML_EXTRA_FILES =
|
||||
# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
|
||||
# will adjust the colors in the stylesheet and background images according to
|
||||
# this color. Hue is specified as an angle on a colorwheel, see
|
||||
# http://en.wikipedia.org/wiki/Hue for more information. For instance the value
|
||||
# https://en.wikipedia.org/wiki/Hue for more information. For instance the value
|
||||
# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
|
||||
# purple, and 360 is red again.
|
||||
# Minimum value: 0, maximum value: 359, default value: 220.
|
||||
@@ -1152,12 +1152,12 @@ HTML_INDEX_NUM_ENTRIES = 100
|
||||
|
||||
# If the GENERATE_DOCSET tag is set to YES, additional index files will be
|
||||
# generated that can be used as input for Apple's Xcode 3 integrated development
|
||||
# environment (see: http://developer.apple.com/tools/xcode/), introduced with
|
||||
# environment (see: https://developer.apple.com/tools/xcode/), introduced with
|
||||
# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a
|
||||
# Makefile in the HTML output directory. Running make will produce the docset in
|
||||
# that directory and running make install will install the docset in
|
||||
# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
|
||||
# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
|
||||
# startup. See https://developer.apple.com/tools/creatingdocsetswithdoxygen.html
|
||||
# for more information.
|
||||
# The default value is: NO.
|
||||
# This tag requires that the tag GENERATE_HTML is set to YES.
|
||||
@@ -1197,7 +1197,7 @@ DOCSET_PUBLISHER_NAME = Publisher
|
||||
# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
|
||||
# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
|
||||
# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
|
||||
# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on
|
||||
# (see: https://www.microsoft.com/en-us/download/details.aspx?id=21138) on
|
||||
# Windows.
|
||||
#
|
||||
# The HTML Help Workshop contains a compiler that can convert all HTML output
|
||||
@@ -1273,7 +1273,7 @@ QCH_FILE =
|
||||
|
||||
# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
|
||||
# Project output. For more information please see Qt Help Project / Namespace
|
||||
# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace).
|
||||
# (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace).
|
||||
# The default value is: org.doxygen.Project.
|
||||
# This tag requires that the tag GENERATE_QHP is set to YES.
|
||||
|
||||
@@ -1281,7 +1281,7 @@ QHP_NAMESPACE = org.doxygen.Project
|
||||
|
||||
# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
|
||||
# Help Project output. For more information please see Qt Help Project / Virtual
|
||||
# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual-
|
||||
# Folders (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual-
|
||||
# folders).
|
||||
# The default value is: doc.
|
||||
# This tag requires that the tag GENERATE_QHP is set to YES.
|
||||
@@ -1290,7 +1290,7 @@ QHP_VIRTUAL_FOLDER = doc
|
||||
|
||||
# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
|
||||
# filter to add. For more information please see Qt Help Project / Custom
|
||||
# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
|
||||
# Filters (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-
|
||||
# filters).
|
||||
# This tag requires that the tag GENERATE_QHP is set to YES.
|
||||
|
||||
@@ -1298,7 +1298,7 @@ QHP_CUST_FILTER_NAME =
|
||||
|
||||
# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
|
||||
# custom filter to add. For more information please see Qt Help Project / Custom
|
||||
# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
|
||||
# Filters (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-
|
||||
# filters).
|
||||
# This tag requires that the tag GENERATE_QHP is set to YES.
|
||||
|
||||
@@ -1306,7 +1306,7 @@ QHP_CUST_FILTER_ATTRS =
|
||||
|
||||
# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
|
||||
# project's filter section matches. Qt Help Project / Filter Attributes (see:
|
||||
# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes).
|
||||
# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#filter-attributes).
|
||||
# This tag requires that the tag GENERATE_QHP is set to YES.
|
||||
|
||||
QHP_SECT_FILTER_ATTRS =
|
||||
@@ -1411,7 +1411,7 @@ FORMULA_FONTSIZE = 10
|
||||
FORMULA_TRANSPARENT = YES
|
||||
|
||||
# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
|
||||
# http://www.mathjax.org) which uses client side Javascript for the rendering
|
||||
# https://www.mathjax.org) which uses client side Javascript for the rendering
|
||||
# instead of using prerendered bitmaps. Use this if you do not have LaTeX
|
||||
# installed or if you want to formulas look prettier in the HTML output. When
|
||||
# enabled you may also need to install MathJax separately and configure the path
|
||||
@@ -1423,7 +1423,7 @@ USE_MATHJAX = NO
|
||||
|
||||
# When MathJax is enabled you can set the default output format to be used for
|
||||
# the MathJax output. See the MathJax site (see:
|
||||
# http://docs.mathjax.org/en/latest/output.html) for more details.
|
||||
# https://docs.mathjax.org/en/latest/output.html) for more details.
|
||||
# Possible values are: HTML-CSS (which is slower, but has the best
|
||||
# compatibility), NativeMML (i.e. MathML) and SVG.
|
||||
# The default value is: HTML-CSS.
|
||||
@@ -1438,11 +1438,11 @@ MATHJAX_FORMAT = HTML-CSS
|
||||
# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
|
||||
# Content Delivery Network so you can quickly see the result without installing
|
||||
# MathJax. However, it is strongly recommended to install a local copy of
|
||||
# MathJax from http://www.mathjax.org before deployment.
|
||||
# The default value is: http://cdn.mathjax.org/mathjax/latest.
|
||||
# MathJax from https://www.mathjax.org before deployment.
|
||||
# The default value is: https://cdn.mathjax.org/mathjax/latest.
|
||||
# This tag requires that the tag USE_MATHJAX is set to YES.
|
||||
|
||||
MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest
|
||||
MATHJAX_RELPATH = https://cdn.mathjax.org/mathjax/latest
|
||||
|
||||
# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
|
||||
# extension names that should be enabled during MathJax rendering. For example
|
||||
@@ -1453,7 +1453,7 @@ MATHJAX_EXTENSIONS =
|
||||
|
||||
# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
|
||||
# of code that will be used on startup of the MathJax code. See the MathJax site
|
||||
# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an
|
||||
# (see: https://docs.mathjax.org/en/latest/output.html) for more details. For an
|
||||
# example see the documentation.
|
||||
# This tag requires that the tag USE_MATHJAX is set to YES.
|
||||
|
||||
@@ -1500,7 +1500,7 @@ SERVER_BASED_SEARCH = NO
|
||||
#
|
||||
# Doxygen ships with an example indexer ( doxyindexer) and search engine
|
||||
# (doxysearch.cgi) which are based on the open source search engine library
|
||||
# Xapian (see: http://xapian.org/).
|
||||
# Xapian (see: https://xapian.org/).
|
||||
#
|
||||
# See the section "External Indexing and Searching" for details.
|
||||
# The default value is: NO.
|
||||
@@ -1513,7 +1513,7 @@ EXTERNAL_SEARCH = NO
|
||||
#
|
||||
# Doxygen ships with an example indexer ( doxyindexer) and search engine
|
||||
# (doxysearch.cgi) which are based on the open source search engine library
|
||||
# Xapian (see: http://xapian.org/). See the section "External Indexing and
|
||||
# Xapian (see: https://xapian.org/). See the section "External Indexing and
|
||||
# Searching" for details.
|
||||
# This tag requires that the tag SEARCHENGINE is set to YES.
|
||||
|
||||
@@ -1684,7 +1684,7 @@ LATEX_SOURCE_CODE = NO
|
||||
|
||||
# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
|
||||
# bibliography, e.g. plainnat, or ieeetr. See
|
||||
# http://en.wikipedia.org/wiki/BibTeX and \cite for more info.
|
||||
# https://en.wikipedia.org/wiki/BibTeX and \cite for more info.
|
||||
# The default value is: plain.
|
||||
# This tag requires that the tag GENERATE_LATEX is set to YES.
|
||||
|
||||
@@ -2051,7 +2051,7 @@ HIDE_UNDOC_RELATIONS = YES
|
||||
|
||||
# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
|
||||
# available from the path. This tool is part of Graphviz (see:
|
||||
# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
|
||||
# https://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
|
||||
# Bell Labs. The other options in this section have no effect if this option is
|
||||
# set to NO
|
||||
# The default value is: NO.
|
||||
|
||||
129
Makefile
129
Makefile
@@ -28,104 +28,139 @@
|
||||
|
||||
ANDROID_STANDALONE_TOOLCHAIN_PATH ?= /usr/local/toolchain
|
||||
|
||||
dotgit=$(shell ls -d .git/config)
|
||||
ifneq ($(dotgit), .git/config)
|
||||
USE_SINGLE_BUILDDIR=1
|
||||
endif
|
||||
|
||||
subbuilddir:=$(shell echo `uname | sed -e 's|[:/\\ \(\)]|_|g'`/`git branch | grep '\* ' | cut -f2- -d' '| sed -e 's|[:/\\ \(\)]|_|g'`)
|
||||
ifeq ($(USE_SINGLE_BUILDDIR),)
|
||||
builddir := build/"$(subbuilddir)"
|
||||
topdir := ../../../..
|
||||
deldirs := $(builddir)
|
||||
else
|
||||
builddir := build
|
||||
topdir := ../..
|
||||
deldirs := $(builddir)/debug $(builddir)/release $(builddir)/fuzz
|
||||
endif
|
||||
|
||||
all: release-all
|
||||
|
||||
cmake-debug:
|
||||
mkdir -p build/debug
|
||||
cd build/debug && cmake -D CMAKE_BUILD_TYPE=Debug ../..
|
||||
mkdir -p $(builddir)/debug
|
||||
cd $(builddir)/debug && cmake -D BUILD_TESTS=ON -D CMAKE_BUILD_TYPE=Debug $(topdir)
|
||||
|
||||
debug: cmake-debug
|
||||
cd build/debug && $(MAKE)
|
||||
cd $(builddir)/debug && $(MAKE)
|
||||
|
||||
# Temporarily disable some tests:
|
||||
# * libwallet_api_tests fail (Issue #895)
|
||||
debug-test:
|
||||
mkdir -p build/debug
|
||||
cd build/debug && cmake -D BUILD_TESTS=ON -D CMAKE_BUILD_TYPE=Debug ../.. && $(MAKE) && $(MAKE) ARGS="-E libwallet_api_tests" test
|
||||
mkdir -p $(builddir)/debug
|
||||
cd $(builddir)/debug && cmake -D BUILD_TESTS=ON -D CMAKE_BUILD_TYPE=Debug $(topdir) && $(MAKE) && $(MAKE) ARGS="-E libwallet_api_tests" test
|
||||
|
||||
debug-all:
|
||||
mkdir -p build/debug
|
||||
cd build/debug && cmake -D BUILD_TESTS=ON -D BUILD_SHARED_LIBS=OFF -D CMAKE_BUILD_TYPE=Debug ../.. && $(MAKE)
|
||||
mkdir -p $(builddir)/debug
|
||||
cd $(builddir)/debug && cmake -D BUILD_TESTS=OFF -D BUILD_SHARED_LIBS=OFF -D CMAKE_BUILD_TYPE=Debug $(topdir) && $(MAKE)
|
||||
|
||||
debug-static-all:
|
||||
mkdir -p build/debug
|
||||
cd build/debug && cmake -D BUILD_TESTS=ON -D STATIC=ON -D CMAKE_BUILD_TYPE=Debug ../.. && $(MAKE)
|
||||
mkdir -p $(builddir)/debug
|
||||
cd $(builddir)/debug && cmake -D BUILD_TESTS=ON -D STATIC=ON -D CMAKE_BUILD_TYPE=Debug $(topdir) && $(MAKE)
|
||||
|
||||
debug-static-win64:
|
||||
mkdir -p $(builddir)/debug
|
||||
cd $(builddir)/debug && cmake -G "MSYS Makefiles" -D STATIC=ON -D ARCH="x86-64" -D BUILD_64=ON -D CMAKE_BUILD_TYPE=Debug -D BUILD_TAG="win-x64" -D CMAKE_TOOLCHAIN_FILE=$(topdir)/cmake/64-bit-toolchain.cmake -D MSYS2_FOLDER=c:/msys64 $(topdir) && $(MAKE)
|
||||
|
||||
debug-static-win32:
|
||||
mkdir -p $(builddir)/debug
|
||||
cd $(builddir)/debug && cmake -G "MSYS Makefiles" -D STATIC=ON -D ARCH="i686" -D BUILD_64=OFF -D CMAKE_BUILD_TYPE=Debug -D BUILD_TAG="win-x32" -D CMAKE_TOOLCHAIN_FILE=$(topdir)/cmake/32-bit-toolchain.cmake -D MSYS2_FOLDER=c:/msys32 $(topdir) && $(MAKE)
|
||||
|
||||
cmake-release:
|
||||
mkdir -p build/release
|
||||
cd build/release && cmake -D CMAKE_BUILD_TYPE=Release ../..
|
||||
mkdir -p $(builddir)/release
|
||||
cd $(builddir)/release && cmake -D BUILD_TESTS=OFF -D CMAKE_BUILD_TYPE=Release $(topdir)
|
||||
|
||||
release: cmake-release
|
||||
cd build/release && $(MAKE)
|
||||
cd $(builddir)/release && $(MAKE)
|
||||
|
||||
release-test:
|
||||
mkdir -p build/release
|
||||
cd build/release && cmake -D BUILD_TESTS=ON -D CMAKE_BUILD_TYPE=release ../.. && $(MAKE) && $(MAKE) test
|
||||
mkdir -p $(builddir)/release
|
||||
cd $(builddir)/release && cmake -D BUILD_TESTS=ON -D CMAKE_BUILD_TYPE=release $(topdir) && $(MAKE) && $(MAKE) test
|
||||
|
||||
release-all:
|
||||
mkdir -p build/release
|
||||
cd build/release && cmake -D BUILD_TESTS=OFF -D CMAKE_BUILD_TYPE=release ../.. && $(MAKE)
|
||||
mkdir -p $(builddir)/release
|
||||
cd $(builddir)/release && cmake -D BUILD_TESTS=OFF -D CMAKE_BUILD_TYPE=release $(topdir) && $(MAKE)
|
||||
|
||||
release-static:
|
||||
mkdir -p build/release
|
||||
cd build/release && cmake -D STATIC=ON -D ARCH="x86-64" -D BUILD_64=ON -D CMAKE_BUILD_TYPE=release ../.. && $(MAKE)
|
||||
mkdir -p $(builddir)/release
|
||||
cd $(builddir)/release && cmake -D BUILD_TESTS=OFF -D STATIC=ON -D ARCH="x86-64" -D BUILD_64=ON -D CMAKE_BUILD_TYPE=release $(topdir) && $(MAKE)
|
||||
|
||||
coverage:
|
||||
mkdir -p build/debug
|
||||
cd build/debug && cmake -D BUILD_TESTS=ON -D CMAKE_BUILD_TYPE=Debug -D COVERAGE=ON ../.. && $(MAKE) && $(MAKE) test
|
||||
mkdir -p $(builddir)/debug
|
||||
cd $(builddir)/debug && cmake -D BUILD_TESTS=ON -D CMAKE_BUILD_TYPE=Debug -D COVERAGE=ON $(topdir) && $(MAKE) && $(MAKE) test
|
||||
|
||||
# Targets for specific prebuilt builds which will be advertised for updates by their build tag
|
||||
|
||||
release-static-linux-armv6:
|
||||
mkdir -p build/release
|
||||
cd build/release && cmake -D BUILD_TESTS=OFF -D ARCH="armv6zk" -D STATIC=ON -D BUILD_64=OFF -D CMAKE_BUILD_TYPE=release -D BUILD_TAG="linux-armv6" ../.. && $(MAKE)
|
||||
mkdir -p $(builddir)/release
|
||||
cd $(builddir)/release && cmake -D BUILD_TESTS=OFF -D ARCH="armv6zk" -D STATIC=ON -D BUILD_64=OFF -D CMAKE_BUILD_TYPE=release -D BUILD_TAG="linux-armv6" $(topdir) && $(MAKE)
|
||||
|
||||
release-static-linux-armv7:
|
||||
mkdir -p build/release
|
||||
cd build/release && cmake -D BUILD_TESTS=OFF -D ARCH="armv7-a" -D STATIC=ON -D BUILD_64=OFF -D CMAKE_BUILD_TYPE=release -D BUILD_TAG="linux-armv7" ../.. && $(MAKE)
|
||||
mkdir -p $(builddir)/release
|
||||
cd $(builddir)/release && cmake -D BUILD_TESTS=OFF -D ARCH="armv7-a" -D STATIC=ON -D BUILD_64=OFF -D CMAKE_BUILD_TYPE=release -D BUILD_TAG="linux-armv7" $(topdir) && $(MAKE)
|
||||
|
||||
release-static-android:
|
||||
mkdir -p build/release/translations
|
||||
cd build/release/translations && cmake ../../../translations && $(MAKE)
|
||||
cd build/release && CC=arm-linux-androideabi-clang CXX=arm-linux-androideabi-clang++ cmake -D BUILD_TESTS=OFF -D ARCH="armv7-a" -D STATIC=ON -D BUILD_64=OFF -D CMAKE_BUILD_TYPE=release -D ANDROID=true -D INSTALL_VENDORED_LIBUNBOUND=ON -D BUILD_TAG="android" -D CMAKE_SYSTEM_NAME="Android" -D CMAKE_ANDROID_STANDALONE_TOOLCHAIN="${ANDROID_STANDALONE_TOOLCHAIN_PATH}" -D CMAKE_ANDROID_ARM_MODE=ON -D CMAKE_ANDROID_ARCH_ABI="armeabi-v7a" ../.. && $(MAKE)
|
||||
release-static-android-armv7:
|
||||
mkdir -p $(builddir)/release/translations
|
||||
cd $(builddir)/release/translations && cmake ../../../translations && $(MAKE)
|
||||
cd $(builddir)/release && CC=arm-linux-androideabi-clang CXX=arm-linux-androideabi-clang++ cmake -D BUILD_TESTS=OFF -D ARCH="armv7-a" -D STATIC=ON -D BUILD_64=OFF -D CMAKE_BUILD_TYPE=release -D ANDROID=true -D INSTALL_VENDORED_LIBUNBOUND=ON -D BUILD_TAG="android-armv7" -D CMAKE_SYSTEM_NAME="Android" -D CMAKE_ANDROID_STANDALONE_TOOLCHAIN="${ANDROID_STANDALONE_TOOLCHAIN_PATH}" -D CMAKE_ANDROID_ARM_MODE=ON -D CMAKE_ANDROID_ARCH_ABI="armeabi-v7a" ../.. && $(MAKE)
|
||||
|
||||
release-static-android-armv8:
|
||||
mkdir -p $(builddir)/release/translations
|
||||
cd $(builddir)/release/translations && cmake ../../../translations && $(MAKE)
|
||||
cd $(builddir)/release && CC=aarch64-linux-android-clang CXX=aarch64-linux-android-clang++ cmake -D BUILD_TESTS=OFF -D ARCH="armv8-a" -D STATIC=ON -D BUILD_64=ON -D CMAKE_BUILD_TYPE=release -D ANDROID=true -D INSTALL_VENDORED_LIBUNBOUND=ON -D BUILD_TAG="android-armv8" -D CMAKE_SYSTEM_NAME="Android" -D CMAKE_ANDROID_STANDALONE_TOOLCHAIN="${ANDROID_STANDALONE_TOOLCHAIN_PATH}" -D CMAKE_ANDROID_ARCH_ABI="arm64-v8a" ../.. && $(MAKE)
|
||||
|
||||
release-static-linux-armv8:
|
||||
mkdir -p build/release
|
||||
cd build/release && cmake -D BUILD_TESTS=OFF -D ARCH="armv8-a" -D STATIC=ON -D BUILD_64=ON -D CMAKE_BUILD_TYPE=release -D BUILD_TAG="linux-armv8" ../.. && $(MAKE)
|
||||
mkdir -p $(builddir)/release
|
||||
cd $(builddir)/release && cmake -D BUILD_TESTS=OFF -D ARCH="armv8-a" -D STATIC=ON -D BUILD_64=ON -D CMAKE_BUILD_TYPE=release -D BUILD_TAG="linux-armv8" $(topdir) && $(MAKE)
|
||||
|
||||
release-static-linux-x86_64:
|
||||
mkdir -p build/release
|
||||
cd build/release && cmake -D BUILD_TESTS=OFF STATIC=ON -D ARCH="x86-64" -D BUILD_64=ON -D CMAKE_BUILD_TYPE=release -D BUILD_TAG="linux-x64" ../.. && $(MAKE)
|
||||
mkdir -p $(builddir)/release
|
||||
cd $(builddir)/release && cmake -D STATIC=ON -D ARCH="x86-64" -D BUILD_64=ON -D CMAKE_BUILD_TYPE=release -D BUILD_TAG="linux-x64" $(topdir) && $(MAKE)
|
||||
|
||||
release-static-freebsd-x86_64:
|
||||
mkdir -p build/release
|
||||
cd build/release && cmake -D STATIC=ON -D ARCH="x86-64" -D BUILD_64=ON -D CMAKE_BUILD_TYPE=release -D BUILD_TAG="freebsd-x64" ../.. && $(MAKE)
|
||||
mkdir -p $(builddir)/release
|
||||
cd $(builddir)/release && cmake -D STATIC=ON -D ARCH="x86-64" -D BUILD_64=ON -D CMAKE_BUILD_TYPE=release -D BUILD_TAG="freebsd-x64" $(topdir) && $(MAKE)
|
||||
|
||||
release-static-mac-x86_64:
|
||||
mkdir -p build/release
|
||||
cd build/release && cmake -D STATIC=ON -D ARCH="x86-64" -D BUILD_64=ON -D CMAKE_BUILD_TYPE=release -D BUILD_TAG="mac-x64" ../.. && $(MAKE)
|
||||
mkdir -p $(builddir)/release
|
||||
cd $(builddir)/release && cmake -D STATIC=ON -D ARCH="x86-64" -D BUILD_64=ON -D CMAKE_BUILD_TYPE=release -D BUILD_TAG="mac-x64" $(topdir) && $(MAKE)
|
||||
|
||||
release-static-linux-i686:
|
||||
mkdir -p build/release
|
||||
cd build/release && cmake -D STATIC=ON -D ARCH="i686" -D BUILD_64=OFF -D CMAKE_BUILD_TYPE=release -D BUILD_TAG="linux-x86" ../.. && $(MAKE)
|
||||
mkdir -p $(builddir)/release
|
||||
cd $(builddir)/release && cmake -D STATIC=ON -D ARCH="i686" -D BUILD_64=OFF -D CMAKE_BUILD_TYPE=release -D BUILD_TAG="linux-x86" $(topdir) && $(MAKE)
|
||||
|
||||
release-static-win64:
|
||||
mkdir -p build/release
|
||||
cd build/release && cmake -G "MSYS Makefiles" -D STATIC=ON -D ARCH="x86-64" -D BUILD_64=ON -D CMAKE_BUILD_TYPE=Release -D BUILD_TAG="win-x64" -D CMAKE_TOOLCHAIN_FILE=../../cmake/64-bit-toolchain.cmake -D MSYS2_FOLDER=c:/msys64 ../.. && $(MAKE)
|
||||
mkdir -p $(builddir)/release
|
||||
cd $(builddir)/release && cmake -G "MSYS Makefiles" -D STATIC=ON -D ARCH="x86-64" -D BUILD_64=ON -D CMAKE_BUILD_TYPE=Release -D BUILD_TAG="win-x64" -D CMAKE_TOOLCHAIN_FILE=$(topdir)/cmake/64-bit-toolchain.cmake -D MSYS2_FOLDER=c:/msys64 $(topdir) && $(MAKE)
|
||||
|
||||
release-static-win32:
|
||||
mkdir -p build/release
|
||||
cd build/release && cmake -G "MSYS Makefiles" -D STATIC=ON -D ARCH="i686" -D BUILD_64=OFF -D CMAKE_BUILD_TYPE=Release -D BUILD_TAG="win-x32" -D CMAKE_TOOLCHAIN_FILE=../../cmake/32-bit-toolchain.cmake -D MSYS2_FOLDER=c:/msys32 ../.. && $(MAKE)
|
||||
mkdir -p $(builddir)/release
|
||||
cd $(builddir)/release && cmake -G "MSYS Makefiles" -D STATIC=ON -D ARCH="i686" -D BUILD_64=OFF -D CMAKE_BUILD_TYPE=Release -D BUILD_TAG="win-x32" -D CMAKE_TOOLCHAIN_FILE=$(topdir)/cmake/32-bit-toolchain.cmake -D MSYS2_FOLDER=c:/msys32 $(topdir) && $(MAKE)
|
||||
|
||||
fuzz:
|
||||
mkdir -p build/fuzz
|
||||
cd build/fuzz && cmake -D STATIC=ON -D SANITIZE=ON -D BUILD_TESTS=ON -D USE_LTO=OFF -D CMAKE_C_COMPILER=afl-gcc -D CMAKE_CXX_COMPILER=afl-g++ -D ARCH="x86-64" -D CMAKE_BUILD_TYPE=fuzz -D BUILD_TAG="linux-x64" ../.. && $(MAKE)
|
||||
mkdir -p $(builddir)/fuzz
|
||||
cd $(builddir)/fuzz && cmake -D STATIC=ON -D SANITIZE=ON -D BUILD_TESTS=ON -D USE_LTO=OFF -D CMAKE_C_COMPILER=afl-gcc -D CMAKE_CXX_COMPILER=afl-g++ -D ARCH="x86-64" -D CMAKE_BUILD_TYPE=fuzz -D BUILD_TAG="linux-x64" $(topdir) && $(MAKE)
|
||||
|
||||
clean:
|
||||
@echo "WARNING: Back-up your wallet if it exists within ./build!" ; \
|
||||
read -r -p "This will destroy the build directory, continue (y/N)?: " CONTINUE; \
|
||||
@echo "WARNING: Back-up your wallet if it exists within ./"$(deldirs)"!" ; \
|
||||
read -r -p "This will destroy the build directory, continue (y/N)?: " CONTINUE; \
|
||||
[ $$CONTINUE = "y" ] || [ $$CONTINUE = "Y" ] || (echo "Exiting."; exit 1;)
|
||||
rm -rf build
|
||||
rm -rf $(deldirs)
|
||||
|
||||
clean-all:
|
||||
@echo "WARNING: Back-up your wallet if it exists within ./build!" ; \
|
||||
read -r -p "This will destroy all build directories, continue (y/N)?: " CONTINUE; \
|
||||
[ $$CONTINUE = "y" ] || [ $$CONTINUE = "Y" ] || (echo "Exiting."; exit 1;)
|
||||
rm -rf ./build
|
||||
|
||||
tags:
|
||||
ctags -R --sort=1 --c++-kinds=+p --fields=+iaS --extra=+q --language-force=C++ src contrib tests/gtest
|
||||
|
||||
39
PKGBUILD
Normal file
39
PKGBUILD
Normal file
@@ -0,0 +1,39 @@
|
||||
# Maintainer: wowario <wowario at protonmail dot com>
|
||||
# Contributor: wowario <wowario at protonmail dot com>
|
||||
|
||||
pkgbase=('wownero-git')
|
||||
pkgname=('wownero-git')
|
||||
pkgver=0.5.0.2
|
||||
pkgrel=1
|
||||
pkgdesc="a fairly launched privacy-centric meme coin with no premine and a finite supply"
|
||||
license=('custom:Cryptonote')
|
||||
arch=('x86_64')
|
||||
url="http://wownero.org/"
|
||||
depends=('boost-libs' 'zeromq' 'unbound' 'libusb')
|
||||
makedepends=('git' 'cmake' 'boost')
|
||||
provides=('wownero-git')
|
||||
|
||||
source=("${pkgname}"::"git+https://github.com/wownero/wownero")
|
||||
|
||||
sha256sums=('SKIP')
|
||||
|
||||
pkgver() {
|
||||
cd "${srcdir}/${pkgname}"
|
||||
printf "$(echo ${pkgver} | sed 's/\.r.*//').r%s.g%s" \
|
||||
"$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
|
||||
}
|
||||
|
||||
build() {
|
||||
cd "${srcdir}/${pkgname}"
|
||||
git fetch --tags && git checkout tags/v0.5.0.2 -b v0.5.0.2
|
||||
USE_SINGLE_BUILDDIR=1 make
|
||||
}
|
||||
|
||||
package_wownero-git() {
|
||||
install -Dm644 "${srcdir}/${pkgname}/LICENSE" "${pkgdir}/usr/share/licenses/${pkgname}/LICENSE"
|
||||
install -Dm644 "${srcdir}/${pkgname}/utils/conf/wownerod.conf" "${pkgdir}/etc/wownerod.conf"
|
||||
install -Dm644 "${srcdir}/${pkgname}/utils/systemd/wownerod.service" "${pkgdir}/usr/lib/systemd/system/wownerod.service"
|
||||
install -Dm755 "${srcdir}/${pkgname}/build/release/bin/wownerod" "${pkgdir}/usr/bin/wownerod"
|
||||
install -Dm755 "${srcdir}/${pkgname}/build/release/bin/wownero-wallet-cli" "${pkgdir}/usr/bin/wownero-wallet-cli"
|
||||
install -Dm755 "${srcdir}/${pkgname}/build/release/bin/wownero-wallet-rpc" "${pkgdir}/usr/bin/wownero-wallet-rpc"
|
||||
}
|
||||
@@ -1,13 +1,13 @@
|
||||
Wownero daemon internationalization
|
||||
Monero daemon internationalization
|
||||
==================================
|
||||
|
||||
The Wownero command line tools can be translated in various languages. If you wish to contribute and need help/support, come chat on `#wownero` (Freenode/IRC)
|
||||
The Monero command line tools can be translated in various languages. If you wish to contribute and need help/support, contact the [Monero Localization Workgroup on Taiga](https://taiga.getmonero.org/project/erciccione-monero-localization/) or come chat on `#monero-translations` (Freenode/IRC, riot/matrix, MatterMost)
|
||||
|
||||
In order to use the same translation workflow as the [Wownero GUI](https://github.com/wownero/wownero-gui), they use Qt Linguist translation files. However, to avoid the dependencies on Qt this normally implies, they use a custom loader to read those files at runtime.
|
||||
In order to use the same translation workflow as the [Monero Core GUI](https://github.com/monero-project/monero-core), they use Qt Linguist translation files. However, to avoid the dependencies on Qt this normally implies, they use a custom loader to read those files at runtime.
|
||||
|
||||
### Tools for translators
|
||||
|
||||
In order to create, update or build translations files, you need to have Qt tools installed. For translating, you need either the **Qt Linguist GUI** ([part of QT Creator](https://www.qt.io/download-open-source/#allDownloadsDiv-9) or a [3rd-party standalone version](https://github.com/lelegard/qtlinguist-installers/releases)), or another tool that supports Qt ts files, such as Transifex. The files are XML, so they can be edited in any plain text editor if needed.
|
||||
In order to create, update or build translations files, you need to have Qt tools installed. For translating, you need either the **Qt Linguist GUI** ([part of Qt Creator](https://www.qt.io/download) or a [3rd-party standalone version](https://github.com/lelegard/qtlinguist-installers/releases)), or another tool that supports Qt ts files, such as Transifex. The files are XML, so they can be edited in any plain text editor if needed.
|
||||
|
||||
### Creating / modifying translations
|
||||
|
||||
@@ -19,11 +19,11 @@ To update ts files after changing source code:
|
||||
|
||||
To add a new language, eg Spanish (ISO code es):
|
||||
|
||||
cp translations/wownero.ts translations/wownero_es.ts
|
||||
cp translations/monero.ts translations/monero_es.ts
|
||||
|
||||
To edit translations for Spanish:
|
||||
|
||||
linguist translations/wownero_es.ts
|
||||
linguist translations/monero_es.ts
|
||||
|
||||
To build translations after modifying them:
|
||||
|
||||
@@ -31,7 +31,7 @@ To build translations after modifying them:
|
||||
|
||||
To test a translation:
|
||||
|
||||
LANG=es ./build/release/bin/wownero-wallet-cli
|
||||
LANG=es ./build/release/bin/monero-wallet-cli
|
||||
|
||||
To add new translatable strings in the source code:
|
||||
|
||||
|
||||
485
README.md
485
README.md
@@ -1,4 +1,4 @@
|
||||
# ~~Mo~~Wownero
|
||||
# ~~Mo~~Wownero - Such privacy! Many coins! Wow! 🐕
|
||||
|
||||
Copyright (c) 2014-2018 The Monero Project.
|
||||
Portions Copyright (c) 2012-2013 The Cryptonote developers.
|
||||
@@ -13,359 +13,87 @@ Portions Copyright (c) 2012-2013 The Cryptonote developers.
|
||||
- GitHub: [https://github.com/wownero/wownero](https://github.com/wownero/wownero)
|
||||
- IRC: [#wownero on Freenode](https://kiwiirc.com/client/irc.freenode.net/?nick=suchchatter|?#wownero)
|
||||
- Bitmessage Chan: wownero (`BM-2cSzWtrj2pzLva9GF1Jp2TYsnLjrnJpvba`)
|
||||
- Network stats: [https://freeboard.io/board/c8mM2c](https://freeboard.io/board/c8mM2c)
|
||||
- Wownero Funding System: [https://funding.wownero.com](https://funding.wownero.com)
|
||||
- Keybase Chat Group: [https://keybase.io/team/wownero](https://keybase.io/team/wownero)
|
||||
|
||||
## Vulnerability response
|
||||
|
||||
- TODO
|
||||
|
||||
|
||||
## Announcements
|
||||
|
||||
You can subscribe to an [announcement listserv](https://lists.getmonero.org) to get critical announcements from the Monero core team. The announcement list can be very helpful for knowing when software updates are needed.
|
||||
|
||||
## Build
|
||||
|
||||
| Operating System | Processor | Status |
|
||||
| --------------------- | -------- |--------|
|
||||
| Ubuntu 16.04 | i686 | TODO
|
||||
| Ubuntu 16.04 | amd64 | TODO
|
||||
| Ubuntu 16.04 | armv7 | TODO
|
||||
| Debian Stable | armv8 | TODO
|
||||
| OSX 10.10 | amd64 | TODO
|
||||
| OSX 10.11 | amd64 | TODO
|
||||
| OSX 10.12 | amd64 | TODO
|
||||
| FreeBSD 11 | amd64 | TODO
|
||||
| DragonFly BSD 4.6 | amd64 | TODO
|
||||
| Windows (MSYS2/MinGW) | i686 | TODO
|
||||
| Windows (MSYS2/MinGW) | amd64 | TODO
|
||||
|
||||
## Coverage
|
||||
|
||||
| Type | Status |
|
||||
|-----------|--------|
|
||||
| License | [](https://opensource.org/licenses/BSD-3-Clause)
|
||||
Blockchain Explorers
|
||||
- https://explore.wownero.com
|
||||
- https://explorer.wowkira.com
|
||||
- http://explorer.wowne.ro
|
||||
- http://wow4edxxxudchgj7.onion
|
||||
- http://wow5eqtzqvsg5jctqzg5g7uk3u62sfqiacj5x6lo4by7bvnj6jkvubyd.onion
|
||||
|
||||
## Introduction
|
||||
|
||||
Wownero is a fork of the private cryptocurrenty Monero with two major changes: A capped emmision that disallows infinite coin creation 10x the coin for 10x the W0W; Wownero is a fairly launched coin with no premine. It's not a fork of another blockchain. With its own genesis block there is no degradation of privacy due to ring signatures using different participants for the same tx outputs on opposing forks.
|
||||
|
||||
**Privacy:** Wownero uses a cryptographically sound system to allow you to send and receive funds without your transactions being easily revealed on the blockchain (the ledger of transactions that everyone has). This ensures that your purchases, receipts, and all transfers remain absolutely private by default.
|
||||
|
||||
**Security:** Using the power of a distributed peer-to-peer consensus network, every transaction on the network is cryptographically secured. Individual wallets have a 25 word mnemonic seed that is only displayed once, and can be written down to backup the wallet. Wallet files are encrypted with a passphrase to ensure they are useless if stolen.
|
||||
|
||||
**Untraceability:** By taking advantage of ring signatures, a special property of a certain type of cryptography, Wownero is able to ensure that transactions are not only untraceable, but have an optional measure of ambiguity that ensures that transactions cannot easily be tied back to an individual user or computer.
|
||||
|
||||
## About this project
|
||||
|
||||
This is the core implementation of Wownero. It is open source and completely free to use without restrictions, except for those specified in the license agreement below. There are no restrictions on anyone creating an alternative implementation of Wownero that uses the protocol and network in a compatible manner.
|
||||
|
||||
As with many development projects, the repository on Github is considered to be the "staging" area for the latest changes. Before changes are merged into that branch on the main repository, they are tested by individual developers in their own branches, submitted as a pull request, and then subsequently tested by contributors who focus on testing and code reviews. That having been said, the repository should be carefully considered before using it in a production environment, unless there is a patch in the repository for a particular show-stopping issue you are experiencing. It is generally a better idea to use a tagged release for stability.
|
||||
|
||||
**Anyone is welcome to contribute to Wownero's codebase!** If you have a fix or code change, feel free to submit it as a pull request directly to the "master" branch. In cases where the change is relatively small or does not affect other parts of the codebase it may be merged in immediately by any one of the collaborators. On the other hand, if the change is particularly large or complex, it is expected that it will be discussed at length either well in advance of the pull request being submitted, or even directly on the pull request. All pull requests will be considered safe until the US dollar valuation of 1 Wownero equals $1000. After this valuation has been reached, more reseach will be needed to introduce experimental cryptography and/or code into the codebase.
|
||||
|
||||
## Supporting the project
|
||||
|
||||
Wownero is a 100% community-sponsored endeavor. If you want to join our efforts, the easiest thing you can do is support the project financially.
|
||||
|
||||
The Wownero donation address (mostly reserved for hookers and blow) is: `Wo3MWeKwtA918DU4c69hVSNgejdWFCRCuWjShRY66mJkU2Hv58eygJWDJS1MNa2Ge5M1WjUkGHuLqHkweDxwZZU42d16v94mP`
|
||||
|
||||
The Monero donation address is: `44AFFq5kSiGBoZ4NMDwYtN18obc8AemS33DBLWs3H7otXft3XjrpDtQGv7SqSsaBYBb98uNbr2VBBEt7f2wfn3RVGQBEP3A` (viewkey: `f359631075708155cc3d92a32b75a7d02a5dcf27756707b47a2b31b21c389501`)
|
||||
|
||||
The Monero Bitcoin donation address is: `1KTexdemPdxSBcG55heUuTjDRYqbC5ZL8H`
|
||||
|
||||
Core development funding and/or some supporting services are also graciously provided by sponsors:
|
||||
|
||||
<img width="100" src="https://botw-pd.s3.amazonaws.com/styles/logo-thumbnail/s3/0024/1083/brand.gif"/><img width="100" src="https://blogvecindad.com/imagenes/2007/02/brawndo.jpg"/><img width="100" src="https://www.subscribepro.com/wp-content/uploads/2016/04/logo-depend-250x130.png"/>
|
||||
|
||||
## License
|
||||
|
||||
See [LICENSE](LICENSE).
|
||||
|
||||
## Contributing
|
||||
|
||||
If you want to help out, see [CONTRIBUTING](CONTRIBUTING.md) for a set of guidelines.
|
||||
Wownero is a privacy-centric memecoin that was fairly launched on April 1, 2018 with no pre-mine, stealth-mine or ICO. Wownero has a maximum supply of around 184 million WOW with a slow and steady emission over 50 years. It is a fork of Monero, but with its own genesis block, so there is no degradation of privacy due to ring signatures using different participants for the same tx outputs on opposing forks.
|
||||
|
||||
## Scheduled software upgrades
|
||||
|
||||
Wownero uses a fixed-schedule mandatory software upgrade (hard fork) mechanism to implement new features. This means that users of Wownero (end users and service providers) need to run current versions and upgrade their software on a regular schedule.The required software for these upgrades will be available prior to the scheduled date. Please check the repository prior to this date for the proper Wownero software version. Below is the historical schedule and the projected schedule for the next upgrade.
|
||||
Wownero uses a fixed-schedule software upgrade (hard fork) mechanism to implement new features. This means that users of Wownero (end users and service providers) should run current versions and upgrade their software on a regular schedule. The required software for these upgrades will be available prior to the scheduled date. Please check the repository prior to this date for the proper Wownero software version. Below is the historical schedule and the projected schedule for the next upgrade.
|
||||
Dates are provided in the format YYYY-MM-DD.
|
||||
|
||||
|
||||
| Software upgrade block height | Date | Fork version | Minimum Wownero version | Recommended Wownero version | Details |
|
||||
|
||||
| Software upgrade block height | Date | Release Name | Minimum Wownero version | Recommended Wownero version | Details |
|
||||
| ------------------------------ | -----------| ----------------- | ---------------------- | -------------------------- | ---------------------------------------------------------------------------------- |
|
||||
| 1 | 2018-04-01 | v7 | v0.1.0.0 | v0.1.0.0 | Cryptonight variant 1, ringsize >= 8, sorted inputs
|
||||
| 6969 | 2018-04-24 | v8 | v0.2.0.0 | v0.2.0.0 | Bulletproofs, LWMA difficulty algorithm, ringsize >= 10, reduce unlock to 4
|
||||
| 53666 | 2018-10-06 | v9 | v0.3.0.0 | v0.3.1.3 | Cryptonight variant 2, LWMA v2, ringsize = 22, MMS
|
||||
| 63469 | 2018-11-11 | v10 | v0.4.0.0 | v0.4.0.0 | LWMA v4
|
||||
| 1 | 2018-04-01 | Awesome Akita | v0.1.0.0 | v0.1.0.0 | Cryptonight variant 1, ringsize >= 8, sorted inputs
|
||||
| 6969 | 2018-04-24 | Busty Brazzers | v0.2.0.0 | v0.2.0.0 | Bulletproofs, LWMA difficulty algorithm, ringsize >= 10, reduce unlock to 4
|
||||
| 53666 | 2018-10-06 | Cool Cage | v0.3.0.0 | v0.3.1.3 | Cryptonight variant 2, LWMA v2, ringsize = 22, MMS
|
||||
| 63469 | 2018-11-11 | Dank Doge | v0.4.0.0 | v0.4.0.0 | LWMA v4
|
||||
| 81769 | 2019-02-19 | Erotic EggplantEmoji | v0.5.0.0 | v0.5.1.1 | Cryptonight/wow, LWMA v1 with N=144, Updated Bulletproofs, Fee Per Byte, Auto-churn
|
||||
|
||||
X's indicate that these details have not been determined as of commit date.
|
||||
|
||||
## Release staging schedule and protocol
|
||||
## Release staging and Contributing
|
||||
|
||||
Approximately three months prior to a scheduled mandatory software upgrade, a branch from Master will be created with the new release version tag. Pull requests that address bugs should then be made to both Master and the new release branch. Pull requests that require extensive review and testing (generally, optimizations and new features) should *not* be made to the release branch.
|
||||
**Anyone is welcome to contribute to Wownero's codebase!**
|
||||
|
||||
## Compiling Wownero from source
|
||||
If you have a fix or code change, feel free to submit it as a pull request. Ahead of a scheduled software upgrade, a development branch will be created with the new release version tag. Pull requests that address bugs should be made to Master. Pull requests that require review and testing (generally, optimizations and new features) should be made to the development branch. All pull requests will be considered safe until the US dollar valuation of 1 Wownero equals $1000. After this valuation has been reached, more research will be needed to introduce experimental cryptography and/or code into the codebase.
|
||||
|
||||
### Dependencies
|
||||
## Installing from a package
|
||||
|
||||
The following table summarizes the tools and libraries required to build. A
|
||||
few of the libraries are also included in this repository (marked as
|
||||
"Vendored"). By default, the build uses the library installed on the system,
|
||||
and ignores the vendored sources. However, if no library is found installed on
|
||||
the system, then the vendored source will be built and used. The vendored
|
||||
sources are also used for statically-linked builds because distribution
|
||||
packages often include only shared library binaries (`.so`) but not static
|
||||
library archives (`.a`).
|
||||
Packages are available for
|
||||
|
||||
| Dep | Min. version | Vendored | Debian/Ubuntu pkg | Arch pkg | Fedora | Optional | Purpose |
|
||||
| ------------ | ------------- | -------- | ------------------ | ------------ | ----------------- | -------- | -------------- |
|
||||
| GCC | 4.7.3 | NO | `build-essential` | `base-devel` | `gcc` | NO | |
|
||||
| CMake | 3.5 | NO | `cmake` | `cmake` | `cmake` | NO | |
|
||||
| pkg-config | any | NO | `pkg-config` | `base-devel` | `pkgconf` | NO | |
|
||||
| Boost | 1.58 | NO | `libboost-all-dev` | `boost` | `boost-devel` | NO | C++ libraries |
|
||||
| OpenSSL | basically any | NO | `libssl-dev` | `openssl` | `openssl-devel` | NO | sha256 sum |
|
||||
| libzmq | 3.0.0 | NO | `libzmq3-dev` | `zeromq` | `cppzmq-devel` | NO | ZeroMQ library |
|
||||
| OpenPGM | ? | NO | `libpgm-dev` | `libpgm` | `openpgm-devel` | NO | For ZeroMQ |
|
||||
| libunbound | 1.4.16 | YES | `libunbound-dev` | `unbound` | `unbound-devel` | NO | DNS resolver |
|
||||
| libsodium | ? | NO | `libsodium-dev` | `libsodium` | `libsodium-devel` | NO | cryptography |
|
||||
| libunwind | any | NO | `libunwind8-dev` | `libunwind` | `libunwind-devel` | YES | Stack traces |
|
||||
| liblzma | any | NO | `liblzma-dev` | `xz` | `xz-devel` | YES | For libunwind |
|
||||
| libreadline | 6.3.0 | NO | `libreadline6-dev` | `readline` | `readline-devel` | YES | Input editing |
|
||||
| ldns | 1.6.17 | NO | `libldns-dev` | `ldns` | `ldns-devel` | YES | SSL toolkit |
|
||||
| expat | 1.1 | NO | `libexpat1-dev` | `expat` | `expat-devel` | YES | XML parsing |
|
||||
| GTest | 1.5 | YES | `libgtest-dev`^ | `gtest` | `gtest-devel` | YES | Test suite |
|
||||
| Doxygen | any | NO | `doxygen` | `doxygen` | `doxygen` | YES | Documentation |
|
||||
| Graphviz | any | NO | `graphviz` | `graphviz` | `graphviz` | YES | Documentation |
|
||||
| pcsclite | ? | NO | `libpcsclite-dev` | ? | `pcsc-lite pcsc-lite-devel` | NO | Ledger |
|
||||
* Arch Linux/Manjaro
|
||||
|
||||
yay -S wownero-git
|
||||
|
||||
* NixOS
|
||||
|
||||
nix-shell -p altcoins.wownero
|
||||
|
||||
* Ubuntu 18.04/Ubuntu 16.04/Debian 9/Debian 8 (amd64)
|
||||
|
||||
sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys B09DF0E4B0C56A94
|
||||
sudo add-apt-repository "deb http://ppa.wownero.com/ bionic main"
|
||||
sudo apt-get update
|
||||
sudo apt-get install wownero
|
||||
|
||||
Packaging for your favorite distribution would be a welcome contribution!
|
||||
|
||||
**DISCLAIMER: These packages are not part of this repository, and as such, do not go through the same review process to ensure their trustworthiness and security.**
|
||||
|
||||
|
||||
[^] On Debian/Ubuntu `libgtest-dev` only includes sources and headers. You must
|
||||
build the library binary manually. This can be done with the following command ```sudo apt-get install libgtest-dev && cd /usr/src/gtest && sudo cmake . && sudo make && sudo mv libg* /usr/lib/ ```
|
||||
## Building from Source
|
||||
|
||||
Debian / Ubuntu one liner for all dependencies
|
||||
``` sudo apt update && sudo apt install build-essential cmake pkg-config libboost-all-dev libssl-dev libzmq3-dev libunbound-dev libsodium-dev libunwind8-dev liblzma-dev libreadline6-dev libldns-dev libexpat1-dev doxygen graphviz libpcsclite-dev libpgm-dev```
|
||||
|
||||
### Cloning the repository
|
||||
|
||||
`$ git clone https://github.com/wownero/wownero`
|
||||
|
||||
Submodules are fetched and updated automatically. If you wish to
|
||||
do this manually, run CMake flag `-DMANUAL_SUBMODULES=ON` to opt out.
|
||||
|
||||
### Build instructions
|
||||
|
||||
Wownero uses the CMake build system and a top-level [Makefile](Makefile) that
|
||||
invokes cmake commands as needed.
|
||||
|
||||
#### On Linux and OS X
|
||||
|
||||
* Install the dependencies
|
||||
* Change to the root of the source code directory and build:
|
||||
* Arch Linux/Manjaro
|
||||
|
||||
sudo pacman -Syu && sudo pacman -S base-devel cmake boost openssl zeromq libpgm unbound libsodium git
|
||||
git clone https://github.com/wownero/wownero
|
||||
cd wownero
|
||||
make
|
||||
|
||||
*Optional*: If your machine has several cores and enough memory, enable
|
||||
parallel build by running `make -j<number of threads>` instead of `make`. For
|
||||
this to be worthwhile, the machine should have one core and about 2GB of RAM
|
||||
available per thread.
|
||||
|
||||
*Note*: If cmake can not find zmq.hpp file on OS X, installing `zmq.hpp` from
|
||||
https://github.com/zeromq/cppzmq to `/usr/local/include` should fix that error.
|
||||
* Debian/Ubuntu
|
||||
|
||||
* The resulting executables can be found in `build/release/bin`
|
||||
sudo apt update && sudo apt install build-essential cmake pkg-config libboost-all-dev libssl-dev libzmq3-dev libunbound-dev libsodium-dev libpgm-dev git
|
||||
git clone https://github.com/wownero/wownero
|
||||
cd wownero
|
||||
make
|
||||
|
||||
* Add `PATH="$PATH:$HOME/wownero/build/release/bin"` to `.profile`
|
||||
|
||||
* Run Wownero with `wownerod --detach`
|
||||
|
||||
* **Optional**: build and run the test suite to verify the binaries:
|
||||
|
||||
make release-test
|
||||
|
||||
*NOTE*: `core_tests` test may take a few hours to complete.
|
||||
|
||||
* **Optional**: to build binaries suitable for debugging:
|
||||
|
||||
make debug
|
||||
|
||||
* **Optional**: to build statically-linked binaries:
|
||||
|
||||
make release-static
|
||||
|
||||
Dependencies need to be built with -fPIC. Static libraries usually aren't, so you may have to build them yourself with -fPIC. Refer to their documentation for how to build them.
|
||||
|
||||
* **Optional**: build documentation in `doc/html` (omit `HAVE_DOT=YES` if `graphviz` is not installed):
|
||||
|
||||
HAVE_DOT=YES doxygen Doxyfile
|
||||
|
||||
#### On Windows:
|
||||
|
||||
Binaries for Windows are built on Windows using the MinGW toolchain within
|
||||
[MSYS2 environment](http://msys2.github.io). The MSYS2 environment emulates a
|
||||
POSIX system. The toolchain runs within the environment and *cross-compiles*
|
||||
binaries that can run outside of the environment as a regular Windows
|
||||
application.
|
||||
|
||||
**Preparing the build environment**
|
||||
|
||||
* Download and install the [MSYS2 installer](http://msys2.github.io), either the 64-bit or the 32-bit package, depending on your system.
|
||||
* Open the MSYS shell via the `MSYS2 Shell` shortcut
|
||||
* Update packages using pacman:
|
||||
|
||||
pacman -Syuu
|
||||
|
||||
* Exit the MSYS shell using Alt+F4
|
||||
* Edit the properties for the `MSYS2 Shell` shortcut changing "msys2_shell.bat" to "msys2_shell.cmd -mingw64" for 64-bit builds or "msys2_shell.cmd -mingw32" for 32-bit builds
|
||||
* Restart MSYS shell via modified shortcut and update packages again using pacman:
|
||||
|
||||
pacman -Syuu
|
||||
|
||||
|
||||
* Install dependencies:
|
||||
|
||||
To build for 64-bit Windows:
|
||||
|
||||
pacman -S mingw-w64-x86_64-toolchain make mingw-w64-x86_64-cmake mingw-w64-x86_64-boost mingw-w64-x86_64-openssl mingw-w64-x86_64-zeromq mingw-w64-x86_64-libsodium
|
||||
|
||||
To build for 32-bit Windows:
|
||||
|
||||
pacman -S mingw-w64-i686-toolchain make mingw-w64-i686-cmake mingw-w64-i686-boost mingw-w64-i686-openssl mingw-w64-i686-zeromq mingw-w64-i686-libsodium
|
||||
|
||||
* Open the MingW shell via `MinGW-w64-Win64 Shell` shortcut on 64-bit Windows
|
||||
or `MinGW-w64-Win64 Shell` shortcut on 32-bit Windows. Note that if you are
|
||||
running 64-bit Windows, you will have both 64-bit and 32-bit MinGW shells.
|
||||
|
||||
**Building**
|
||||
|
||||
* If you are on a 64-bit system, run:
|
||||
|
||||
make release-static-win64
|
||||
|
||||
* If you are on a 32-bit system, run:
|
||||
|
||||
make release-static-win32
|
||||
|
||||
* The resulting executables can be found in `build/release/bin`
|
||||
|
||||
### On FreeBSD:
|
||||
|
||||
The project can be built from scratch by following instructions for Linux above. If you are running wownero in a jail you need to add the flag: `allow.sysvipc=1` to your jail configuration, otherwise lmdb will throw the error message: `Failed to open lmdb environment: Function not implemented`.
|
||||
|
||||
### On OpenBSD:
|
||||
|
||||
#### OpenBSD < 6.2
|
||||
|
||||
This has been tested on OpenBSD 5.8.
|
||||
|
||||
You will need to add a few packages to your system. `pkg_add db cmake gcc gcc-libs g++ miniupnpc gtest`.
|
||||
|
||||
The doxygen and graphviz packages are optional and require the xbase set.
|
||||
|
||||
The Boost package has a bug that will prevent librpc.a from building correctly. In order to fix this, you will have to Build boost yourself from scratch. Follow the directions here (under "Building Boost"):
|
||||
https://github.com/bitcoin/bitcoin/blob/master/doc/build-openbsd.md
|
||||
|
||||
You will have to add the serialization, date_time, and regex modules to Boost when building as they are needed by Wownero.
|
||||
|
||||
To build: `env CC=egcc CXX=eg++ CPP=ecpp DEVELOPER_LOCAL_TOOLS=1 BOOST_ROOT=/path/to/the/boost/you/built make release-static-64`
|
||||
|
||||
#### OpenBSD >= 6.2
|
||||
|
||||
You will need to add a few packages to your system. `pkg_add cmake miniupnpc zeromq libiconv`.
|
||||
|
||||
The doxygen and graphviz packages are optional and require the xbase set.
|
||||
|
||||
|
||||
Build the Boost library using clang. This guide is derived from: https://github.com/bitcoin/bitcoin/blob/master/doc/build-openbsd.md
|
||||
|
||||
We assume you are compiling with a non-root user and you have `doas` enabled.
|
||||
|
||||
Note: do not use the boost package provided by OpenBSD, as we are installing boost to `/usr/local`.
|
||||
|
||||
```
|
||||
# Create boost building directory
|
||||
mkdir ~/boost
|
||||
cd ~/boost
|
||||
|
||||
# Fetch boost source
|
||||
ftp -o boost_1_64_0.tar.bz2 https://netcologne.dl.sourceforge.net/project/boost/boost/1.64.0/boost_1_64_0.tar.bz2
|
||||
|
||||
# MUST output: (SHA256) boost_1_64_0.tar.bz2: OK
|
||||
echo "7bcc5caace97baa948931d712ea5f37038dbb1c5d89b43ad4def4ed7cb683332 boost_1_64_0.tar.bz2" | sha256 -c
|
||||
tar xfj boost_1_64_0.tar.bz2
|
||||
|
||||
# Fetch and apply boost patches, required for OpenBSD
|
||||
ftp -o boost_test_impl_execution_monitor_ipp.patch https://raw.githubusercontent.com/openbsd/ports/bee9e6df517077a7269ff0dfd57995f5c6a10379/devel/boost/patches/patch-boost_test_impl_execution_monitor_ipp
|
||||
ftp -o boost_config_platform_bsd_hpp.patch https://raw.githubusercontent.com/openbsd/ports/90658284fb786f5a60dd9d6e8d14500c167bdaa0/devel/boost/patches/patch-boost_config_platform_bsd_hpp
|
||||
|
||||
# MUST output: (SHA256) boost_config_platform_bsd_hpp.patch: OK
|
||||
echo "1f5e59d1154f16ee1e0cc169395f30d5e7d22a5bd9f86358f738b0ccaea5e51d boost_config_platform_bsd_hpp.patch" | sha256 -c
|
||||
# MUST output: (SHA256) boost_test_impl_execution_monitor_ipp.patch: OK
|
||||
echo "30cec182a1437d40c3e0bd9a866ab5ddc1400a56185b7e671bb3782634ed0206 boost_test_impl_execution_monitor_ipp.patch" | sha256 -c
|
||||
|
||||
cd boost_1_64_0
|
||||
patch -p0 < ../boost_test_impl_execution_monitor_ipp.patch
|
||||
patch -p0 < ../boost_config_platform_bsd_hpp.patch
|
||||
|
||||
# Start building boost
|
||||
echo 'using clang : : c++ : <cxxflags>"-fvisibility=hidden -fPIC" <linkflags>"" <archiver>"ar" <striper>"strip" <ranlib>"ranlib" <rc>"" : ;' > user-config.jam
|
||||
./bootstrap.sh --without-icu --with-libraries=chrono,filesystem,program_options,system,thread,test,date_time,regex,serialization,locale --with-toolset=clang
|
||||
./b2 toolset=clang cxxflags="-stdlib=libc++" linkflags="-stdlib=libc++" -sICONV_PATH=/usr/local
|
||||
doas ./b2 -d0 runtime-link=shared threadapi=pthread threading=multi link=static variant=release --layout=tagged --build-type=complete --user-config=user-config.jam -sNO_BZIP2=1 -sICONV_PATH=/usr/local --prefix=/usr/local install
|
||||
```
|
||||
|
||||
Build cppzmq
|
||||
|
||||
Build the cppzmq bindings.
|
||||
|
||||
We assume you are compiling with a non-root user and you have `doas` enabled.
|
||||
|
||||
```
|
||||
# Create cppzmq building directory
|
||||
mkdir ~/cppzmq
|
||||
cd ~/cppzmq
|
||||
|
||||
# Fetch cppzmq source
|
||||
ftp -o cppzmq-4.2.3.tar.gz https://github.com/zeromq/cppzmq/archive/v4.2.3.tar.gz
|
||||
|
||||
# MUST output: (SHA256) cppzmq-4.2.3.tar.gz: OK
|
||||
echo "3e6b57bf49115f4ae893b1ff7848ead7267013087dc7be1ab27636a97144d373 cppzmq-4.2.3.tar.gz" | sha256 -c
|
||||
tar xfz cppzmq-4.2.3.tar.gz
|
||||
|
||||
# Start building cppzmq
|
||||
cd cppzmq-4.2.3
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
doas make install
|
||||
```
|
||||
|
||||
Build wownero: `env DEVELOPER_LOCAL_TOOLS=1 BOOST_ROOT=/usr/local make release-static`
|
||||
|
||||
### On Solaris:
|
||||
|
||||
The default Solaris linker can't be used, you have to install GNU ld, then run cmake manually with the path to your copy of GNU ld:
|
||||
|
||||
mkdir -p build/release
|
||||
cd build/release
|
||||
cmake -DCMAKE_LINKER=/path/to/ld -D CMAKE_BUILD_TYPE=Release ../..
|
||||
cd ../..
|
||||
|
||||
Then you can run make as usual.
|
||||
|
||||
### Building portable statically linked binaries
|
||||
|
||||
By default, in either dynamically or statically linked builds, binaries target the specific host processor on which the build happens and are not portable to other processors. Portable binaries can be built using the following targets:
|
||||
|
||||
* ```make release-static-linux-x86_64``` builds binaries on Linux on x86_64 portable across POSIX systems on x86_64 processors
|
||||
* ```make release-static-linux-i686``` builds binaries on Linux on x86_64 or i686 portable across POSIX systems on i686 processors
|
||||
* ```make release-static-linux-armv8``` builds binaries on Linux portable across POSIX systems on armv8 processors
|
||||
* ```make release-static-linux-armv7``` builds binaries on Linux portable across POSIX systems on armv7 processors
|
||||
* ```make release-static-linux-armv6``` builds binaries on Linux portable across POSIX systems on armv6 processors
|
||||
* ```make release-static-win64``` builds binaries on 64-bit Windows portable across 64-bit Windows systems
|
||||
* ```make release-static-win32``` builds binaries on 64-bit or 32-bit Windows portable across 32-bit Windows systems
|
||||
|
||||
## Running wownerod
|
||||
## Running Binaries
|
||||
|
||||
The build places the binary in `bin/` sub-directory within the build directory
|
||||
from which cmake was invoked (repository root by default). To run in
|
||||
@@ -390,111 +118,30 @@ service](utils/systemd/wownerod.service) assumes that the user `wownero` exists
|
||||
and its home is the data directory specified in the [example
|
||||
config](utils/conf/wownerod.conf).
|
||||
|
||||
If you're on Mac, you may need to add the `--max-concurrency 1` option to
|
||||
wownero-wallet-cli, and possibly wownerod, if you get crashes refreshing.
|
||||
Once node is synced to network, run the CLI wallet by entering:
|
||||
|
||||
## Internationalization
|
||||
./bin/wownero-wallet-cli
|
||||
|
||||
See [README.i18n.md](README.i18n.md).
|
||||
Type `help` in CLI wallet to see standard commands (for advanced options, type `help_advanced`).
|
||||
|
||||
## Using Tor
|
||||
## Wownero Graphical Wallets
|
||||
|
||||
While Wownero isn't made to integrate with Tor, it can be used wrapped with torsocks, by
|
||||
setting the following configuration parameters and environment variables:
|
||||
* [Wownero-Light-Wallet](https://github.com/wownero/Wownero-Light-Wallet)
|
||||
|
||||
* `--p2p-bind-ip 127.0.0.1` on the command line or `p2p-bind-ip=127.0.0.1` in
|
||||
wownerod.conf to disable listening for connections on external interfaces.
|
||||
* `--no-igd` on the command line or `no-igd=1` in wownerod.conf to disable IGD
|
||||
(UPnP port forwarding negotiation), which is pointless with Tor.
|
||||
* `DNS_PUBLIC=tcp` or `DNS_PUBLIC=tcp://x.x.x.x` where x.x.x.x is the IP of the
|
||||
desired DNS server, for DNS requests to go over TCP, so that they are routed
|
||||
through Tor. When IP is not specified, wownerod uses the default list of
|
||||
servers defined in [src/common/dns_utils.cpp](src/common/dns_utils.cpp).
|
||||
* `TORSOCKS_ALLOW_INBOUND=1` to tell torsocks to allow wownerod to bind to interfaces
|
||||
to accept connections from the wallet. On some Linux systems, torsocks
|
||||
allows binding to localhost by default, so setting this variable is only
|
||||
necessary to allow binding to local LAN/VPN interfaces to allow wallets to
|
||||
connect from remote hosts. On other systems, it may be needed for local wallets
|
||||
as well.
|
||||
* Do NOT pass `--detach` when running through torsocks with systemd, (see
|
||||
[utils/systemd/wownerod.service](utils/systemd/wownerod.service) for details).
|
||||
* If you use the wallet with a Tor daemon via the loopback IP (eg, 127.0.0.1:9050),
|
||||
then use `--untrusted-daemon` unless it is your own hidden service.
|
||||

|
||||
|
||||
Example command line to start wownerod through Tor:
|
||||
|
||||
DNS_PUBLIC=tcp torsocks wownerod --p2p-bind-ip 127.0.0.1 --no-igd
|
||||
* [Wownerujo Android Wallet](https://github.com/wownero/wownerujo)
|
||||
|
||||
### Using Tor on Tails
|
||||

|
||||

|
||||
|
||||
TAILS ships with a very restrictive set of firewall rules. Therefore, you need
|
||||
to add a rule to allow this connection too, in addition to telling torsocks to
|
||||
allow inbound connections. Full example:
|
||||
## Donating to Wownero Project
|
||||
|
||||
sudo iptables -I OUTPUT 2 -p tcp -d 127.0.0.1 -m tcp --dport 34568 -j ACCEPT
|
||||
DNS_PUBLIC=tcp torsocks ./wownerod --p2p-bind-ip 127.0.0.1 --no-igd --rpc-bind-ip 127.0.0.1 \
|
||||
--data-dir /home/amnesia/Persistent/your/directory/to/the/blockchain
|
||||
Developers are volunteers doing this mostly for shits and giggles. If you would like to support our shenanigans and stimulant addictions, please consider donating to [WFS proposals](https://funding.wownero.com/proposals) or the [dev slush fund](https://funding.wownero.com/donate).
|
||||
|
||||
## Debugging
|
||||
Donations may also be sent to:
|
||||
|
||||
This section contains general instructions for debugging failed installs or problems encountered with Wownero. First ensure you are running the latest version built from the Github repo.
|
||||
XMR: `44SQVPGLufPasUcuUQSZiF5c9BFzjcP8ucDxzzFDgLf1VkCEFaidJ3u2AhSKMhPLKA3jc2iS8wQHFcaigM6fXmo6AnFRn5B`
|
||||
|
||||
### Obtaining stack traces and core dumps on Unix systems
|
||||
|
||||
We generally use the tool `gdb` (GNU debugger) to provide stack trace functionality, and `ulimit` to provide core dumps in builds which crash or segfault.
|
||||
|
||||
* To use gdb in order to obtain a stack trace for a build that has stalled:
|
||||
|
||||
Run the build.
|
||||
|
||||
Once it stalls, enter the following command:
|
||||
|
||||
```
|
||||
gdb /path/to/wownerod `pidof wownerod`
|
||||
```
|
||||
|
||||
Type `thread apply all bt` within gdb in order to obtain the stack trace
|
||||
|
||||
* If however the core dumps or segfaults:
|
||||
|
||||
Enter `ulimit -c unlimited` on the command line to enable unlimited filesizes for core dumps
|
||||
|
||||
Enter `echo core | sudo tee /proc/sys/kernel/core_pattern` to stop cores from being hijacked by other tools
|
||||
|
||||
Run the build.
|
||||
|
||||
When it terminates with an output along the lines of "Segmentation fault (core dumped)", there should be a core dump file in the same directory as wownerod. It may be named just `core`, or `core.xxxx` with numbers appended.
|
||||
|
||||
You can now analyse this core dump with `gdb` as follows:
|
||||
|
||||
`gdb /path/to/wownerod /path/to/dumpfile`
|
||||
|
||||
Print the stack trace with `bt`
|
||||
|
||||
* To run wownero within gdb:
|
||||
|
||||
Type `gdb /path/to/wownerod`
|
||||
|
||||
Pass command-line options with `--args` followed by the relevant arguments
|
||||
|
||||
Type `run` to run wownerod
|
||||
|
||||
### Analysing memory corruption
|
||||
|
||||
We use the tool `valgrind` for this.
|
||||
|
||||
Run with `valgrind /path/to/wownerod`. It will be slow.
|
||||
|
||||
### LMDB
|
||||
|
||||
Instructions for debugging suspected blockchain corruption as per @HYC
|
||||
|
||||
There is an `mdb_stat` command in the LMDB source that can print statistics about the database but it's not routinely built. This can be built with the following command:
|
||||
|
||||
`cd ~/wownero/external/db_drivers/liblmdb && make`
|
||||
|
||||
The output of `mdb_stat -ea <path to blockchain dir>` will indicate inconsistencies in the blocks, block_heights and block_info table.
|
||||
|
||||
The output of `mdb_dump -s blocks <path to blockchain dir>` and `mdb_dump -s block_info <path to blockchain dir>` is useful for indicating whether blocks and block_info contain the same keys.
|
||||
|
||||
These records are dumped as hex data, where the first line is the key and the second line is the data.
|
||||
BTC: `bc1qcw9zglp3fxyl25zswemw7jczlqryms2lsmu464`
|
||||
|
||||
@@ -39,7 +39,7 @@ macro(CHECK_LINKER_FLAG flag VARIABLE)
|
||||
endif()
|
||||
set(${VARIABLE} "" CACHE INTERNAL "Have linker flag ${flag}")
|
||||
file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
|
||||
"Determining if the ${flag} linker flag is suppored "
|
||||
"Determining if the ${flag} linker flag is supported "
|
||||
"failed with the following output:\n"
|
||||
"${OUTPUT}\n\n")
|
||||
endif()
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
# that follow. The default is UTF-8 which is also the encoding used for all
|
||||
# text before the first occurrence of this tag. Doxygen uses libiconv (or the
|
||||
# iconv built into libc) for the transcoding. See
|
||||
# http://www.gnu.org/software/libiconv for the list of possible encodings.
|
||||
# https://www.gnu.org/software/libiconv for the list of possible encodings.
|
||||
|
||||
DOXYFILE_ENCODING = UTF-8
|
||||
|
||||
@@ -242,7 +242,7 @@ EXTENSION_MAPPING =
|
||||
|
||||
# If MARKDOWN_SUPPORT is enabled (the default) then doxygen pre-processes all
|
||||
# comments according to the Markdown format, which allows for more readable
|
||||
# documentation. See http://daringfireball.net/projects/markdown/ for details.
|
||||
# documentation. See https://daringfireball.net/projects/markdown/ for details.
|
||||
# The output of markdown processing is further processed by doxygen, so you
|
||||
# can mix doxygen, HTML, and XML commands with Markdown formatting.
|
||||
# Disable only in case of backward compatibilities issues.
|
||||
@@ -589,7 +589,7 @@ LAYOUT_FILE =
|
||||
# containing the references data. This must be a list of .bib files. The
|
||||
# .bib extension is automatically appended if omitted. Using this command
|
||||
# requires the bibtex tool to be installed. See also
|
||||
# http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style
|
||||
# https://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style
|
||||
# of the bibliography can be controlled using LATEX_BIB_STYLE. To use this
|
||||
# feature you need bibtex and perl available in the search path.
|
||||
|
||||
@@ -665,7 +665,7 @@ INPUT = ../README.md \
|
||||
# This tag can be used to specify the character encoding of the source files
|
||||
# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
|
||||
# also the default input encoding. Doxygen uses libiconv (or the iconv built
|
||||
# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for
|
||||
# into libc) for the transcoding. See https://www.gnu.org/software/libiconv for
|
||||
# the list of possible encodings.
|
||||
|
||||
INPUT_ENCODING = UTF-8
|
||||
@@ -833,7 +833,7 @@ REFERENCES_LINK_SOURCE = YES
|
||||
# If the USE_HTAGS tag is set to YES then the references to source code
|
||||
# will point to the HTML generated by the htags(1) tool instead of doxygen
|
||||
# built-in source browser. The htags tool is part of GNU's global source
|
||||
# tagging system (see http://www.gnu.org/software/global/global.html). You
|
||||
# tagging system (see https://www.gnu.org/software/global/global.html). You
|
||||
# will need version 4.8.6 or higher.
|
||||
|
||||
USE_HTAGS = NO
|
||||
@@ -928,7 +928,7 @@ HTML_EXTRA_FILES =
|
||||
# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output.
|
||||
# Doxygen will adjust the colors in the style sheet and background images
|
||||
# according to this color. Hue is specified as an angle on a colorwheel,
|
||||
# see http://en.wikipedia.org/wiki/Hue for more information.
|
||||
# see https://en.wikipedia.org/wiki/Hue for more information.
|
||||
# For instance the value 0 represents red, 60 is yellow, 120 is green,
|
||||
# 180 is cyan, 240 is blue, 300 purple, and 360 is red again.
|
||||
# The allowed range is 0 to 359.
|
||||
@@ -981,7 +981,7 @@ HTML_INDEX_NUM_ENTRIES = 100
|
||||
# directory and running "make install" will install the docset in
|
||||
# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find
|
||||
# it at startup.
|
||||
# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
|
||||
# See https://developer.apple.com/tools/creatingdocsetswithdoxygen.html
|
||||
# for more information.
|
||||
|
||||
GENERATE_DOCSET = NO
|
||||
@@ -1179,7 +1179,7 @@ FORMULA_FONTSIZE = 10
|
||||
FORMULA_TRANSPARENT = YES
|
||||
|
||||
# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax
|
||||
# (see http://www.mathjax.org) which uses client side Javascript for the
|
||||
# (see https://www.mathjax.org) which uses client side Javascript for the
|
||||
# rendering instead of using prerendered bitmaps. Use this if you do not
|
||||
# have LaTeX installed or if you want to formulas look prettier in the HTML
|
||||
# output. When enabled you may also need to install MathJax separately and
|
||||
@@ -1194,9 +1194,9 @@ USE_MATHJAX = NO
|
||||
# MATHJAX_RELPATH should be ../mathjax. The default value points to
|
||||
# the MathJax Content Delivery Network so you can quickly see the result without
|
||||
# installing MathJax. However, it is strongly recommended to install a local
|
||||
# copy of MathJax from http://www.mathjax.org before deployment.
|
||||
# copy of MathJax from https://www.mathjax.org before deployment.
|
||||
|
||||
MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest
|
||||
MATHJAX_RELPATH = https://cdn.mathjax.org/mathjax/latest
|
||||
|
||||
# The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension
|
||||
# names that should be enabled during MathJax rendering.
|
||||
@@ -1318,7 +1318,7 @@ LATEX_SOURCE_CODE = NO
|
||||
|
||||
# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
|
||||
# bibliography, e.g. plainnat, or ieeetr. The default style is "plain". See
|
||||
# http://en.wikipedia.org/wiki/BibTeX for more info.
|
||||
# https://en.wikipedia.org/wiki/BibTeX for more info.
|
||||
|
||||
LATEX_BIB_STYLE = plain
|
||||
|
||||
|
||||
60
cmake/FindHIDAPI.cmake
Normal file
60
cmake/FindHIDAPI.cmake
Normal file
@@ -0,0 +1,60 @@
|
||||
# - try to find HIDAPI library
|
||||
# from http://www.signal11.us/oss/hidapi/
|
||||
#
|
||||
# Cache Variables: (probably not for direct use in your scripts)
|
||||
# HIDAPI_INCLUDE_DIR
|
||||
# HIDAPI_LIBRARY
|
||||
#
|
||||
# Non-cache variables you might use in your CMakeLists.txt:
|
||||
# HIDAPI_FOUND
|
||||
# HIDAPI_INCLUDE_DIRS
|
||||
# HIDAPI_LIBRARIES
|
||||
#
|
||||
# Requires these CMake modules:
|
||||
# FindPackageHandleStandardArgs (known included with CMake >=2.6.2)
|
||||
#
|
||||
# Original Author:
|
||||
# 2009-2010 Ryan Pavlik <rpavlik@iastate.edu> <abiryan@ryand.net>
|
||||
# http://academic.cleardefinition.com
|
||||
# Iowa State University HCI Graduate Program/VRAC
|
||||
#
|
||||
# Copyright Iowa State University 2009-2010.
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or copy at
|
||||
# http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
find_library(HIDAPI_LIBRARY
|
||||
NAMES hidapi hidapi-libusb)
|
||||
|
||||
find_path(HIDAPI_INCLUDE_DIR
|
||||
NAMES hidapi.h
|
||||
PATH_SUFFIXES
|
||||
hidapi)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(HIDAPI
|
||||
DEFAULT_MSG
|
||||
HIDAPI_LIBRARY
|
||||
HIDAPI_INCLUDE_DIR)
|
||||
|
||||
if(HIDAPI_FOUND)
|
||||
set(HIDAPI_LIBRARIES "${HIDAPI_LIBRARY}")
|
||||
if((STATIC AND UNIX AND NOT APPLE) OR (DEPENDS AND CMAKE_SYSTEM_NAME STREQUAL "Linux"))
|
||||
find_library(LIBUSB-1.0_LIBRARY usb-1.0)
|
||||
find_library(LIBUDEV_LIBRARY udev)
|
||||
if(LIBUSB-1.0_LIBRARY)
|
||||
set(HIDAPI_LIBRARIES "${HIDAPI_LIBRARIES};${LIBUSB-1.0_LIBRARY}")
|
||||
if(LIBUDEV_LIBRARY)
|
||||
set(HIDAPI_LIBRARIES "${HIDAPI_LIBRARIES};${LIBUDEV_LIBRARY}")
|
||||
else()
|
||||
message(WARNING "libudev library not found, binaries may fail to link.")
|
||||
endif()
|
||||
else()
|
||||
message(WARNING "libusb-1.0 library not found, binaries may fail to link.")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(HIDAPI_INCLUDE_DIRS "${HIDAPI_INCLUDE_DIR}")
|
||||
endif()
|
||||
|
||||
mark_as_advanced(HIDAPI_INCLUDE_DIR HIDAPI_LIBRARY)
|
||||
@@ -1,54 +0,0 @@
|
||||
# - Find PCSC
|
||||
# Find the native PCSC includes and library
|
||||
#
|
||||
# PCSC_INCLUDE_DIR - where to find winscard.h, wintypes.h, etc.
|
||||
# PCSC_LIBRARIES - List of libraries when using PCSC.
|
||||
# PCSC_FOUND - True if PCSC found.
|
||||
|
||||
|
||||
IF (PCSC_INCLUDE_DIR AND PCSC_LIBRARIES)
|
||||
# Already in cache, be silent
|
||||
SET(PCSC_FIND_QUIETLY TRUE)
|
||||
ENDIF (PCSC_INCLUDE_DIR AND PCSC_LIBRARIES)
|
||||
|
||||
IF (NOT WIN32)
|
||||
FIND_PACKAGE(PkgConfig)
|
||||
PKG_CHECK_MODULES(PC_PCSC libpcsclite)
|
||||
|
||||
FIND_PATH(PCSC_INCLUDE_DIR winscard.h
|
||||
HINTS
|
||||
/usr/include/PCSC
|
||||
${PC_PCSC_INCLUDEDIR}
|
||||
${PC_PCSC_INCLUDE_DIRS}
|
||||
PATH_SUFFIXES PCSC
|
||||
)
|
||||
|
||||
FIND_LIBRARY(PCSC_LIBRARY NAMES pcsclite libpcsclite PCSC
|
||||
HINTS
|
||||
${PC_PCSC_LIBDIR}
|
||||
${PC_PCSC_LIBRARY_DIRS}
|
||||
)
|
||||
|
||||
ELSE (NOT WIN32)
|
||||
IF(BUILD_64 STREQUAL "ON")
|
||||
set(PCSC_INCLUDE_DIR /mingw64/x86_64-w64-mingw32/include)
|
||||
set(PCSC_LIBRARY /mingw64/x86_64-w64-mingw32/lib/libwinscard.a)
|
||||
ELSE(BUILD_64 STREQUAL "ON")
|
||||
set(PCSC_INCLUDE_DIR /mingw32/i686-w64-mingw32/include)
|
||||
set(PCSC_LIBRARY /mingw32/i686-w64-mingw32/lib/libwinscard.a)
|
||||
ENDIF(BUILD_64 STREQUAL "ON")
|
||||
ENDIF (NOT WIN32)
|
||||
|
||||
# handle the QUIETLY and REQUIRED arguments and set PCSC_FOUND to TRUE if
|
||||
# all listed variables are TRUE
|
||||
INCLUDE(FindPackageHandleStandardArgs)
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(PCSC DEFAULT_MSG PCSC_LIBRARY PCSC_INCLUDE_DIR)
|
||||
|
||||
IF(PCSC_FOUND)
|
||||
SET( PCSC_LIBRARIES ${PCSC_LIBRARY} )
|
||||
SET(PCSC_STATIC_LIBRARIES ${PCSC_STATIC_LIBRARY})
|
||||
ELSE(PCSC_FOUND)
|
||||
SET( PCSC_LIBRARIES )
|
||||
ENDIF(PCSC_FOUND)
|
||||
|
||||
MARK_AS_ADVANCED( PCSC_LIBRARY PCSC_INCLUDE_DIR PCSC_STATIC_LIBRARY)
|
||||
@@ -23,7 +23,7 @@
|
||||
|
||||
find_path(Readline_ROOT_DIR
|
||||
NAMES include/readline/readline.h
|
||||
PATHS /opt/local/ /usr/local/ /usr/
|
||||
PATHS /usr/local/opt/readline/ /opt/local/ /usr/local/ /usr/
|
||||
NO_DEFAULT_PATH
|
||||
)
|
||||
|
||||
|
||||
18
contrib/codefresh/codefresh.yml
Normal file
18
contrib/codefresh/codefresh.yml
Normal file
@@ -0,0 +1,18 @@
|
||||
version: '1.0'
|
||||
steps:
|
||||
init_submodules:
|
||||
title: Init Submodules
|
||||
commands:
|
||||
- git submodule update --init --recursive
|
||||
image: codefreshio/git-image:latest
|
||||
working_directory: ${{main_clone}}
|
||||
|
||||
BuildingDockerImage:
|
||||
title: Building Docker Image
|
||||
type: build
|
||||
image_name: monero
|
||||
working_directory: ./
|
||||
tag: '${{CF_BRANCH_TAG_NORMALIZED}}'
|
||||
dockerfile: Dockerfile
|
||||
build_arguments:
|
||||
- NPROC=1
|
||||
@@ -52,6 +52,13 @@ Additional targets:
|
||||
download-win: run 'make download-win' to fetch all sources needed for win builds
|
||||
download-linux: run 'make download-linux' to fetch all sources needed for linux builds
|
||||
|
||||
#Darwin (macos) builds:
|
||||
|
||||
To build with the x86_64-apple-darwin11 you require the mac os developer tools in MacOSX10.11.sdk.
|
||||
Download it from apple, or search for it on github. Create a new directoty called SDKs in this
|
||||
directory and place the entire MacOSX10.11.sdk folder in it. The depends build will then pick it up automatically
|
||||
(without requiring SDK_PATH).
|
||||
|
||||
### Other documentation
|
||||
|
||||
- [description.md](description.md): General description of the depends system
|
||||
|
||||
25
contrib/depends/packages/eudev.mk
Normal file
25
contrib/depends/packages/eudev.mk
Normal file
@@ -0,0 +1,25 @@
|
||||
package=eudev
|
||||
$(package)_version=v3.2.6
|
||||
$(package)_download_path=https://github.com/gentoo/eudev/archive/
|
||||
$(package)_file_name=$($(package)_version).tar.gz
|
||||
$(package)_sha256_hash=a96ecb8637667897b8bd4dee4c22c7c5f08b327be45186e912ce6bc768385852
|
||||
|
||||
define $(package)_set_vars
|
||||
$(package)_config_opts=--disable-gudev --disable-introspection --disable-hwdb --disable-manpages --disable-shared
|
||||
endef
|
||||
|
||||
define $(package)_config_cmds
|
||||
$($(package)_autoconf)
|
||||
endef
|
||||
|
||||
define $(package)_build_cmd
|
||||
$(MAKE)
|
||||
endef
|
||||
|
||||
define $(package)_preprocess_cmds
|
||||
cd $($(package)_build_subdir); autoreconf -f -i
|
||||
endef
|
||||
|
||||
define $(package)_stage_cmds
|
||||
$(MAKE) DESTDIR=$($(package)_staging_dir) install
|
||||
endef
|
||||
30
contrib/depends/packages/hidapi.mk
Normal file
30
contrib/depends/packages/hidapi.mk
Normal file
@@ -0,0 +1,30 @@
|
||||
package=hidapi
|
||||
$(package)_version=0.8.0-rc1
|
||||
$(package)_download_path=https://github.com/signal11/hidapi/archive
|
||||
$(package)_file_name=$(package)-$($(package)_version).tar.gz
|
||||
$(package)_sha256_hash=3c147200bf48a04c1e927cd81589c5ddceff61e6dac137a605f6ac9793f4af61
|
||||
$(package)_linux_dependencies=libusb eudev
|
||||
|
||||
define $(package)_set_vars
|
||||
$(package)_config_opts=--enable-static --disable-shared
|
||||
$(package)_config_opts+=--prefix=$(host_prefix)
|
||||
$(package)_config_opts_darwin+=RANLIB="$(host_prefix)/native/bin/x86_64-apple-darwin11-ranlib" AR="$(host_prefix)/native/bin/x86_64-apple-darwin11-ar" CC="$(host_prefix)/native/bin/$($(package)_cc)"
|
||||
$(package)_config_opts_linux+=libudev_LIBS="-L$(host_prefix)/lib -ludev"
|
||||
$(package)_config_opts_linux+=libudev_CFLAGS=-I$(host_prefix)/include
|
||||
$(package)_config_opts_linux+=libusb_LIBS="-L$(host_prefix)/lib -lusb-1.0"
|
||||
$(package)_config_opts_linux+=libusb_CFLAGS=-I$(host_prefix)/include/libusb-1.0
|
||||
$(package)_config_opts_linux+=--with-pic
|
||||
endef
|
||||
|
||||
define $(package)_config_cmds
|
||||
./bootstrap &&\
|
||||
$($(package)_autoconf) $($(package)_config_opts)
|
||||
endef
|
||||
|
||||
define $(package)_build_cmds
|
||||
$(MAKE)
|
||||
endef
|
||||
|
||||
define $(package)_stage_cmds
|
||||
$(MAKE) DESTDIR=$($(package)_staging_dir) install
|
||||
endef
|
||||
31
contrib/depends/packages/libusb.mk
Normal file
31
contrib/depends/packages/libusb.mk
Normal file
@@ -0,0 +1,31 @@
|
||||
package=libusb
|
||||
$(package)_version=1.0.9
|
||||
$(package)_download_path=http://sourceforge.net/projects/libusb/files/libusb-1.0/libusb-1.0.9/
|
||||
$(package)_file_name=$(package)-$($(package)_version).tar.bz2
|
||||
$(package)_sha256_hash=e920eedc2d06b09606611c99ec7304413c6784cba6e33928e78243d323195f9b
|
||||
|
||||
define $(package)_preprocess_cmds
|
||||
autoreconf -i
|
||||
endef
|
||||
|
||||
define $(package)_set_vars
|
||||
$(package)_config_opts=--disable-shared
|
||||
$(package)_config_opts_linux=--with-pic
|
||||
endef
|
||||
|
||||
define $(package)_config_cmds
|
||||
cp -f $(BASEDIR)/config.guess config.guess &&\
|
||||
cp -f $(BASEDIR)/config.sub config.sub &&\
|
||||
$($(package)_autoconf)
|
||||
endef
|
||||
|
||||
define $(package)_build_cmd
|
||||
$(MAKE)
|
||||
endef
|
||||
|
||||
define $(package)_stage_cmds
|
||||
$(MAKE) DESTDIR=$($(package)_staging_dir) install
|
||||
endef
|
||||
|
||||
define $(package)_postprocess_cmds cp -f lib/libusb-1.0.a lib/libusb.a
|
||||
endef
|
||||
@@ -1,13 +1,14 @@
|
||||
packages:=boost openssl libevent zeromq cppzmq zlib expat ldns cppzmq readline libiconv qt
|
||||
packages:=boost openssl libevent zeromq cppzmq zlib expat ldns cppzmq readline libiconv qt hidapi
|
||||
native_packages := native_ccache
|
||||
|
||||
wallet_packages=bdb
|
||||
|
||||
darwin_native_packages = native_biplist native_ds_store native_mac_alias
|
||||
darwin_packages += sodium-darwin
|
||||
darwin_packages = sodium-darwin
|
||||
|
||||
linux_packages = eudev libusb
|
||||
|
||||
ifeq ($(host_os),linux)
|
||||
packages += pcsc-lite
|
||||
packages += unwind
|
||||
packages += sodium
|
||||
endif
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
package=pcsc-lite
|
||||
$(package)_version=1.8.23
|
||||
$(package)_download_path=https://pcsclite.apdu.fr/files
|
||||
$(package)_file_name=$(package)-$($(package)_version).tar.bz2
|
||||
$(package)_sha256_hash=5a27262586eff39cfd5c19aadc8891dd71c0818d3d629539bd631b958be689c9
|
||||
|
||||
define $(package)_set_vars
|
||||
$(package)_build_opts=CC="$($(package)_cc)"
|
||||
$(package)_config_env=AR="$($(package)_ar)" RANLIB="$($(package)_ranlib)" CC="$($(package)_cc)"
|
||||
$(package)_config_opts=--prefix=$(host_prefix)
|
||||
$(package)_config_opts_release=--disable-debug-mode --disable-libsystemd --disable-libudev --enable-static --disable-shared --disable-libusb
|
||||
$(package)_build_opts=CFLAGS="$($(package)_cflags) $($(package)_cppflags) -fPIC"
|
||||
endef
|
||||
|
||||
define $(package)_config_cmds
|
||||
./bootstrap &&\
|
||||
$($(package)_autoconf) $($(package)_config_opts)
|
||||
endef
|
||||
|
||||
define $(package)_build_cmds
|
||||
$(MAKE) $($(package)_build_opts)
|
||||
endef
|
||||
|
||||
define $(package)_stage_cmds
|
||||
$(MAKE) DESTDIR=$($(package)_staging_dir) install
|
||||
endef
|
||||
@@ -5,13 +5,14 @@ $(package)_file_name=libsodium-$($(package)_version).tar.gz
|
||||
$(package)_sha256_hash=fb6a9e879a2f674592e4328c5d9f79f082405ee4bb05cb6e679b90afe9e178f4
|
||||
|
||||
define $(package)_set_vars
|
||||
$(package)_config_opts=--enable-static
|
||||
$(package)_build_opts_darwin=OS=Darwin LIBTOOL="$($(package)_libtool)"
|
||||
$(package)_config_opts=--enable-static --disable-shared
|
||||
$(package)_config_opts+=--prefix=$(host_prefix)
|
||||
endef
|
||||
|
||||
define $(package)_config_cmds
|
||||
./autogen.sh &&\
|
||||
$($(package)_autoconf) $($(package)_config_opts) RANLIB="$(host_prefix)/native/bin/x86_64-apple-darwin11-ranlib" AR="$(host_prefix)/native/bin/x86_64-apple-darwin11-ar"
|
||||
$($(package)_autoconf) $($(package)_config_opts) RANLIB="$(host_prefix)/native/bin/x86_64-apple-darwin11-ranlib" AR="$(host_prefix)/native/bin/x86_64-apple-darwin11-ar" CC="$(host_prefix)/native/bin/$($(package)_cc)"
|
||||
endef
|
||||
|
||||
define $(package)_build_cmds
|
||||
|
||||
@@ -5,7 +5,7 @@ $(package)_file_name=libsodium-$($(package)_version).tar.gz
|
||||
$(package)_sha256_hash=fb6a9e879a2f674592e4328c5d9f79f082405ee4bb05cb6e679b90afe9e178f4
|
||||
|
||||
define $(package)_set_vars
|
||||
$(package)_config_opts=--enable-static
|
||||
$(package)_config_opts=--enable-static --disable-shared
|
||||
$(package)_config_opts+=--prefix=$(host_prefix)
|
||||
endef
|
||||
|
||||
|
||||
@@ -18,6 +18,9 @@ SET(LIBUNWIND_INCLUDE_DIR @prefix@/include)
|
||||
SET(LIBUNWIND_LIBRARIES @prefix@/lib/libunwind.a)
|
||||
SET(LIBUNWIND_LIBRARY_DIRS @prefix@/lib)
|
||||
|
||||
SET(LIBUSB-1.0_LIBRARY @prefix@/lib/libusb-1.0.a)
|
||||
SET(LIBUDEV_LIBRARY @prefix@/lib/libudev.a)
|
||||
|
||||
SET(ZMQ_INCLUDE_PATH @prefix@/include)
|
||||
SET(ZMQ_LIB @prefix@/lib/libzmq.a)
|
||||
|
||||
@@ -38,6 +41,8 @@ set (CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) # Find programs on host
|
||||
set (CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) # Find libs in target
|
||||
set (CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) # Find includes in target
|
||||
|
||||
set(CMAKE_SYSTEM_PROCESSOR ${CMAKE_HOST_SYSTEM_PROCESSOR} CACHE STRING "" FORCE)
|
||||
|
||||
# specify the cross compiler to be used. Darwin uses clang provided by the SDK.
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
|
||||
SET(CMAKE_C_COMPILER @prefix@/native/bin/clang)
|
||||
@@ -48,7 +53,9 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
|
||||
SET(APPLE True)
|
||||
SET(BUILD_TAG "mac-x64")
|
||||
SET(BUILD_64 ON)
|
||||
if(NOT TRAVIS)
|
||||
SET(ARCH "x86_64")
|
||||
endif()
|
||||
SET(BREW OFF)
|
||||
SET(PORT OFF)
|
||||
SET(CMAKE_OSX_SYSROOT "@sdk@/MacOSX10.11.sdk/")
|
||||
@@ -78,5 +85,14 @@ elseif(ARCHITECTURE STREQUAL "aarch64")
|
||||
set(BUILD_64 ON)
|
||||
endif()
|
||||
|
||||
if(ARCHITECTURE STREQUAL "i686" AND CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||
SET(LINUX_32 ON)
|
||||
SET(ARCH_ID "i386")
|
||||
endif()
|
||||
|
||||
if(ARCHITECTURE STREQUAL "x86_64" AND CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||
SET(ARCH_ID "x86_64")
|
||||
endif()
|
||||
|
||||
#Create a new global cmake flag that indicates building with depends
|
||||
set (DEPENDS true)
|
||||
|
||||
@@ -63,7 +63,8 @@ namespace epee
|
||||
|
||||
~async_stdin_reader()
|
||||
{
|
||||
stop();
|
||||
try { stop(); }
|
||||
catch (...) { /* ignore */ }
|
||||
}
|
||||
|
||||
#ifdef HAVE_READLINE
|
||||
@@ -351,8 +352,11 @@ eof:
|
||||
|
||||
std::string command;
|
||||
bool get_line_ret = m_stdin_reader.get_line(command);
|
||||
if (!m_running || m_stdin_reader.eos())
|
||||
if (!m_running)
|
||||
break;
|
||||
if (m_stdin_reader.eos())
|
||||
{
|
||||
MGINFO("EOF on stdin, exiting");
|
||||
break;
|
||||
}
|
||||
if (!get_line_ret)
|
||||
|
||||
45
contrib/epee/include/fnv1.h
Normal file
45
contrib/epee/include/fnv1.h
Normal file
@@ -0,0 +1,45 @@
|
||||
// Copyright (c) 2018, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace epee
|
||||
{
|
||||
|
||||
namespace fnv
|
||||
{
|
||||
inline uint64_t FNV1a(const char *ptr, size_t sz)
|
||||
{
|
||||
uint64_t h = 0xcbf29ce484222325;
|
||||
for (size_t i = 0; i < sz; ++i)
|
||||
h = (h ^ *(const uint8_t*)ptr++) * 0x100000001b3;
|
||||
return h;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -33,6 +33,7 @@
|
||||
#include <iosfwd>
|
||||
#include <string>
|
||||
|
||||
#include "wipeable_string.h"
|
||||
#include "span.h"
|
||||
|
||||
namespace epee
|
||||
@@ -41,6 +42,9 @@ namespace epee
|
||||
{
|
||||
//! \return A std::string containing hex of `src`.
|
||||
static std::string string(const span<const std::uint8_t> src);
|
||||
//! \return A epee::wipeable_string containing hex of `src`.
|
||||
static epee::wipeable_string wipeable_string(const span<const std::uint8_t> src);
|
||||
template<typename T> static epee::wipeable_string wipeable_string(const T &pod) { return wipeable_string(span<const uint8_t>((const uint8_t*)&pod, sizeof(pod))); }
|
||||
|
||||
//! \return An array containing hex of `src`.
|
||||
template<std::size_t N>
|
||||
@@ -59,6 +63,8 @@ namespace epee
|
||||
static void formatted(std::ostream& out, const span<const std::uint8_t> src);
|
||||
|
||||
private:
|
||||
template<typename T> T static convert(const span<const std::uint8_t> src);
|
||||
|
||||
//! Write `src` bytes as hex to `out`. `out` must be twice the length
|
||||
static void buffer_unchecked(char* out, const span<const std::uint8_t> src) noexcept;
|
||||
};
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
|
||||
#define MONERO_DEFAULT_LOG_CATEGORY "default"
|
||||
#define MAX_LOG_FILE_SIZE 104850000 // 100 MB - 7600 bytes
|
||||
#define MAX_LOG_FILES 50
|
||||
|
||||
#define MCFATAL(cat,x) CLOG(FATAL,cat) << x
|
||||
#define MCERROR(cat,x) CLOG(ERROR,cat) << x
|
||||
@@ -105,7 +106,7 @@
|
||||
#endif
|
||||
|
||||
std::string mlog_get_default_log_path(const char *default_filename);
|
||||
void mlog_configure(const std::string &filename_base, bool console, const std::size_t max_log_file_size = MAX_LOG_FILE_SIZE);
|
||||
void mlog_configure(const std::string &filename_base, bool console, const std::size_t max_log_file_size = MAX_LOG_FILE_SIZE, const std::size_t max_log_files = MAX_LOG_FILES);
|
||||
void mlog_set_categories(const char *categories);
|
||||
std::string mlog_get_categories();
|
||||
void mlog_set_log_level(int level);
|
||||
|
||||
87
contrib/epee/include/mlocker.h
Normal file
87
contrib/epee/include/mlocker.h
Normal file
@@ -0,0 +1,87 @@
|
||||
// Copyright (c) 2018, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
|
||||
namespace epee
|
||||
{
|
||||
class mlocker
|
||||
{
|
||||
public:
|
||||
mlocker(void *ptr, size_t len);
|
||||
~mlocker();
|
||||
|
||||
static size_t get_page_size();
|
||||
static size_t get_num_locked_pages();
|
||||
static size_t get_num_locked_objects();
|
||||
|
||||
static void lock(void *ptr, size_t len);
|
||||
static void unlock(void *ptr, size_t len);
|
||||
|
||||
private:
|
||||
static size_t page_size;
|
||||
static size_t num_locked_objects;
|
||||
|
||||
static boost::mutex &mutex();
|
||||
static std::map<size_t, unsigned int> &map();
|
||||
static void lock_page(size_t page);
|
||||
static void unlock_page(size_t page);
|
||||
|
||||
void *ptr;
|
||||
size_t len;
|
||||
};
|
||||
|
||||
/// Locks memory while in scope
|
||||
///
|
||||
/// Primarily useful for making sure that private keys don't get swapped out
|
||||
// to disk
|
||||
template <class T>
|
||||
struct mlocked : public T {
|
||||
using type = T;
|
||||
|
||||
mlocked(): T() { mlocker::lock(this, sizeof(T)); }
|
||||
mlocked(const T &t): T(t) { mlocker::lock(this, sizeof(T)); }
|
||||
mlocked(const mlocked<T> &mt): T(mt) { mlocker::lock(this, sizeof(T)); }
|
||||
mlocked(const T &&t): T(t) { mlocker::lock(this, sizeof(T)); }
|
||||
mlocked(const mlocked<T> &&mt): T(mt) { mlocker::lock(this, sizeof(T)); }
|
||||
mlocked<T> &operator=(const mlocked<T> &mt) { T::operator=(mt); return *this; }
|
||||
~mlocked() { mlocker::unlock(this, sizeof(T)); }
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
T& unwrap(mlocked<T>& src) { return src; }
|
||||
|
||||
template<typename T>
|
||||
const T& unwrap(mlocked<T> const& src) { return src; }
|
||||
|
||||
template <class T, size_t N>
|
||||
using mlocked_arr = mlocked<std::array<T, N>>;
|
||||
}
|
||||
@@ -1109,8 +1109,16 @@ POP_WARNINGS
|
||||
sock_.open(remote_endpoint.protocol());
|
||||
if(bind_ip != "0.0.0.0" && bind_ip != "0" && bind_ip != "" )
|
||||
{
|
||||
boost::asio::ip::tcp::endpoint local_endpoint(boost::asio::ip::address::from_string(adr.c_str()), 0);
|
||||
sock_.bind(local_endpoint);
|
||||
boost::asio::ip::tcp::endpoint local_endpoint(boost::asio::ip::address::from_string(bind_ip.c_str()), 0);
|
||||
boost::system::error_code ec;
|
||||
sock_.bind(local_endpoint, ec);
|
||||
if (ec)
|
||||
{
|
||||
MERROR("Error binding to " << bind_ip << ": " << ec.message());
|
||||
if (sock_.is_open())
|
||||
sock_.close();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1215,8 +1223,16 @@ POP_WARNINGS
|
||||
sock_.open(remote_endpoint.protocol());
|
||||
if(bind_ip != "0.0.0.0" && bind_ip != "0" && bind_ip != "" )
|
||||
{
|
||||
boost::asio::ip::tcp::endpoint local_endpoint(boost::asio::ip::address::from_string(adr.c_str()), 0);
|
||||
sock_.bind(local_endpoint);
|
||||
boost::asio::ip::tcp::endpoint local_endpoint(boost::asio::ip::address::from_string(bind_ip.c_str()), 0);
|
||||
boost::system::error_code ec;
|
||||
sock_.bind(local_endpoint, ec);
|
||||
if (ec)
|
||||
{
|
||||
MERROR("Error binding to " << bind_ip << ": " << ec.message());
|
||||
if (sock_.is_open())
|
||||
sock_.close();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
boost::shared_ptr<boost::asio::deadline_timer> sh_deadline(new boost::asio::deadline_timer(io_service_));
|
||||
|
||||
@@ -69,7 +69,7 @@ namespace net_utils
|
||||
typedef t_connection_context connection_context;//t_connection_context net_utils::connection_context_base connection_context;
|
||||
typedef http_server_config config_type;
|
||||
|
||||
simple_http_connection_handler(i_service_endpoint* psnd_hndlr, config_type& config);
|
||||
simple_http_connection_handler(i_service_endpoint* psnd_hndlr, config_type& config, t_connection_context& conn_context);
|
||||
virtual ~simple_http_connection_handler(){}
|
||||
|
||||
bool release_protocol()
|
||||
@@ -144,6 +144,7 @@ namespace net_utils
|
||||
size_t m_newlines;
|
||||
protected:
|
||||
i_service_endpoint* m_psnd_hndlr;
|
||||
t_connection_context& m_conn_context;
|
||||
};
|
||||
|
||||
template<class t_connection_context>
|
||||
@@ -175,9 +176,8 @@ namespace net_utils
|
||||
typedef custum_handler_config<t_connection_context> config_type;
|
||||
|
||||
http_custom_handler(i_service_endpoint* psnd_hndlr, config_type& config, t_connection_context& conn_context)
|
||||
: simple_http_connection_handler<t_connection_context>(psnd_hndlr, config),
|
||||
: simple_http_connection_handler<t_connection_context>(psnd_hndlr, config, conn_context),
|
||||
m_config(config),
|
||||
m_conn_context(conn_context),
|
||||
m_auth(m_config.m_user ? http_server_auth{*m_config.m_user, config.rng} : http_server_auth{})
|
||||
{}
|
||||
inline bool handle_request(const http_request_info& query_info, http_response_info& response)
|
||||
@@ -197,7 +197,7 @@ namespace net_utils
|
||||
response.m_response_comment = "OK";
|
||||
response.m_body.clear();
|
||||
|
||||
return m_config.m_phandler->handle_http_request(query_info, response, m_conn_context);
|
||||
return m_config.m_phandler->handle_http_request(query_info, response, this->m_conn_context);
|
||||
}
|
||||
|
||||
virtual bool thread_init()
|
||||
@@ -219,7 +219,6 @@ namespace net_utils
|
||||
private:
|
||||
//simple_http_connection_handler::config_type m_stub_config;
|
||||
config_type& m_config;
|
||||
t_connection_context& m_conn_context;
|
||||
http_server_auth m_auth;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -196,16 +196,17 @@ namespace net_utils
|
||||
|
||||
//--------------------------------------------------------------------------------------------
|
||||
template<class t_connection_context>
|
||||
simple_http_connection_handler<t_connection_context>::simple_http_connection_handler(i_service_endpoint* psnd_hndlr, config_type& config):
|
||||
simple_http_connection_handler<t_connection_context>::simple_http_connection_handler(i_service_endpoint* psnd_hndlr, config_type& config, t_connection_context& conn_context):
|
||||
m_state(http_state_retriving_comand_line),
|
||||
m_body_transfer_type(http_body_transfer_undefined),
|
||||
m_is_stop_handling(false),
|
||||
m_is_stop_handling(false),
|
||||
m_len_summary(0),
|
||||
m_len_remain(0),
|
||||
m_config(config),
|
||||
m_config(config),
|
||||
m_want_close(false),
|
||||
m_newlines(0),
|
||||
m_psnd_hndlr(psnd_hndlr)
|
||||
m_psnd_hndlr(psnd_hndlr),
|
||||
m_conn_context(conn_context)
|
||||
{
|
||||
|
||||
}
|
||||
@@ -281,7 +282,7 @@ namespace net_utils
|
||||
m_is_stop_handling = true;
|
||||
if(m_cache.size() > HTTP_MAX_URI_LEN)
|
||||
{
|
||||
LOG_ERROR("simple_http_connection_handler::handle_buff_out: Too long URI line");
|
||||
LOG_ERROR_CC(m_conn_context, "simple_http_connection_handler::handle_buff_out: Too long URI line");
|
||||
m_state = http_state_error;
|
||||
return false;
|
||||
}
|
||||
@@ -295,7 +296,7 @@ namespace net_utils
|
||||
m_is_stop_handling = true;
|
||||
if(m_cache.size() > HTTP_MAX_HEADER_LEN)
|
||||
{
|
||||
LOG_ERROR("simple_http_connection_handler::handle_buff_in: Too long header area");
|
||||
LOG_ERROR_CC(m_conn_context, "simple_http_connection_handler::handle_buff_in: Too long header area");
|
||||
m_state = http_state_error;
|
||||
return false;
|
||||
}
|
||||
@@ -310,10 +311,10 @@ namespace net_utils
|
||||
case http_state_connection_close:
|
||||
return false;
|
||||
default:
|
||||
LOG_ERROR("simple_http_connection_handler::handle_char_out: Wrong state: " << m_state);
|
||||
LOG_ERROR_CC(m_conn_context, "simple_http_connection_handler::handle_char_out: Wrong state: " << m_state);
|
||||
return false;
|
||||
case http_state_error:
|
||||
LOG_ERROR("simple_http_connection_handler::handle_char_out: Error state!!!");
|
||||
LOG_ERROR_CC(m_conn_context, "simple_http_connection_handler::handle_char_out: Error state!!!");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -327,8 +328,10 @@ namespace net_utils
|
||||
inline bool analize_http_method(const boost::smatch& result, http::http_method& method, int& http_ver_major, int& http_ver_minor)
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(result[0].matched, false, "simple_http_connection_handler::analize_http_method() assert failed...");
|
||||
http_ver_major = boost::lexical_cast<int>(result[11]);
|
||||
http_ver_minor = boost::lexical_cast<int>(result[12]);
|
||||
if (!boost::conversion::try_lexical_convert<int>(result[11], http_ver_major))
|
||||
return false;
|
||||
if (!boost::conversion::try_lexical_convert<int>(result[12], http_ver_minor))
|
||||
return false;
|
||||
|
||||
if(result[3].matched)
|
||||
method = http::http_method_options;
|
||||
@@ -350,13 +353,18 @@ namespace net_utils
|
||||
template<class t_connection_context>
|
||||
bool simple_http_connection_handler<t_connection_context>::handle_invoke_query_line()
|
||||
{
|
||||
STATIC_REGEXP_EXPR_1(rexp_match_command_line, "^(((OPTIONS)|(GET)|(HEAD)|(POST)|(PUT)|(DELETE)|(TRACE)) (\\S+) HTTP/(\\d+).(\\d+))\r?\n", boost::regex::icase | boost::regex::normal);
|
||||
STATIC_REGEXP_EXPR_1(rexp_match_command_line, "^(((OPTIONS)|(GET)|(HEAD)|(POST)|(PUT)|(DELETE)|(TRACE)) (\\S+) HTTP/(\\d+)\\.(\\d+))\r?\n", boost::regex::icase | boost::regex::normal);
|
||||
// 123 4 5 6 7 8 9 10 11 12
|
||||
//size_t match_len = 0;
|
||||
boost::smatch result;
|
||||
if(boost::regex_search(m_cache, result, rexp_match_command_line, boost::match_default) && result[0].matched)
|
||||
{
|
||||
analize_http_method(result, m_query_info.m_http_method, m_query_info.m_http_ver_hi, m_query_info.m_http_ver_hi);
|
||||
if (!analize_http_method(result, m_query_info.m_http_method, m_query_info.m_http_ver_hi, m_query_info.m_http_ver_hi))
|
||||
{
|
||||
m_state = http_state_error;
|
||||
MERROR("Failed to analyze method");
|
||||
return false;
|
||||
}
|
||||
m_query_info.m_URI = result[10];
|
||||
if (!parse_uri(m_query_info.m_URI, m_query_info.m_uri_content))
|
||||
{
|
||||
@@ -375,7 +383,7 @@ namespace net_utils
|
||||
}else
|
||||
{
|
||||
m_state = http_state_error;
|
||||
LOG_ERROR("simple_http_connection_handler<t_connection_context>::handle_invoke_query_line(): Failed to match first line: " << m_cache);
|
||||
LOG_ERROR_CC(m_conn_context, "simple_http_connection_handler<t_connection_context>::handle_invoke_query_line(): Failed to match first line: " << m_cache);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -406,7 +414,7 @@ namespace net_utils
|
||||
|
||||
if(!parse_cached_header(m_query_info.m_header_info, m_cache, pos))
|
||||
{
|
||||
LOG_ERROR("simple_http_connection_handler<t_connection_context>::analize_cached_request_header_and_invoke_state(): failed to anilize request header: " << m_cache);
|
||||
LOG_ERROR_CC(m_conn_context, "simple_http_connection_handler<t_connection_context>::analize_cached_request_header_and_invoke_state(): failed to anilize request header: " << m_cache);
|
||||
m_state = http_state_error;
|
||||
return false;
|
||||
}
|
||||
@@ -422,7 +430,7 @@ namespace net_utils
|
||||
m_body_transfer_type = http_body_transfer_measure;
|
||||
if(!get_len_from_content_lenght(m_query_info.m_header_info.m_content_length, m_len_summary))
|
||||
{
|
||||
LOG_ERROR("simple_http_connection_handler<t_connection_context>::analize_cached_request_header_and_invoke_state(): Failed to get_len_from_content_lenght();, m_query_info.m_content_length="<<m_query_info.m_header_info.m_content_length);
|
||||
LOG_ERROR_CC(m_conn_context, "simple_http_connection_handler<t_connection_context>::analize_cached_request_header_and_invoke_state(): Failed to get_len_from_content_lenght();, m_query_info.m_content_length="<<m_query_info.m_header_info.m_content_length);
|
||||
m_state = http_state_error;
|
||||
return false;
|
||||
}
|
||||
@@ -455,7 +463,7 @@ namespace net_utils
|
||||
case http_body_transfer_multipart:
|
||||
case http_body_transfer_undefined:
|
||||
default:
|
||||
LOG_ERROR("simple_http_connection_handler<t_connection_context>::handle_retriving_query_body(): Unexpected m_body_query_type state:" << m_body_transfer_type);
|
||||
LOG_ERROR_CC(m_conn_context, "simple_http_connection_handler<t_connection_context>::handle_retriving_query_body(): Unexpected m_body_query_type state:" << m_body_transfer_type);
|
||||
m_state = http_state_error;
|
||||
return false;
|
||||
}
|
||||
@@ -536,7 +544,7 @@ namespace net_utils
|
||||
body_info.m_etc_fields.push_back(std::pair<std::string, std::string>(result[field_etc_name], result[field_val]));
|
||||
else
|
||||
{
|
||||
LOG_ERROR("simple_http_connection_handler<t_connection_context>::parse_cached_header() not matched last entry in:"<<m_cache_to_process);
|
||||
LOG_ERROR_CC(m_conn_context, "simple_http_connection_handler<t_connection_context>::parse_cached_header() not matched last entry in:" << m_cache_to_process);
|
||||
}
|
||||
|
||||
it_current_bound = result[(int)result.size()-1]. first;
|
||||
@@ -553,7 +561,8 @@ namespace net_utils
|
||||
if(!(boost::regex_search( str, result, rexp_mach_field, boost::match_default) && result[0].matched))
|
||||
return false;
|
||||
|
||||
len = boost::lexical_cast<size_t>(result[0]);
|
||||
try { len = boost::lexical_cast<size_t>(result[0]); }
|
||||
catch(...) { return false; }
|
||||
return true;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------
|
||||
|
||||
@@ -275,6 +275,9 @@ public:
|
||||
}
|
||||
virtual ~async_protocol_handler()
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
m_deletion_initiated = true;
|
||||
if(m_connection_initialized)
|
||||
{
|
||||
@@ -288,6 +291,9 @@ public:
|
||||
CHECK_AND_ASSERT_MES_NO_RET(0 == boost::interprocess::ipcdetail::atomic_read32(&m_wait_count), "Failed to wait for operation completion. m_wait_count = " << m_wait_count);
|
||||
|
||||
MTRACE(m_connection_context << "~async_protocol_handler()");
|
||||
|
||||
}
|
||||
catch (...) { /* ignore */ }
|
||||
}
|
||||
|
||||
bool start_outer_call()
|
||||
|
||||
@@ -106,7 +106,8 @@ namespace net_utils
|
||||
~blocked_mode_client()
|
||||
{
|
||||
//profile_tools::local_coast lc("~blocked_mode_client()", 3);
|
||||
shutdown();
|
||||
try { shutdown(); }
|
||||
catch(...) { /* ignore */ }
|
||||
}
|
||||
|
||||
inline
|
||||
|
||||
@@ -85,6 +85,14 @@ public: \
|
||||
static_assert(std::is_pod<decltype(this_ref.varialble)>::value, "t_type must be a POD type."); \
|
||||
KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE_N(varialble, val_name)
|
||||
|
||||
#define KV_SERIALIZE_VAL_POD_AS_BLOB_OPT_N(varialble, val_name, default_value) \
|
||||
do { \
|
||||
static_assert(std::is_pod<decltype(this_ref.varialble)>::value, "t_type must be a POD type."); \
|
||||
bool ret = KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE_N(varialble, val_name); \
|
||||
if (!ret) \
|
||||
epee::serialize_default(this_ref.varialble, default_value); \
|
||||
} while(0);
|
||||
|
||||
#define KV_SERIALIZE_CONTAINER_POD_AS_BLOB_N(varialble, val_name) \
|
||||
epee::serialization::selector<is_store>::serialize_stl_container_pod_val_as_blob(this_ref.varialble, stg, hparent_section, val_name);
|
||||
|
||||
@@ -92,6 +100,7 @@ public: \
|
||||
|
||||
#define KV_SERIALIZE(varialble) KV_SERIALIZE_N(varialble, #varialble)
|
||||
#define KV_SERIALIZE_VAL_POD_AS_BLOB(varialble) KV_SERIALIZE_VAL_POD_AS_BLOB_N(varialble, #varialble)
|
||||
#define KV_SERIALIZE_VAL_POD_AS_BLOB_OPT(varialble, def) KV_SERIALIZE_VAL_POD_AS_BLOB_OPT_N(varialble, #varialble, def)
|
||||
#define KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE(varialble) KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE_N(varialble, #varialble) //skip is_pod compile time check
|
||||
#define KV_SERIALIZE_CONTAINER_POD_AS_BLOB(varialble) KV_SERIALIZE_CONTAINER_POD_AS_BLOB_N(varialble, #varialble)
|
||||
#define KV_SERIALIZE_OPT(variable,default_value) KV_SERIALIZE_OPT_N(variable, #variable, default_value)
|
||||
|
||||
@@ -161,7 +161,7 @@ namespace epee
|
||||
typename stl_container::value_type* pelem = (typename stl_container::value_type*)buff.data();
|
||||
CHECK_AND_ASSERT_MES(!(loaded_size%sizeof(typename stl_container::value_type)),
|
||||
false,
|
||||
"size in blob " << loaded_size << " not have not zero modulo for sizeof(value_type) = " << sizeof(typename stl_container::value_type));
|
||||
"size in blob " << loaded_size << " not have not zero modulo for sizeof(value_type) = " << sizeof(typename stl_container::value_type) << ", type " << typeid(typename stl_container::value_type).name());
|
||||
size_t count = (loaded_size/sizeof(typename stl_container::value_type));
|
||||
hint_resize(container, count);
|
||||
for(size_t i = 0; i < count; i++)
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
@@ -52,11 +53,15 @@ namespace epee
|
||||
template<typename T>
|
||||
class span
|
||||
{
|
||||
/* Supporting class types is tricky - the {ptr,len} constructor will allow
|
||||
derived-to-base conversions. This is NOT desireable because an array of
|
||||
derived types is not an array of base types. It is possible to handle
|
||||
this case, implement when/if needed. */
|
||||
static_assert(!std::is_class<T>(), "no class types are currently allowed");
|
||||
template<typename U>
|
||||
static constexpr bool safe_conversion() noexcept
|
||||
{
|
||||
// Allow exact matches or `T*` -> `const T*`.
|
||||
using with_const = typename std::add_const<U>::type;
|
||||
return std::is_same<T, U>() ||
|
||||
(std::is_const<T>() && std::is_same<T, with_const>());
|
||||
}
|
||||
|
||||
public:
|
||||
using value_type = T;
|
||||
using size_type = std::size_t;
|
||||
@@ -71,7 +76,9 @@ namespace epee
|
||||
constexpr span() noexcept : ptr(nullptr), len(0) {}
|
||||
constexpr span(std::nullptr_t) noexcept : span() {}
|
||||
|
||||
constexpr span(T* const src_ptr, const std::size_t count) noexcept
|
||||
//! Prevent derived-to-base conversions; invalid in this context.
|
||||
template<typename U, typename = typename std::enable_if<safe_conversion<U>()>::type>
|
||||
constexpr span(U* const src_ptr, const std::size_t count) noexcept
|
||||
: ptr(src_ptr), len(count) {}
|
||||
|
||||
//! Conversion from C-array. Prevents common bugs with sizeof + arrays.
|
||||
@@ -81,6 +88,16 @@ namespace epee
|
||||
constexpr span(const span&) noexcept = default;
|
||||
span& operator=(const span&) noexcept = default;
|
||||
|
||||
/*! Try to remove `amount` elements from beginning of span.
|
||||
\return Number of elements removed. */
|
||||
std::size_t remove_prefix(std::size_t amount) noexcept
|
||||
{
|
||||
amount = std::min(len, amount);
|
||||
ptr += amount;
|
||||
len -= amount;
|
||||
return amount;
|
||||
}
|
||||
|
||||
constexpr iterator begin() const noexcept { return ptr; }
|
||||
constexpr const_iterator cbegin() const noexcept { return ptr; }
|
||||
|
||||
@@ -105,6 +122,14 @@ namespace epee
|
||||
return {src.data(), src.size()};
|
||||
}
|
||||
|
||||
//! \return `span<T::value_type>` from a STL compatible `src`.
|
||||
template<typename T>
|
||||
constexpr span<typename T::value_type> to_mut_span(T& src)
|
||||
{
|
||||
// compiler provides diagnostic if size() is not size_t.
|
||||
return {src.data(), src.size()};
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
constexpr bool has_padding() noexcept
|
||||
{
|
||||
@@ -127,4 +152,13 @@ namespace epee
|
||||
static_assert(!has_padding<T>(), "source type may have padding");
|
||||
return {reinterpret_cast<const std::uint8_t*>(std::addressof(src)), sizeof(T)};
|
||||
}
|
||||
|
||||
//! \return `span<std::uint8_t>` which represents the bytes at `&src`.
|
||||
template<typename T>
|
||||
span<std::uint8_t> as_mut_byte_span(T& src) noexcept
|
||||
{
|
||||
static_assert(!std::is_empty<T>(), "empty types will not work -> sizeof == 1");
|
||||
static_assert(!has_padding<T>(), "source type may have padding");
|
||||
return {reinterpret_cast<std::uint8_t*>(std::addressof(src)), sizeof(T)};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,6 +46,7 @@
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
#include "hex.h"
|
||||
#include "memwipe.h"
|
||||
#include "mlocker.h"
|
||||
#include "span.h"
|
||||
#include "warnings.h"
|
||||
|
||||
@@ -358,6 +359,12 @@ POP_WARNINGS
|
||||
return hex_to_pod(hex_str, unwrap(s));
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
template<class t_pod_type>
|
||||
bool hex_to_pod(const std::string& hex_str, epee::mlocked<t_pod_type>& s)
|
||||
{
|
||||
return hex_to_pod(hex_str, unwrap(s));
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
bool validate_hex(uint64_t length, const std::string& str);
|
||||
//----------------------------------------------------------------------------
|
||||
inline std::string get_extension(const std::string& str)
|
||||
|
||||
@@ -28,28 +28,46 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <boost/optional/optional.hpp>
|
||||
#include <stddef.h>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include "memwipe.h"
|
||||
#include "fnv1.h"
|
||||
|
||||
namespace epee
|
||||
{
|
||||
class wipeable_string
|
||||
{
|
||||
public:
|
||||
typedef char value_type;
|
||||
|
||||
wipeable_string() {}
|
||||
wipeable_string(const wipeable_string &other);
|
||||
wipeable_string(wipeable_string &&other);
|
||||
wipeable_string(const std::string &other);
|
||||
wipeable_string(std::string &&other);
|
||||
wipeable_string(const char *s);
|
||||
wipeable_string(const char *s, size_t len);
|
||||
~wipeable_string();
|
||||
void wipe();
|
||||
void push_back(char c);
|
||||
void pop_back();
|
||||
void operator+=(char c);
|
||||
void operator+=(const std::string &s);
|
||||
void operator+=(const epee::wipeable_string &s);
|
||||
void operator+=(const char *s);
|
||||
void append(const char *ptr, size_t len);
|
||||
char pop_back();
|
||||
const char *data() const noexcept { return buffer.data(); }
|
||||
char *data() noexcept { return buffer.data(); }
|
||||
size_t size() const noexcept { return buffer.size(); }
|
||||
size_t length() const noexcept { return buffer.size(); }
|
||||
bool empty() const noexcept { return buffer.empty(); }
|
||||
void trim();
|
||||
void split(std::vector<wipeable_string> &fields) const;
|
||||
boost::optional<wipeable_string> parse_hexstr() const;
|
||||
template<typename T> inline bool hex_to_pod(T &pod) const;
|
||||
template<typename T> inline bool hex_to_pod(tools::scrubbed<T> &pod) const { return hex_to_pod(unwrap(pod)); }
|
||||
void resize(size_t sz);
|
||||
void reserve(size_t sz);
|
||||
void clear();
|
||||
@@ -64,4 +82,29 @@ namespace epee
|
||||
private:
|
||||
std::vector<char> buffer;
|
||||
};
|
||||
|
||||
template<typename T> inline bool wipeable_string::hex_to_pod(T &pod) const
|
||||
{
|
||||
static_assert(std::is_pod<T>::value, "expected pod type");
|
||||
if (size() != sizeof(T) * 2)
|
||||
return false;
|
||||
boost::optional<epee::wipeable_string> blob = parse_hexstr();
|
||||
if (!blob)
|
||||
return false;
|
||||
if (blob->size() != sizeof(T))
|
||||
return false;
|
||||
pod = *(const T*)blob->data();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
namespace std
|
||||
{
|
||||
template<> struct hash<epee::wipeable_string>
|
||||
{
|
||||
size_t operator()(const epee::wipeable_string &s) const
|
||||
{
|
||||
return epee::fnv::FNV1a(s.data(), s.size());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
add_library(epee STATIC hex.cpp http_auth.cpp mlog.cpp net_utils_base.cpp string_tools.cpp wipeable_string.cpp memwipe.c
|
||||
connection_basic.cpp network_throttle.cpp network_throttle-detail.cpp)
|
||||
connection_basic.cpp network_throttle.cpp network_throttle-detail.cpp mlocker.cpp)
|
||||
if (USE_READLINE AND GNU_READLINE_FOUND)
|
||||
add_library(epee_readline STATIC readline_buffer.cpp)
|
||||
endif()
|
||||
@@ -54,7 +54,9 @@ endif()
|
||||
target_link_libraries(epee
|
||||
PUBLIC
|
||||
easylogging
|
||||
${Boost_CHRONO_LIBRARY}
|
||||
${Boost_FILESYSTEM_LIBRARY}
|
||||
${Boost_THREAD_LIBRARY}
|
||||
PRIVATE
|
||||
${OPENSSL_LIBRARIES}
|
||||
${EXTRA_LIBRARIES})
|
||||
|
||||
@@ -52,17 +52,21 @@ namespace epee
|
||||
}
|
||||
}
|
||||
|
||||
std::string to_hex::string(const span<const std::uint8_t> src)
|
||||
template<typename T>
|
||||
T to_hex::convert(const span<const std::uint8_t> src)
|
||||
{
|
||||
if (std::numeric_limits<std::size_t>::max() / 2 < src.size())
|
||||
throw std::range_error("hex_view::to_string exceeded maximum size");
|
||||
|
||||
std::string out{};
|
||||
T out{};
|
||||
out.resize(src.size() * 2);
|
||||
buffer_unchecked(std::addressof(out[0]), src);
|
||||
to_hex::buffer_unchecked((char*)out.data(), src); // can't see the non const version in wipeable_string??
|
||||
return out;
|
||||
}
|
||||
|
||||
std::string to_hex::string(const span<const std::uint8_t> src) { return convert<std::string>(src); }
|
||||
epee::wipeable_string to_hex::wipeable_string(const span<const std::uint8_t> src) { return convert<epee::wipeable_string>(src); }
|
||||
|
||||
void to_hex::buffer(std::ostream& out, const span<const std::uint8_t> src)
|
||||
{
|
||||
write_hex(std::ostreambuf_iterator<char>{out}, src);
|
||||
|
||||
@@ -50,7 +50,7 @@
|
||||
|
||||
void *memwipe(void *ptr, size_t n)
|
||||
{
|
||||
if (memset_s(ptr, n, 0, n))
|
||||
if (n > 0 && memset_s(ptr, n, 0, n))
|
||||
{
|
||||
#ifdef NDEBUG
|
||||
fprintf(stderr, "Error: memset_s failed\n");
|
||||
@@ -67,7 +67,8 @@ void *memwipe(void *ptr, size_t n)
|
||||
|
||||
void *memwipe(void *ptr, size_t n)
|
||||
{
|
||||
explicit_bzero(ptr, n);
|
||||
if (n > 0)
|
||||
explicit_bzero(ptr, n);
|
||||
SCARECROW
|
||||
return ptr;
|
||||
}
|
||||
@@ -105,7 +106,8 @@ static void memory_cleanse(void *ptr, size_t len)
|
||||
|
||||
void *memwipe(void *ptr, size_t n)
|
||||
{
|
||||
memory_cleanse(ptr, n);
|
||||
if (n > 0)
|
||||
memory_cleanse(ptr, n);
|
||||
SCARECROW
|
||||
return ptr;
|
||||
}
|
||||
|
||||
181
contrib/epee/src/mlocker.cpp
Normal file
181
contrib/epee/src/mlocker.cpp
Normal file
@@ -0,0 +1,181 @@
|
||||
// Copyright (c) 2018, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#if defined __GNUC__ && !defined _WIN32
|
||||
#define HAVE_MLOCK 1
|
||||
#endif
|
||||
|
||||
#include <unistd.h>
|
||||
#if defined HAVE_MLOCK
|
||||
#include <sys/mman.h>
|
||||
#endif
|
||||
#include "misc_log_ex.h"
|
||||
#include "syncobj.h"
|
||||
#include "mlocker.h"
|
||||
|
||||
static size_t query_page_size()
|
||||
{
|
||||
#if defined HAVE_MLOCK
|
||||
long ret = sysconf(_SC_PAGESIZE);
|
||||
if (ret <= 0)
|
||||
{
|
||||
MERROR("Failed to determine page size");
|
||||
return 0;
|
||||
}
|
||||
return ret;
|
||||
#else
|
||||
#warning Missing query_page_size implementation
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void do_lock(void *ptr, size_t len)
|
||||
{
|
||||
#if defined HAVE_MLOCK
|
||||
int ret = mlock(ptr, len);
|
||||
if (ret < 0)
|
||||
MERROR("Error locking page at " << ptr << ": " << strerror(errno));
|
||||
#else
|
||||
#warning Missing do_lock implementation
|
||||
#endif
|
||||
}
|
||||
|
||||
static void do_unlock(void *ptr, size_t len)
|
||||
{
|
||||
#if defined HAVE_MLOCK
|
||||
int ret = munlock(ptr, len);
|
||||
if (ret < 0)
|
||||
MERROR("Error unlocking page at " << ptr << ": " << strerror(errno));
|
||||
#else
|
||||
#warning Missing implementation of page size detection
|
||||
#endif
|
||||
}
|
||||
|
||||
namespace epee
|
||||
{
|
||||
size_t mlocker::page_size = 0;
|
||||
size_t mlocker::num_locked_objects = 0;
|
||||
|
||||
boost::mutex &mlocker::mutex()
|
||||
{
|
||||
static boost::mutex *vmutex = new boost::mutex();
|
||||
return *vmutex;
|
||||
}
|
||||
std::map<size_t, unsigned int> &mlocker::map()
|
||||
{
|
||||
static std::map<size_t, unsigned int> *vmap = new std::map<size_t, unsigned int>();
|
||||
return *vmap;
|
||||
}
|
||||
|
||||
size_t mlocker::get_page_size()
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(mutex());
|
||||
if (page_size == 0)
|
||||
page_size = query_page_size();
|
||||
return page_size;
|
||||
}
|
||||
|
||||
mlocker::mlocker(void *ptr, size_t len): ptr(ptr), len(len)
|
||||
{
|
||||
lock(ptr, len);
|
||||
}
|
||||
|
||||
mlocker::~mlocker()
|
||||
{
|
||||
unlock(ptr, len);
|
||||
}
|
||||
|
||||
void mlocker::lock(void *ptr, size_t len)
|
||||
{
|
||||
size_t page_size = get_page_size();
|
||||
if (page_size == 0)
|
||||
return;
|
||||
|
||||
CRITICAL_REGION_LOCAL(mutex());
|
||||
const size_t first = ((uintptr_t)ptr) / page_size;
|
||||
const size_t last = (((uintptr_t)ptr) + len - 1) / page_size;
|
||||
for (size_t page = first; page <= last; ++page)
|
||||
lock_page(page);
|
||||
++num_locked_objects;
|
||||
}
|
||||
|
||||
void mlocker::unlock(void *ptr, size_t len)
|
||||
{
|
||||
size_t page_size = get_page_size();
|
||||
if (page_size == 0)
|
||||
return;
|
||||
CRITICAL_REGION_LOCAL(mutex());
|
||||
const size_t first = ((uintptr_t)ptr) / page_size;
|
||||
const size_t last = (((uintptr_t)ptr) + len - 1) / page_size;
|
||||
for (size_t page = first; page <= last; ++page)
|
||||
unlock_page(page);
|
||||
--num_locked_objects;
|
||||
}
|
||||
|
||||
size_t mlocker::get_num_locked_pages()
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(mutex());
|
||||
return map().size();
|
||||
}
|
||||
|
||||
size_t mlocker::get_num_locked_objects()
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(mutex());
|
||||
return num_locked_objects;
|
||||
}
|
||||
|
||||
void mlocker::lock_page(size_t page)
|
||||
{
|
||||
std::pair<std::map<size_t, unsigned int>::iterator, bool> p = map().insert(std::make_pair(page, 1));
|
||||
if (p.second)
|
||||
{
|
||||
do_lock((void*)(page * page_size), page_size);
|
||||
}
|
||||
else
|
||||
{
|
||||
++p.first->second;
|
||||
}
|
||||
}
|
||||
|
||||
void mlocker::unlock_page(size_t page)
|
||||
{
|
||||
std::map<size_t, unsigned int>::iterator i = map().find(page);
|
||||
if (i == map().end())
|
||||
{
|
||||
MERROR("Attempt to unlock unlocked page at " << (void*)(page * page_size));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!--i->second)
|
||||
{
|
||||
map().erase(i);
|
||||
do_unlock((void*)(page * page_size), page_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -28,6 +28,13 @@
|
||||
#ifndef _MLOG_H_
|
||||
#define _MLOG_H_
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING
|
||||
#define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <time.h>
|
||||
#include <atomic>
|
||||
#include <boost/filesystem.hpp>
|
||||
@@ -117,7 +124,32 @@ static const char *get_default_categories(int level)
|
||||
return categories;
|
||||
}
|
||||
|
||||
void mlog_configure(const std::string &filename_base, bool console, const std::size_t max_log_file_size)
|
||||
#ifdef WIN32
|
||||
bool EnableVTMode()
|
||||
{
|
||||
// Set output mode to handle virtual terminal sequences
|
||||
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
if (hOut == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
DWORD dwMode = 0;
|
||||
if (!GetConsoleMode(hOut, &dwMode))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
|
||||
if (!SetConsoleMode(hOut, dwMode))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
void mlog_configure(const std::string &filename_base, bool console, const std::size_t max_log_file_size, const std::size_t max_log_files)
|
||||
{
|
||||
el::Configurations c;
|
||||
c.setGlobally(el::ConfigurationType::Filename, filename_base);
|
||||
@@ -135,9 +167,65 @@ void mlog_configure(const std::string &filename_base, bool console, const std::s
|
||||
el::Loggers::addFlag(el::LoggingFlag::DisableApplicationAbortOnFatalLog);
|
||||
el::Loggers::addFlag(el::LoggingFlag::ColoredTerminalOutput);
|
||||
el::Loggers::addFlag(el::LoggingFlag::StrictLogFileSizeCheck);
|
||||
el::Helpers::installPreRollOutCallback([filename_base](const char *name, size_t){
|
||||
el::Helpers::installPreRollOutCallback([filename_base, max_log_files](const char *name, size_t){
|
||||
std::string rname = generate_log_filename(filename_base.c_str());
|
||||
rename(name, rname.c_str());
|
||||
int ret = rename(name, rname.c_str());
|
||||
if (ret < 0)
|
||||
{
|
||||
// can't log a failure, but don't do the file removal below
|
||||
return;
|
||||
}
|
||||
if (max_log_files != 0)
|
||||
{
|
||||
std::vector<boost::filesystem::path> found_files;
|
||||
const boost::filesystem::directory_iterator end_itr;
|
||||
const boost::filesystem::path filename_base_path(filename_base);
|
||||
const boost::filesystem::path parent_path = filename_base_path.has_parent_path() ? filename_base_path.parent_path() : ".";
|
||||
for (boost::filesystem::directory_iterator iter(parent_path); iter != end_itr; ++iter)
|
||||
{
|
||||
const std::string filename = iter->path().string();
|
||||
if (filename.size() >= filename_base.size() && std::memcmp(filename.data(), filename_base.data(), filename_base.size()) == 0)
|
||||
{
|
||||
found_files.push_back(iter->path());
|
||||
}
|
||||
}
|
||||
if (found_files.size() >= max_log_files)
|
||||
{
|
||||
std::sort(found_files.begin(), found_files.end(), [](const boost::filesystem::path &a, const boost::filesystem::path &b) {
|
||||
boost::system::error_code ec;
|
||||
std::time_t ta = boost::filesystem::last_write_time(boost::filesystem::path(a), ec);
|
||||
if (ec)
|
||||
{
|
||||
MERROR("Failed to get timestamp from " << a << ": " << ec);
|
||||
ta = std::time(nullptr);
|
||||
}
|
||||
std::time_t tb = boost::filesystem::last_write_time(boost::filesystem::path(b), ec);
|
||||
if (ec)
|
||||
{
|
||||
MERROR("Failed to get timestamp from " << b << ": " << ec);
|
||||
tb = std::time(nullptr);
|
||||
}
|
||||
static_assert(std::is_integral<time_t>(), "bad time_t");
|
||||
return ta < tb;
|
||||
});
|
||||
for (size_t i = 0; i <= found_files.size() - max_log_files; ++i)
|
||||
{
|
||||
try
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
boost::filesystem::remove(found_files[i], ec);
|
||||
if (ec)
|
||||
{
|
||||
MERROR("Failed to remove " << found_files[i] << ": " << ec);
|
||||
}
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
MERROR("Failed to remove " << found_files[i] << ": " << e.what());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
mlog_set_common_prefix();
|
||||
const char *monero_log = getenv("MONERO_LOGS");
|
||||
@@ -146,6 +234,9 @@ void mlog_configure(const std::string &filename_base, bool console, const std::s
|
||||
monero_log = get_default_categories(0);
|
||||
}
|
||||
mlog_set_log(monero_log);
|
||||
#ifdef WIN32
|
||||
EnableVTMode();
|
||||
#endif
|
||||
}
|
||||
|
||||
void mlog_set_categories(const char *categories)
|
||||
|
||||
@@ -26,11 +26,24 @@
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include <boost/optional/optional.hpp>
|
||||
#include <string.h>
|
||||
#include "memwipe.h"
|
||||
#include "misc_log_ex.h"
|
||||
#include "wipeable_string.h"
|
||||
|
||||
static constexpr const char hex[] = u8"0123456789abcdef";
|
||||
|
||||
namespace
|
||||
{
|
||||
int atolower(int c)
|
||||
{
|
||||
if (c >= 'A' && c <= 'Z')
|
||||
c |= 32;
|
||||
return c;
|
||||
}
|
||||
}
|
||||
|
||||
namespace epee
|
||||
{
|
||||
|
||||
@@ -69,6 +82,12 @@ wipeable_string::wipeable_string(const char *s)
|
||||
memcpy(buffer.data(), s, size());
|
||||
}
|
||||
|
||||
wipeable_string::wipeable_string(const char *s, size_t len)
|
||||
{
|
||||
grow(len);
|
||||
memcpy(buffer.data(), s, len);
|
||||
}
|
||||
|
||||
wipeable_string::~wipeable_string()
|
||||
{
|
||||
wipe();
|
||||
@@ -109,9 +128,99 @@ void wipeable_string::push_back(char c)
|
||||
buffer.back() = c;
|
||||
}
|
||||
|
||||
void wipeable_string::pop_back()
|
||||
void wipeable_string::operator+=(char c)
|
||||
{
|
||||
resize(size() - 1);
|
||||
push_back(c);
|
||||
}
|
||||
|
||||
void wipeable_string::append(const char *ptr, size_t len)
|
||||
{
|
||||
const size_t orgsz = size();
|
||||
CHECK_AND_ASSERT_THROW_MES(orgsz < std::numeric_limits<size_t>::max() - len, "Appended data too large");
|
||||
grow(orgsz + len);
|
||||
if (len > 0)
|
||||
memcpy(data() + orgsz, ptr, len);
|
||||
}
|
||||
|
||||
void wipeable_string::operator+=(const char *s)
|
||||
{
|
||||
append(s, strlen(s));
|
||||
}
|
||||
|
||||
void wipeable_string::operator+=(const epee::wipeable_string &s)
|
||||
{
|
||||
append(s.data(), s.size());
|
||||
}
|
||||
|
||||
void wipeable_string::operator+=(const std::string &s)
|
||||
{
|
||||
append(s.c_str(), s.size());
|
||||
}
|
||||
|
||||
void wipeable_string::trim()
|
||||
{
|
||||
size_t prefix = 0;
|
||||
while (prefix < size() && data()[prefix] == ' ')
|
||||
++prefix;
|
||||
if (prefix > 0)
|
||||
memmove(buffer.data(), buffer.data() + prefix, size() - prefix);
|
||||
|
||||
size_t suffix = 0;
|
||||
while (suffix < size()-prefix && data()[size() - 1 - prefix - suffix] == ' ')
|
||||
++suffix;
|
||||
|
||||
resize(size() - prefix - suffix);
|
||||
}
|
||||
|
||||
void wipeable_string::split(std::vector<wipeable_string> &fields) const
|
||||
{
|
||||
fields.clear();
|
||||
size_t len = size();
|
||||
const char *ptr = data();
|
||||
bool space = true;
|
||||
while (len--)
|
||||
{
|
||||
const char c = *ptr++;
|
||||
if (c != ' ')
|
||||
{
|
||||
if (space)
|
||||
fields.push_back({});
|
||||
fields.back().push_back(c);
|
||||
}
|
||||
space = c == ' ';
|
||||
}
|
||||
}
|
||||
|
||||
boost::optional<epee::wipeable_string> wipeable_string::parse_hexstr() const
|
||||
{
|
||||
if (size() % 2 != 0)
|
||||
return boost::none;
|
||||
boost::optional<epee::wipeable_string> res = epee::wipeable_string("");
|
||||
const size_t len = size();
|
||||
const char *d = data();
|
||||
res->grow(0, len / 2);
|
||||
for (size_t i = 0; i < len; i += 2)
|
||||
{
|
||||
char c = atolower(d[i]);
|
||||
const char *ptr0 = strchr(hex, c);
|
||||
if (!ptr0)
|
||||
return boost::none;
|
||||
c = atolower(d[i+1]);
|
||||
const char *ptr1 = strchr(hex, c);
|
||||
if (!ptr1)
|
||||
return boost::none;
|
||||
res->push_back(((ptr0-hex)<<4) | (ptr1-hex));
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
char wipeable_string::pop_back()
|
||||
{
|
||||
const size_t sz = size();
|
||||
CHECK_AND_ASSERT_THROW_MES(sz > 0, "Popping from an empty string");
|
||||
const char c = buffer.back();
|
||||
resize(sz - 1);
|
||||
return c;
|
||||
}
|
||||
|
||||
void wipeable_string::resize(size_t sz)
|
||||
|
||||
@@ -10,12 +10,12 @@ fi
|
||||
type="$1"
|
||||
if test -z "$type"
|
||||
then
|
||||
echo "usage: $0 block|transaction|signature|cold-outputs|cold-transaction|load-from-binary|load-from-json|base58|parse-url|http-client|levin"
|
||||
echo "usage: $0 block|transaction|signature|cold-outputs|cold-transaction|load-from-binary|load-from-json|base58|parse-url|http-client|levin|bulletproof"
|
||||
exit 1
|
||||
fi
|
||||
case "$type" in
|
||||
block|transaction|signature|cold-outputs|cold-transaction|load-from-binary|load-from-json|base58|parse-url|http-client|levin) ;;
|
||||
*) echo "usage: $0 block|transaction|signature|cold-outputs|cold-transaction|load-from-binary|load-from-json|base58|parse-url|http-client|levin"; exit 1 ;;
|
||||
block|transaction|signature|cold-outputs|cold-transaction|load-from-binary|load-from-json|base58|parse-url|http-client|levin|bulletproof) ;;
|
||||
*) echo "usage: $0 block|transaction|signature|cold-outputs|cold-transaction|load-from-binary|load-from-json|base58|parse-url|http-client|levin|bulletproof"; exit 1 ;;
|
||||
esac
|
||||
|
||||
if test -d "fuzz-out/$type"
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
if [ ! -d "$SNAP_USER_DATA/etc" ]; then
|
||||
mkdir $SNAP_USER_DATA/etc/
|
||||
cp -R $SNAP/etc/monerod.conf $SNAP_USER_DATA/etc/monerod.conf
|
||||
fi
|
||||
|
||||
exec "$SNAP/bin/monerod" "$@"
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 18 KiB |
@@ -1,31 +1,29 @@
|
||||
name: monero
|
||||
version: 0.11.1.0-1
|
||||
summary: "Monero: the secure, private, untraceable cryptocurrency https://getmonero.org"
|
||||
name: wownero
|
||||
version: 0.5.0.0
|
||||
summary: "Wownero: the secure, private, untraceable cryptocurrency http://wownero.org"
|
||||
description: |
|
||||
Monero is a private, secure, untraceable, decentralised digital currency.
|
||||
You are your bank, you control your funds, and nobody can trace your transfers
|
||||
unless you allow them to do so.
|
||||
Wownero: a fairly launched privacy-centric meme coin with no premine and a finite supply.
|
||||
grade: devel
|
||||
confinement: strict
|
||||
|
||||
apps:
|
||||
monerod:
|
||||
wownerod:
|
||||
daemon: forking
|
||||
command: |
|
||||
monerod-wrapper --detach --data-dir ${SNAP_COMMON} --config-file ${SNAP_USER_DATA}/etc/monerod.conf
|
||||
wownerod-wrapper --detach --data-dir ${SNAP_COMMON} --config-file ${SNAP_USER_DATA}/etc/wownerod.conf
|
||||
plugs:
|
||||
- network
|
||||
- network-bind
|
||||
monero-wallet-rpc:
|
||||
wownero-wallet-rpc:
|
||||
command: |
|
||||
monero-wallet-rpc --log-file ${SNAP_USER_DATA}
|
||||
wownero-wallet-rpc --log-file ${SNAP_USER_DATA}
|
||||
plugs:
|
||||
- home
|
||||
- network
|
||||
- network-bind
|
||||
monero-wallet-cli:
|
||||
wownero-wallet-cli:
|
||||
command: |
|
||||
monero-wallet-cli --log-file ${SNAP_USER_DATA}
|
||||
wownero-wallet-cli --log-file ${SNAP_USER_DATA}
|
||||
plugs:
|
||||
- home
|
||||
- network
|
||||
@@ -71,8 +69,8 @@ parts:
|
||||
plugin: dump
|
||||
source: .
|
||||
organize:
|
||||
contrib/snap/monerod.conf: etc/monerod.conf
|
||||
contrib/snap/monerod-wrapper: bin/monerod-wrapper
|
||||
contrib/snap/wownerod.conf: etc/wownerod.conf
|
||||
contrib/snap/wownerod-wrapper: bin/wownerod-wrapper
|
||||
prime:
|
||||
- etc
|
||||
- bin
|
||||
|
||||
8
contrib/snap/wownerod-wrapper
Executable file
8
contrib/snap/wownerod-wrapper
Executable file
@@ -0,0 +1,8 @@
|
||||
#!/bin/sh
|
||||
|
||||
if [ ! -d "$SNAP_USER_DATA/etc" ]; then
|
||||
mkdir $SNAP_USER_DATA/etc/
|
||||
cp -R $SNAP/etc/wownerod.conf $SNAP_USER_DATA/etc/wownerod.conf
|
||||
fi
|
||||
|
||||
exec "$SNAP/bin/wownerod" "$@"
|
||||
@@ -1,9 +1,10 @@
|
||||
# Configuration for monerod
|
||||
# Syntax: any command line option may be specified as 'clioptionname=value'.
|
||||
# Boolean options such as 'no-igd' are specified as 'no-igd=1'.
|
||||
# See 'monerod --help' for all available options.
|
||||
|
||||
# Overrided by snap:
|
||||
# data-dir=/var/lib/monero
|
||||
# log-file=/var/log/monero/monero.log
|
||||
# Overridden by snap:
|
||||
# data-dir=/var/lib/wownero
|
||||
# log-file=/var/log/wownero/wownero.log
|
||||
|
||||
log-level=0
|
||||
48
external/CMakeLists.txt
vendored
48
external/CMakeLists.txt
vendored
@@ -34,22 +34,42 @@
|
||||
# We always compile if we are building statically to reduce static dependency issues...
|
||||
# ...except for FreeBSD, because FreeBSD is a special case that doesn't play well with
|
||||
# others.
|
||||
|
||||
find_package(Miniupnpc REQUIRED)
|
||||
|
||||
message(STATUS "Using in-tree miniupnpc")
|
||||
add_subdirectory(miniupnp/miniupnpc)
|
||||
set_property(TARGET libminiupnpc-static PROPERTY FOLDER "external")
|
||||
if(MSVC)
|
||||
set_property(TARGET libminiupnpc-static APPEND_STRING PROPERTY COMPILE_FLAGS " -wd4244 -wd4267")
|
||||
elseif(NOT MSVC)
|
||||
set_property(TARGET libminiupnpc-static APPEND_STRING PROPERTY COMPILE_FLAGS " -Wno-undef -Wno-unused-result -Wno-unused-value")
|
||||
endif()
|
||||
if(CMAKE_SYSTEM_NAME MATCHES "NetBSD")
|
||||
set_property(TARGET libminiupnpc-static APPEND_STRING PROPERTY COMPILE_FLAGS " -D_NETBSD_SOURCE")
|
||||
if(NOT IOS)
|
||||
find_package(Miniupnpc QUIET)
|
||||
endif()
|
||||
|
||||
set(UPNP_LIBRARIES "libminiupnpc-static" PARENT_SCOPE)
|
||||
# If we have the correct shared version and we're not building static, use it
|
||||
if(STATIC OR IOS)
|
||||
set(USE_SHARED_MINIUPNPC false)
|
||||
elseif(MINIUPNP_FOUND AND MINIUPNPC_VERSION_1_7_OR_HIGHER)
|
||||
set(USE_SHARED_MINIUPNPC true)
|
||||
endif()
|
||||
|
||||
if(USE_SHARED_MINIUPNPC)
|
||||
message(STATUS "Using shared miniupnpc found at ${MINIUPNP_INCLUDE_DIR}")
|
||||
|
||||
set(UPNP_STATIC false PARENT_SCOPE)
|
||||
set(UPNP_INCLUDE ${MINIUPNP_INCLUDE_DIR} PARENT_SCOPE)
|
||||
set(UPNP_LIBRARIES ${MINIUPNP_LIBRARY} PARENT_SCOPE)
|
||||
else()
|
||||
if(STATIC)
|
||||
message(STATUS "Using miniupnpc from local source tree for static build")
|
||||
else()
|
||||
message(STATUS "Using miniupnpc from local source tree (/external/miniupnp/miniupnpc)")
|
||||
endif()
|
||||
|
||||
add_subdirectory(miniupnp/miniupnpc)
|
||||
|
||||
set_property(TARGET libminiupnpc-static PROPERTY FOLDER "external")
|
||||
if(MSVC)
|
||||
set_property(TARGET libminiupnpc-static APPEND_STRING PROPERTY COMPILE_FLAGS " -wd4244 -wd4267")
|
||||
elseif(NOT MSVC)
|
||||
set_property(TARGET libminiupnpc-static APPEND_STRING PROPERTY COMPILE_FLAGS " -Wno-undef -Wno-unused-result -Wno-unused-value")
|
||||
endif()
|
||||
|
||||
set(UPNP_STATIC true PARENT_SCOPE)
|
||||
set(UPNP_LIBRARIES "libminiupnpc-static" PARENT_SCOPE)
|
||||
endif()
|
||||
|
||||
find_package(Unbound)
|
||||
|
||||
|
||||
27
external/easylogging++/easylogging++.cc
vendored
27
external/easylogging++/easylogging++.cc
vendored
@@ -1967,17 +1967,19 @@ void VRegistry::setCategories(const char* categories, bool clear) {
|
||||
base::threading::ScopedLock scopedLock(lock());
|
||||
auto insert = [&](std::stringstream& ss, Level level) {
|
||||
m_categories.push_back(std::make_pair(ss.str(), level));
|
||||
m_cached_allowed_categories.clear();
|
||||
};
|
||||
|
||||
if (clear) {
|
||||
m_categories.clear();
|
||||
m_cached_allowed_categories.clear();
|
||||
m_categoriesString.clear();
|
||||
}
|
||||
if (!categories)
|
||||
return;
|
||||
if (!m_categoriesString.empty())
|
||||
m_categoriesString += ",";
|
||||
m_categoriesString += categories;
|
||||
if (!categories)
|
||||
return;
|
||||
|
||||
bool isCat = true;
|
||||
bool isLevel = false;
|
||||
@@ -2033,15 +2035,22 @@ static int priority(Level level) {
|
||||
|
||||
bool VRegistry::allowed(Level level, const char* category) {
|
||||
base::threading::ScopedLock scopedLock(lock());
|
||||
const std::string scategory = category;
|
||||
const std::map<std::string, int>::const_iterator it = m_cached_allowed_categories.find(scategory);
|
||||
if (it != m_cached_allowed_categories.end())
|
||||
return priority(level) <= it->second;
|
||||
if (m_categories.empty() || category == nullptr) {
|
||||
return false;
|
||||
} else {
|
||||
std::deque<std::pair<std::string, Level>>::const_reverse_iterator it = m_categories.rbegin();
|
||||
for (; it != m_categories.rend(); ++it) {
|
||||
if (base::utils::Str::wildCardMatch(category, it->first.c_str())) {
|
||||
return priority(level) <= priority(it->second);
|
||||
const int p = priority(it->second);
|
||||
m_cached_allowed_categories.insert(std::make_pair(std::move(scategory), p));
|
||||
return priority(level) <= p;
|
||||
}
|
||||
}
|
||||
m_cached_allowed_categories.insert(std::make_pair(std::move(scategory), -1));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -2083,6 +2092,17 @@ void VRegistry::setFromArgs(const base::utils::CommandLineArgs* commandLineArgs)
|
||||
# define ELPP_DEFAULT_LOGGING_FLAGS 0x0
|
||||
#endif // !defined(ELPP_DEFAULT_LOGGING_FLAGS)
|
||||
// Storage
|
||||
el::base::type::StoragePointer getresetELPP(bool reset)
|
||||
{
|
||||
static el::base::type::StoragePointer p(new el::base::Storage(el::LogBuilderPtr(new el::base::DefaultLogBuilder())));
|
||||
if (reset)
|
||||
p = NULL;
|
||||
return p;
|
||||
}
|
||||
el::base::type::StoragePointer el::base::Storage::getELPP()
|
||||
{
|
||||
return getresetELPP(false);
|
||||
}
|
||||
#if ELPP_ASYNC_LOGGING
|
||||
Storage::Storage(const LogBuilderPtr& defaultLogBuilder, base::IWorker* asyncDispatchWorker) :
|
||||
#else
|
||||
@@ -2131,6 +2151,7 @@ Storage::Storage(const LogBuilderPtr& defaultLogBuilder) :
|
||||
|
||||
Storage::~Storage(void) {
|
||||
ELPP_INTERNAL_INFO(4, "Destroying storage");
|
||||
getresetELPP(true);
|
||||
#if ELPP_ASYNC_LOGGING
|
||||
ELPP_INTERNAL_INFO(5, "Replacing log dispatch callback to synchronous");
|
||||
uninstallLogDispatchCallback<base::AsyncLogDispatchCallback>(std::string("AsyncLogDispatchCallback"));
|
||||
|
||||
11
external/easylogging++/easylogging++.h
vendored
11
external/easylogging++/easylogging++.h
vendored
@@ -2490,6 +2490,7 @@ class VRegistry : base::NoCopy, public base::threading::ThreadSafe {
|
||||
inline void clearCategories(void) {
|
||||
base::threading::ScopedLock scopedLock(lock());
|
||||
m_categories.clear();
|
||||
m_cached_allowed_categories.clear();
|
||||
}
|
||||
|
||||
inline void clearModules(void) {
|
||||
@@ -2531,6 +2532,7 @@ class VRegistry : base::NoCopy, public base::threading::ThreadSafe {
|
||||
base::type::EnumType* m_pFlags;
|
||||
std::map<std::string, base::type::VerboseLevel> m_modules;
|
||||
std::deque<std::pair<std::string, Level>> m_categories;
|
||||
std::map<std::string, int> m_cached_allowed_categories;
|
||||
std::string m_categoriesString;
|
||||
std::string m_filenameCommonPrefix;
|
||||
};
|
||||
@@ -2769,6 +2771,8 @@ class Storage : base::NoCopy, public base::threading::ThreadSafe {
|
||||
return it->second;
|
||||
}
|
||||
|
||||
static el::base::type::StoragePointer getELPP();
|
||||
|
||||
private:
|
||||
base::RegisteredHitCounters* m_registeredHitCounters;
|
||||
base::RegisteredLoggers* m_registeredLoggers;
|
||||
@@ -2801,7 +2805,7 @@ class Storage : base::NoCopy, public base::threading::ThreadSafe {
|
||||
}
|
||||
};
|
||||
extern ELPP_EXPORT base::type::StoragePointer elStorage;
|
||||
#define ELPP el::base::elStorage
|
||||
#define ELPP el::base::Storage::getELPP()
|
||||
class DefaultLogDispatchCallback : public LogDispatchCallback {
|
||||
protected:
|
||||
void handle(const LogDispatchData* data);
|
||||
@@ -4631,10 +4635,9 @@ el::base::debug::CrashHandler elCrashHandler(ELPP_USE_DEF_CRASH_HANDLER); \
|
||||
}
|
||||
|
||||
#if ELPP_ASYNC_LOGGING
|
||||
# define INITIALIZE_EASYLOGGINGPP ELPP_INIT_EASYLOGGINGPP(new el::base::Storage(el::LogBuilderPtr(new el::base::DefaultLogBuilder()),\
|
||||
new el::base::AsyncDispatchWorker()))
|
||||
# define INITIALIZE_EASYLOGGINGPP ELPP_INIT_EASYLOGGINGPP(NULL)
|
||||
#else
|
||||
# define INITIALIZE_EASYLOGGINGPP ELPP_INIT_EASYLOGGINGPP(new el::base::Storage(el::LogBuilderPtr(new el::base::DefaultLogBuilder())))
|
||||
# define INITIALIZE_EASYLOGGINGPP ELPP_INIT_EASYLOGGINGPP(NULL)
|
||||
#endif // ELPP_ASYNC_LOGGING
|
||||
#define INITIALIZE_NULL_EASYLOGGINGPP \
|
||||
namespace el {\
|
||||
|
||||
2
external/miniupnp
vendored
2
external/miniupnp
vendored
Submodule external/miniupnp updated: 6a63f99549...6b9b73a567
@@ -130,14 +130,14 @@ endif()
|
||||
add_subdirectory(cryptonote_protocol)
|
||||
if(NOT IOS)
|
||||
add_subdirectory(simplewallet)
|
||||
add_subdirectory(gen_multisig)
|
||||
add_subdirectory(daemonizer)
|
||||
add_subdirectory(daemon)
|
||||
add_subdirectory(blockchain_utilities)
|
||||
endif()
|
||||
|
||||
if(CMAKE_BUILD_TYPE STREQUAL Debug)
|
||||
add_subdirectory(debug_utilities)
|
||||
add_subdirectory(blockchain_utilities)
|
||||
add_subdirectory(gen_multisig)
|
||||
endif()
|
||||
|
||||
if(PER_BLOCK_CHECKPOINT)
|
||||
|
||||
@@ -224,7 +224,7 @@ struct Dbt_safe : public Dbt
|
||||
namespace cryptonote
|
||||
{
|
||||
|
||||
void BlockchainBDB::add_block(const block& blk, const size_t& block_size, const difficulty_type& cumulative_difficulty, const uint64_t& coins_generated, const crypto::hash& blk_hash)
|
||||
void BlockchainBDB::add_block(const block& blk, size_t block_weight, const difficulty_type& cumulative_difficulty, const uint64_t& coins_generated, const crypto::hash& blk_hash)
|
||||
{
|
||||
LOG_PRINT_L3("BlockchainBDB::" << __func__);
|
||||
check_open();
|
||||
@@ -255,7 +255,7 @@ void BlockchainBDB::add_block(const block& blk, const size_t& block_size, const
|
||||
if (res)
|
||||
throw0(DB_ERROR("Failed to add block blob to db transaction."));
|
||||
|
||||
Dbt_copy<size_t> sz(block_size);
|
||||
Dbt_copy<size_t> sz(block_weight);
|
||||
if (m_block_sizes->put(DB_DEFAULT_TX, &key, &sz, 0))
|
||||
throw0(DB_ERROR("Failed to add block size to db transaction."));
|
||||
|
||||
@@ -313,7 +313,7 @@ void BlockchainBDB::remove_block()
|
||||
throw1(DB_ERROR("Failed to add removal of block hash to db transaction"));
|
||||
}
|
||||
|
||||
void BlockchainBDB::add_transaction_data(const crypto::hash& blk_hash, const transaction& tx, const crypto::hash& tx_hash)
|
||||
void BlockchainBDB::add_transaction_data(const crypto::hash& blk_hash, const transaction& tx, const crypto::hash& tx_hash, const crypto::hash& tx_prunable_hash)
|
||||
{
|
||||
LOG_PRINT_L3("BlockchainBDB::" << __func__);
|
||||
check_open();
|
||||
@@ -655,7 +655,7 @@ bool BlockchainBDB::for_all_blocks(std::function<bool(uint64_t, const crypto::ha
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool BlockchainBDB::for_all_transactions(std::function<bool(const crypto::hash&, const cryptonote::transaction&)> f) const
|
||||
bool BlockchainBDB::for_all_transactions(std::function<bool(const crypto::hash&, const cryptonote::transaction&)> f, bool pruned) const
|
||||
{
|
||||
LOG_PRINT_L3("BlockchainBDB::" << __func__);
|
||||
check_open();
|
||||
@@ -1213,6 +1213,11 @@ std::vector<std::string> BlockchainBDB::get_filenames() const
|
||||
return full_paths;
|
||||
}
|
||||
|
||||
bool BlockchainBDB::remove_data_file(const std::string& folder)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string BlockchainBDB::get_db_name() const
|
||||
{
|
||||
LOG_PRINT_L3("BlockchainBDB::" << __func__);
|
||||
@@ -1348,7 +1353,7 @@ uint64_t BlockchainBDB::get_top_block_timestamp() const
|
||||
return get_block_timestamp(m_height - 1);
|
||||
}
|
||||
|
||||
size_t BlockchainBDB::get_block_size(const uint64_t& height) const
|
||||
size_t BlockchainBDB::get_block_weight(const uint64_t& height) const
|
||||
{
|
||||
LOG_PRINT_L3("BlockchainBDB::" << __func__);
|
||||
check_open();
|
||||
@@ -1856,7 +1861,7 @@ void BlockchainBDB::block_txn_abort()
|
||||
// TODO
|
||||
}
|
||||
|
||||
uint64_t BlockchainBDB::add_block(const block& blk, const size_t& block_size, const difficulty_type& cumulative_difficulty, const uint64_t& coins_generated, const std::vector<transaction>& txs)
|
||||
uint64_t BlockchainBDB::add_block(const block& blk, size_t block_weight, const difficulty_type& cumulative_difficulty, const uint64_t& coins_generated, const std::vector<transaction>& txs)
|
||||
{
|
||||
LOG_PRINT_L3("BlockchainBDB::" << __func__);
|
||||
check_open();
|
||||
@@ -1869,7 +1874,7 @@ uint64_t BlockchainBDB::add_block(const block& blk, const size_t& block_size, co
|
||||
uint64_t num_outputs = m_num_outputs;
|
||||
try
|
||||
{
|
||||
BlockchainDB::add_block(blk, block_size, cumulative_difficulty, coins_generated, txs);
|
||||
BlockchainDB::add_block(blk, block_weight, cumulative_difficulty, coins_generated, txs);
|
||||
m_write_txn = NULL;
|
||||
|
||||
TIME_MEASURE_START(time1);
|
||||
|
||||
@@ -244,6 +244,8 @@ public:
|
||||
|
||||
virtual std::vector<std::string> get_filenames() const;
|
||||
|
||||
virtual bool remove_data_file(const std::string& folder);
|
||||
|
||||
virtual std::string get_db_name() const;
|
||||
|
||||
virtual bool lock();
|
||||
@@ -264,7 +266,7 @@ public:
|
||||
|
||||
virtual uint64_t get_top_block_timestamp() const;
|
||||
|
||||
virtual size_t get_block_size(const uint64_t& height) const;
|
||||
virtual size_t get_block_weight(const uint64_t& height) const;
|
||||
|
||||
virtual difficulty_type get_block_cumulative_difficulty(const uint64_t& height) const;
|
||||
|
||||
@@ -301,7 +303,6 @@ public:
|
||||
virtual uint64_t get_indexing_base() const { return 1; }
|
||||
|
||||
virtual output_data_t get_output_key(const uint64_t& amount, const uint64_t& index);
|
||||
virtual output_data_t get_output_key(const uint64_t& global_index) const;
|
||||
virtual void get_output_key(const uint64_t &amount, const std::vector<uint64_t> &offsets, std::vector<output_data_t> &outputs);
|
||||
|
||||
virtual tx_out_index get_output_tx_and_index_from_global(const uint64_t& index) const;
|
||||
@@ -317,7 +318,7 @@ public:
|
||||
virtual bool has_key_image(const crypto::key_image& img) const;
|
||||
|
||||
virtual uint64_t add_block( const block& blk
|
||||
, const size_t& block_size
|
||||
, size_t block_weight
|
||||
, const difficulty_type& cumulative_difficulty
|
||||
, const uint64_t& coins_generated
|
||||
, const std::vector<transaction>& txs
|
||||
@@ -352,7 +353,7 @@ public:
|
||||
|
||||
private:
|
||||
virtual void add_block( const block& blk
|
||||
, const size_t& block_size
|
||||
, size_t block_weight
|
||||
, const difficulty_type& cumulative_difficulty
|
||||
, const uint64_t& coins_generated
|
||||
, const crypto::hash& block_hash
|
||||
@@ -360,7 +361,7 @@ private:
|
||||
|
||||
virtual void remove_block();
|
||||
|
||||
virtual void add_transaction_data(const crypto::hash& blk_hash, const transaction& tx, const crypto::hash& tx_hash);
|
||||
virtual void add_transaction_data(const crypto::hash& blk_hash, const transaction& tx, const crypto::hash& tx_hash, const crypto::hash& tx_prunable_hash);
|
||||
|
||||
virtual void remove_transaction_data(const crypto::hash& tx_hash, const transaction& tx);
|
||||
|
||||
@@ -381,7 +382,7 @@ private:
|
||||
|
||||
virtual bool for_all_key_images(std::function<bool(const crypto::key_image&)>) const;
|
||||
virtual bool for_all_blocks(std::function<bool(uint64_t, const crypto::hash&, const cryptonote::block&)>) const;
|
||||
virtual bool for_all_transactions(std::function<bool(const crypto::hash&, const cryptonote::transaction&)>) const;
|
||||
virtual bool for_all_transactions(std::function<bool(const crypto::hash&, const cryptonote::transaction&)>, bool pruned) const;
|
||||
virtual bool for_all_outputs(std::function<bool(uint64_t amount, const crypto::hash &tx_hash, size_t tx_idx)> f) const;
|
||||
|
||||
// Hard fork related storage
|
||||
@@ -417,6 +418,7 @@ private:
|
||||
* @return the global index of the desired output
|
||||
*/
|
||||
uint64_t get_output_global_index(const uint64_t& amount, const uint64_t& index);
|
||||
output_data_t get_output_key(const uint64_t& global_index) const;
|
||||
void checkpoint_worker() const;
|
||||
void check_open() const;
|
||||
|
||||
|
||||
@@ -87,8 +87,8 @@ const command_line::arg_descriptor<std::string> arg_db_type = {
|
||||
};
|
||||
const command_line::arg_descriptor<std::string> arg_db_sync_mode = {
|
||||
"db-sync-mode"
|
||||
, "Specify sync option, using format [safe|fast|fastest]:[sync|async]:[nblocks_per_sync]."
|
||||
, "fast:async:1000"
|
||||
, "Specify sync option, using format [safe|fast|fastest]:[sync|async]:[<nblocks_per_sync>[blocks]|<nbytes_per_sync>[bytes]]."
|
||||
, "fast:async:250000000bytes"
|
||||
};
|
||||
const command_line::arg_descriptor<bool> arg_db_salvage = {
|
||||
"db-salvage"
|
||||
@@ -121,10 +121,10 @@ void BlockchainDB::pop_block()
|
||||
pop_block(blk, txs);
|
||||
}
|
||||
|
||||
void BlockchainDB::add_transaction(const crypto::hash& blk_hash, const transaction& tx, const crypto::hash* tx_hash_ptr)
|
||||
void BlockchainDB::add_transaction(const crypto::hash& blk_hash, const transaction& tx, const crypto::hash* tx_hash_ptr, const crypto::hash* tx_prunable_hash_ptr)
|
||||
{
|
||||
bool miner_tx = false;
|
||||
crypto::hash tx_hash;
|
||||
crypto::hash tx_hash, tx_prunable_hash;
|
||||
if (!tx_hash_ptr)
|
||||
{
|
||||
// should only need to compute hash for miner transactions
|
||||
@@ -135,6 +135,13 @@ void BlockchainDB::add_transaction(const crypto::hash& blk_hash, const transacti
|
||||
{
|
||||
tx_hash = *tx_hash_ptr;
|
||||
}
|
||||
if (tx.version >= 2)
|
||||
{
|
||||
if (!tx_prunable_hash_ptr)
|
||||
tx_prunable_hash = get_transaction_prunable_hash(tx);
|
||||
else
|
||||
tx_prunable_hash = *tx_prunable_hash_ptr;
|
||||
}
|
||||
|
||||
for (const txin_v& tx_input : tx.vin)
|
||||
{
|
||||
@@ -161,7 +168,7 @@ void BlockchainDB::add_transaction(const crypto::hash& blk_hash, const transacti
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t tx_id = add_transaction_data(blk_hash, tx, tx_hash);
|
||||
uint64_t tx_id = add_transaction_data(blk_hash, tx, tx_hash, tx_prunable_hash);
|
||||
|
||||
std::vector<uint64_t> amount_output_indices;
|
||||
|
||||
@@ -189,7 +196,8 @@ void BlockchainDB::add_transaction(const crypto::hash& blk_hash, const transacti
|
||||
}
|
||||
|
||||
uint64_t BlockchainDB::add_block( const block& blk
|
||||
, const size_t& block_size
|
||||
, size_t block_weight
|
||||
, uint64_t long_term_block_weight
|
||||
, const difficulty_type& cumulative_difficulty
|
||||
, const uint64_t& coins_generated
|
||||
, const std::vector<transaction>& txs
|
||||
@@ -211,13 +219,22 @@ uint64_t BlockchainDB::add_block( const block& blk
|
||||
// call out to add the transactions
|
||||
|
||||
time1 = epee::misc_utils::get_tick_count();
|
||||
|
||||
uint64_t num_rct_outs = 0;
|
||||
add_transaction(blk_hash, blk.miner_tx);
|
||||
if (blk.miner_tx.version == 2)
|
||||
num_rct_outs += blk.miner_tx.vout.size();
|
||||
int tx_i = 0;
|
||||
crypto::hash tx_hash = crypto::null_hash;
|
||||
for (const transaction& tx : txs)
|
||||
{
|
||||
tx_hash = blk.tx_hashes[tx_i];
|
||||
add_transaction(blk_hash, tx, &tx_hash);
|
||||
for (const auto &vout: tx.vout)
|
||||
{
|
||||
if (vout.amount == 0)
|
||||
++num_rct_outs;
|
||||
}
|
||||
++tx_i;
|
||||
}
|
||||
TIME_MEASURE_FINISH(time1);
|
||||
@@ -225,7 +242,7 @@ uint64_t BlockchainDB::add_block( const block& blk
|
||||
|
||||
// call out to subclass implementation to add the block & metadata
|
||||
time1 = epee::misc_utils::get_tick_count();
|
||||
add_block(blk, block_size, cumulative_difficulty, coins_generated, blk_hash);
|
||||
add_block(blk, block_weight, long_term_block_weight, cumulative_difficulty, coins_generated, num_rct_outs, blk_hash);
|
||||
TIME_MEASURE_FINISH(time1);
|
||||
time_add_block1 += time1;
|
||||
|
||||
@@ -355,582 +372,7 @@ void BlockchainDB::fixup()
|
||||
LOG_PRINT_L1("Database is opened read only - skipping fixup check");
|
||||
return;
|
||||
}
|
||||
|
||||
// There was a bug that would cause key images for transactions without
|
||||
// any outputs to not be added to the spent key image set. There are two
|
||||
// instances of such transactions, in blocks 202612 and 685498.
|
||||
// The key images below are those from the inputs in those transactions.
|
||||
// On testnet, there are no such transactions
|
||||
// See commit 533acc30eda7792c802ea8b6417917fa99b8bc2b for the fix
|
||||
static const char * const mainnet_genesis_hex = "418015bb9ae982a1975da7d79277c2705727a56894ba0fb246adaabb1f4632e3";
|
||||
crypto::hash mainnet_genesis_hash;
|
||||
epee::string_tools::hex_to_pod(mainnet_genesis_hex, mainnet_genesis_hash );
|
||||
set_batch_transactions(true);
|
||||
batch_start();
|
||||
|
||||
if (get_block_hash_from_height(0) == mainnet_genesis_hash)
|
||||
{
|
||||
// block 202612 (511 key images in 511 transactions)
|
||||
static const char * const key_images_202612[] =
|
||||
{
|
||||
"51fc647fb27439fbb3672197d2068e4110391edf80d822f58607bd5757cba7f3",
|
||||
"d8cf1c1bd41f13c4553186e130e6e2c1cd80135ddb418f350088926997a95ca9",
|
||||
"95d2556c8acd1457dce7bfd9c83b1d82b821a55a9c9588b04b7b5cf562a65949",
|
||||
"4b5d987fee1bb563a162d23e41741ad73560c003e26a09b6655f09496538daac",
|
||||
"1d25ea86323d1578579d3894a54b99ea1c3e2dca547c6726c44aef67db958b02",
|
||||
"92e46fb70be5d9df39ca83c4fc6ae26c594118314bb75502a9c9752a781d0b33",
|
||||
"924d0cb9060d429be7e59d164a0f80a4dabc3607d44401b26fb93e7182ab435d",
|
||||
"f63e4a23fec860fd4c3734623891330ac1ff5af251e83a0e6247287818b8a72f",
|
||||
"5b14c5ef13738d015619b61dacefc2ade3660d25b35ef96330a8f4e2afc26526",
|
||||
"d5016b012a2fb6ca23fd56ece544d847962264b4aee15efe1465805fd824a8fb",
|
||||
"0a7f3da1d9dd341cd96829e484b07163099763ac7bd60603b7ee14f7dbcb278d",
|
||||
"d716c03d7447d2b693f6f61b6ad36bd57344033fc1a11feaf60d569f40014530",
|
||||
"23154a812e99ce226f6a87087e0812f419aed51289f1c0c359b0b61303b53a36",
|
||||
"03940341e1a99d5b0c68eacfdf5a20df90d7d0a3d6089d39709cdd964490755c",
|
||||
"ef09648814cfe071f5d8e9cfde57247ad09409265c4b6c84697bbb046809bd7e",
|
||||
"8843ec52b0496ca4e895813cfe00bb18ea777d3618e9bd2e200287e888e2f5c7",
|
||||
"8558bf39baf3df62b5d33cdf97163a365e6c44f4d6deef920730b4982b66449f",
|
||||
"504d9380ce581de0af97d5800d5ca9e61d78df368907151ab1e567eb6445332a",
|
||||
"673797763593c23b3ee07b43bd8760365e2c251a8a60a275528ff34a477110cc",
|
||||
"25178c95e4d402c58d79c160d2c52dd3c45db2c78e6aaa8d24d35c64f19d4957",
|
||||
"407c3a05dcc8bdcb0446b5d562cf05b4536fc7337344765215130d5f1e7ee906",
|
||||
"4e7fa771a5455d8ee8295f01181a360cdc6467cc185c2834c7daf9fbf85b6f1d",
|
||||
"6beb64cb024f9c5c988f942177fc9c1ec5ecfa85b7db0f13a17f9f98e8e46fe7",
|
||||
"6406bfc4e486e64c889ea15577d66e5835c65c6a39ec081af8ac5acdc153b4b5",
|
||||
"1b1da638709f9f85898af70ffaa5b88d5a4c9f2663ca92113c400ab25caf553c",
|
||||
"da49407a9e1ed27abd28076a647177157c42517e2542e9b6a4921fdadf4e8742",
|
||||
"3c3fdba2a792fddaeb033605163991a09933e8f05c6c934d718e50a613b64d69",
|
||||
"82c60429171173739fa67c4807cab359620299e6ed2a9da80139b5b1e23c5456",
|
||||
"0a19e5767e1381ac16f57cfa5aabd8463551d19f069f7f3465c11a8583253f3e",
|
||||
"d0fae6ffdd4818399eae6224978f170f696150eaf699f2f218abc00c68530f96",
|
||||
"0937889aeb3af5c64608d9a9f88229a068e53417448f00f9aa5e28c570cca8f8",
|
||||
"d6072d269753020912524961ce8c6930cf35abe5c4b2bdc7fd678338d20a68fb",
|
||||
"0e8bc9b06fcc842bdaa7df029bfd1f252d5defc014d58a006c10ab678ecf543f",
|
||||
"9d42f90520f02c9258be53b123d69ddbce5f33f92a903d3fb4cf3358ff0e07b5",
|
||||
"1cc05416b12cbe719617158773c3e6173435fc64e1ee44310dc696baecaeaa95",
|
||||
"266b15222913c11ef6403ee15dc42c8c0e16bc5fa2f49110447802236e045797",
|
||||
"791b123af3b71ac9497a010610f72207ff8ec642969b5cf0d2891b21e7eee562",
|
||||
"946d4d7b084dc32495f22b35fc30394144c8e0ba04f3ad6e2c2bfb0173a2266d",
|
||||
"2c015cb990c1583228d08b2d5de9227b950c3f57364fc1033bca5c0fbfd08c58",
|
||||
"13fdc41862fd85507f579c69accb9cc6a40f5971bfa41e3caff598a3dcffd2fc",
|
||||
"64b06d9874a83917c583c9439d1c736083377d67fda2961b623f7124663134c3",
|
||||
"2fa49cd19e0aa02989991a4c3760f44be800fe8fb4d58b23aca382e10dc0d2d6",
|
||||
"377628f265f799772e9fb6065be8b6eee200c329f729fe36c25ee179e4d20df9",
|
||||
"ba94fa79134ce383b6a98b04dc6ad3d1b950e410d50a292bc770f9685e59fe91",
|
||||
"875c924329f0733e31fe8d8aed70dc1906335b8a9984932b6368ea24edb39765",
|
||||
"f31f4abb3f5ee42a5aae86d70b3bd9a9c1934933641893864dd333f89719d608",
|
||||
"2bcd629e125514a780f568d3c2e8b12a2e7fbbee06e652bbeed3e7825508e31c",
|
||||
"918b43581163ca1963de21bb9ac401756e75c3f00ac8dcfafc139f1ad5d7d998",
|
||||
"5730dd57fa52749a0d6502b11c9d802ac495875542431310c674a65655b7c2a3",
|
||||
"03f84b990683e569e2f6143bb963a2a8de411e7c4b7923117b94c7afcb4b43ea",
|
||||
"b298c8510d35bd2be0ff0753ad7d98d480f4c6490bb67fb93cd4632ea726e8a7",
|
||||
"0a771afbf9be104c01b89eaeb57073297d35ac8fbbcc0816820fdb9a29d26625",
|
||||
"713d90d6ca1be1a4e05a5f8441dc528c699caa09eda49c09072f5f8291354c2e",
|
||||
"988827f45c19330d9404309f63d536a447803cca7cb182ef005b074def09ab7d",
|
||||
"9dcaa105b4def895f3faee704c250bdc924316f153cb972f3fb565beec0b7942",
|
||||
"1c06c30afe65b59e9e22d6bb454e4209a03efe53cdbf27b3945d5d75b1b90427",
|
||||
"49e08c13d1da209ec1aea7b7fbe0daa648e30febeb2aa5ffbaaabdd71a278ac2",
|
||||
"e1c2e49ab7b829854c46a64772ded35459908e0f563edbcf5c612913b7767046",
|
||||
"e08bb7d133490ca85a6325d46807170cd07618b6a5f6e1d069e44890cc366fab",
|
||||
"5c73ca0691cde2f35b7933d6db33f0b642ec70d0bd3f2b0ebbd97754ca67e248",
|
||||
"6404399151872a521dae767311712225dba65d810ba2feba209204221b5d772d",
|
||||
"4a0c3aa6cef36f44edf08ad8fb1533d7e1186e317da8a3afb3d81af072043233",
|
||||
"104b3e1af37cf10b663a7ec8452ea882082018c4d5be4cd49e7f532e2fea64e5",
|
||||
"e723a46bf9684b4476c3005eb5c26511c58b7eb3c708ddf7470ee30a40834b32",
|
||||
"18e6f0fa3aa779a73ceefabea27bff3202003fd2c558ec5f5d07920528947d57",
|
||||
"c97e73eb593ff39e63307220796cc64974c0c8adac860a2559ab47c49bc0c860",
|
||||
"13c363a962955b00db6d5a68b8307cd900ae9202d9b2deb357b8d433545244ac",
|
||||
"76a488865151fab977d3639bac6cba4ba9b52aa17d28ac3580775ed0bff393e4",
|
||||
"a14de587c9f4cd50bb470ecffd10026de97b9b5e327168a0a8906891d39d4319",
|
||||
"b1d38ee1c4ca8ae2754a719706e6f71865e8c512310061b8d26438fedf78707e",
|
||||
"772bb8a3f74be96fa84be5fa8f9a8ef355e2df54869c2e8ae6ad2bf54ed5057e",
|
||||
"3083a7011da36be63e3f7cacd70ab52e364dd58783302f1cb07535a66b5735f5",
|
||||
"2b1d892e3002aa3201deb4ffe28c0c43b75b8f30c96b5d43f6d5829049ecbd94",
|
||||
"cb738aabe44c6fb17ade284bf27db0169e309bf8cf9c91c4e4e62856619a4c64",
|
||||
"1707e04b792f4953f460f217b9bb94c84cef60736a749fb01277cfe0eaaa48c7",
|
||||
"ab8b6bac9b8a4f00b78acb4bd50ed2758e0fa100964b6f298d2a943eb2af2b30",
|
||||
"dd317193fef72490f3be01293b29e9c2f94eda10824a76ca74bf39dd7cb40ab2",
|
||||
"4fb3d995b087af7517fcb79e71f43bac0c4fbda64d89417a40ca4a708f2e8bc1",
|
||||
"549ba38c31bf926b2cb7e8f7f15d15df6388dce477a3aff0245caa44606849fc",
|
||||
"7585c14ab9abbffb89d0fa9f00c78ecae9f7c9062e5d4f1fae8453b3951fc60b",
|
||||
"953f855323f72461b7167e3df0f4fd746a06f5a7f98aa42acdce2eef822a0b2f",
|
||||
"0931932d57dde94dcfb017179a5a0954b7d671422149738260a365ca44f50eb8",
|
||||
"a3d179d16a4a275a3bb0f260cee9284db243abad637a9dbe92d02940f1c7ee8c",
|
||||
"959843f1e76ff0785dafe312c2ea66380fdc32b9d6180920f05f874c74599a80",
|
||||
"fbc36b3e1718fe6c338968b04caa01a7adb315d206abc63e56768d69e008a65d",
|
||||
"f054de7eac5e2ea48072e7fb4db93594c5f5d2dfa0afe8266042b6adc80dfdca",
|
||||
"39dfc68dc6ba8c457b2995562c867cef2f2cf994e8d6776a6b20869e25053f70",
|
||||
"19ad7ca7629758c22ac83643605c8a32a6665bae8e35dbc9b4ad90343756ebb3",
|
||||
"e89e80ea5c64cf7840f614f26e35a12c9c3091fa873e63b298835d9eda31a9ea",
|
||||
"572c1b9a83c947f62331b83009cc2ec9e62eab7260b49929388e6500c45cd917",
|
||||
"df0b21f679e6c0bf97f7b874e9f07c93c3467b092f3d9e1484e5646fda6eca5f",
|
||||
"8f3b7c0f4b403af62fe83d3cfac3f1e2572af8afa4cea3f3e2e04291efe84cf6",
|
||||
"aae8b8db243009d021d8c9897d52ee8125a17212f0a8b85f681ad8950ae45f0e",
|
||||
"3d45a4957d27447dea83d9ae2ef392a3a86619bfcf8dda2db405a7b304997797",
|
||||
"a5b0a619a8e3030b691bdba1ed951cd54e4bc2063602eae26d9791fb18e60301",
|
||||
"14650df217dd64a2905cd058114e761502dff37d40e80789200bc53af29b265f",
|
||||
"fd6a245ab5e4e6e18d7ba9b37478ce38248f0ab864e5511d2208ae3d25017e5f",
|
||||
"fbe0be6dd42a11feb5db5ae56fcbbac41041ab04a35f1df075580e960c8eeab0",
|
||||
"72f3f1213d9bec92ba9705b447d99cd0a6a446e37a3c1c50bb8ece1090bfe56e",
|
||||
"20df836554e1534f62b2a6df9ce58e11c1b9b4746ce8ee3c462300a8c01f5e76",
|
||||
"5c3d2a81b7331c86420ad32b6e9a212b73b1c3413724a0f91bf073eba18e2f1f",
|
||||
"63264ddfb29cd36fc18f3ee6614c4101ba7229bc5ac375f912590d3f0df982f4",
|
||||
"5ec4eb637761c1c9dbc6aa6649d4410508ef8d25d61ad6caa40c6ee3236d5515",
|
||||
"270c70940536017915e1cdbc003de7279ec1c94cba1ef6130f4236f7e306e4f0",
|
||||
"c1d1d57a7c03f6ddeeab5230a4910db8355e2143f473dea6e1d57c2f8d882b76",
|
||||
"218c030a7fdc9917e9f87e2921e258d34d7740a68b5bee48a392b8a2acf1f347",
|
||||
"ac47861c01c89ea64abee14cf6e1f317859ed56b69ae66377dc63e6575b7b1eb",
|
||||
"23bf549c8a03f9870983c8098e974308ec362354b0dcf636c242a88f24fc2718",
|
||||
"a3ce8b817e5212c851c6b95e693849a396c79b0d04b2a554de9b78933fbea2b7",
|
||||
"7310120c1cc1961b0d3fce13743c8a7075ae426fe6cccaf83600f24cee106236",
|
||||
"8fa0630f193777dcc4f5eccd1ad9ceacf80acdf65e52e4e01bf3a2b2fdd0dac6",
|
||||
"4a5f5c87f67d573d0673f01abaebc26eaa62e6d04627588549cc9e6c142dc994",
|
||||
"78971cccacc645116f9d380c167f955d54b386a22af112233f7de004fc0c8316",
|
||||
"badc67216868e1de1bbe044bf0e6070e6ee0353d05c13fa0c43b1897db5219a2",
|
||||
"c45b2a168bc51cbb615a79f97432cc4bb6b104da9cdc1fc640c930657452f71b",
|
||||
"c17eda13541d14554c5db542155b08b6bf9cb403d425745b662ebc2b2b9b3a3b",
|
||||
"313210cd9d2efc1603f07859bae7bd5fb5914f4a631b943f2f6ff5927a4e681a",
|
||||
"6ee94ec8af4e6828f9b46c590ea55da640ef50e810a247d3e8cdf4b91c42d2c2",
|
||||
"505b7a4d9f1ba6577aa2a941843f86c205b23b1ea21035925e587022e2f0aeed",
|
||||
"98e6a7cd687e8192e300a8202999ec31ad57bc34f656f2ae90d148607ff6d29f",
|
||||
"1be5db002c0a446cc2c1da363e5d08ae045cd8f5e76c8cccd65d5166393c0bdf",
|
||||
"17c02ac6d390c5c735e1e873c40294220e89071fca08a5da396a131fa1ba8670",
|
||||
"2540507c39ae6fdcd90de826077f0ca390da126166a25c15c048a60606a27367",
|
||||
"5ab9328e525c7a017ef4f591d995ad4595d74cbf8ff4112af33b08c70661a304",
|
||||
"9c105587a96c51d81422f64e46016564d22329760648c95dcac7218f3733f915",
|
||||
"525afb1b94a75f1edc2b55c700071e14a2166acda003370047c30dba8ea80278",
|
||||
"745d4a5d9f95ca4efa6261b6bcd4ecacd504b5b901a2ce1353c522a5c0c15dcc",
|
||||
"5a5a568cd87ba34252ba254e6a320e1a7f52f13e7451bb887efb34ff881785f2",
|
||||
"1ec50a80198cd830b51f4f7a0222015a268d9b40f04e7f838c7b8dc7abf63b01",
|
||||
"68836b662d79349cb42f5cef54e6a066157d398cc87d3b13f29fc04e5cf364a5",
|
||||
"658db317f355a9cbd86f673775cac0c308fe14967428fd283a36e300a6a53b2f",
|
||||
"677d79a8c467dd9db38f0ef45c2787dd368f701a6b47bf7a5f06112c38da643e",
|
||||
"2baa455d4066f5d628f9ecd315cb57deca71069db5d0d112ae0aa18a84b6f0d7",
|
||||
"5e7b0889f351560081360ac2b1429b48b2f7d886227f144e3b198e2f1fa56ed9",
|
||||
"c3d317fbf26e15add8b4f8f93df9de9b22297b8e4945ebab9ee249d4f72f4e45",
|
||||
"3c0b705a5c1e31abc7e46d8ff3c148a033f6875454cfb67f8d2a2b9a57a5ba7e",
|
||||
"a0ab74663561af2adc2d38be3569fbe7aa2454346416ac96e5eb26b1e01b1e2f",
|
||||
"53526cffdb74327670566c1dacacffb7d30a43a7f1862ff8bab87737bfa5edb6",
|
||||
"24c5d36ab98d88f87b2c71afb4ea8562e05c7aa0b50f3bc0f9ed50a4cd52989b",
|
||||
"c3ce4de5f94dff65d11e33a865855a4404259cf45263914c884f79db4f35169d",
|
||||
"f1009b6dcf30030cff872d636fb96ed233eb6ecb8ffed003c7da64e4f5a02f4c",
|
||||
"e3729f58614d3b42450d1599d863983ab7e3e5c29fb57aad7958c8923a2627c4",
|
||||
"31cf4792f7b5ce01b217ec80184edd2a7c49c0b21701f5494ee2c9bac67c28ca",
|
||||
"b42a5c9c92a656c5bb2b759ce160fdfd245243aeb1786338faea63b62e9a60ce",
|
||||
"a1efc8d5d0855933d5ac8fe5960c7acacb92fcb09bfbc929e5002f168251e648",
|
||||
"c4322c7f3682ec94b0dcb42f13b498c36cf575d505aacc8ec8bf67a6a2abf4c9",
|
||||
"684ee5aa3c98357aeaddcc30c6620939b52aeef729e24b4a46ccafc44f24d831",
|
||||
"36180f2ae11d105e0efbfbddb94e6b45b08609a383e4e1a8fa3b06d7a8051de9",
|
||||
"96c2d183eacc87581a0b17b8d07878bc10d436728510715109a7565d9972f8b5",
|
||||
"3068c9d04d561c7e29e3f621280b61a61885de0e9ec35a66a3116ca7a9e09627",
|
||||
"2eb94b9673ad6f8f88288fddfceae4baaeccb37bed88a35611d826ba06a5363b",
|
||||
"fc8cd5fae8b81121001f7767dcd5f185c0fdcc88cce1fbb184ddbcfad697ba54",
|
||||
"51521da1ecedea6d588d774eb155d936b32a14913c2f11d989bcc5116e65bf41",
|
||||
"3d23542e597a83dd6307700d79058b920f281c65f832333734d8a0adec510495",
|
||||
"11d2e01913ff0d4bd21970d709d88e63289492c0bbad7bff99c0d36858a841ca",
|
||||
"de674f1eee3068d2bc8c2f2897d8556e5deb872869652f7d3a4e5dbc6f1063c8",
|
||||
"e722d7f728526110c0921791b417afde4af1e87ae48ccc01911786197843104b",
|
||||
"aaba3a4e2a7d20ab76edfbcccefc27acfd509db3638582c28230e73ffd71d340",
|
||||
"1385a7209dafb9622dd4274179832e40c7fae19445383c34ef79adb0e4de0c98",
|
||||
"108408531fca288d74de4a2c596eab8569e355d9ab2f8380f4d24073a6b3fa95",
|
||||
"294476a86fcd39351ae452cdb8af9584067ec4501ec6182d0062bb154559fed3",
|
||||
"e64b175e0284c5cb69c8db46344ed43b5ced8abfe3cbf0c197103cfd116944cd",
|
||||
"cdd73a0f1fa7c14ed2177ae2163035333718847e49dd5cca6775bd20fc7553ad",
|
||||
"d423d2a374bc66a4587a5e3affa327ca75b8116051320759a3b88a868a7b80d4",
|
||||
"f13ad1e5b1315557d5497b58516eb3b0759d909725ddd0eb8a0dee439c6c0a48",
|
||||
"3a600b547a6061186a54e491344fd50cc7d4f0566a386a40aba6545254773728",
|
||||
"37a6f3f221fe17cc04a65aa544d5135e8297ecaf0853ba784dffacb74feb481b",
|
||||
"0ca42d67d0f84b28861d63e919e6ce5ad527447fdc53a03d8497a0241bee9376",
|
||||
"c7dbda42459e6fadb92c416eaef3e04674fc57915a93f3be4e656634c9654075",
|
||||
"0e34d728ae4fe347a5afecdf886fbd4d48a65c5d0dfab807da6ae95b6b2d7a3a",
|
||||
"f1bc69257ed510db5b2ed370010b037f452a29c49e36337264b3011ce2516216",
|
||||
"33f98f6b8a8e202463955998fba3b790199daa893e5471554826cfd9daa5c02f",
|
||||
"f8a0a37a2c9ebd7022d7cded1ee0318fd363020070b4cdaea800e44dcc1300d2",
|
||||
"6862714daedb908a4d86a3a3f1e65ec2c29ae61501b4ddcaf184243dd095d71b",
|
||||
"555cd19a6d21941c1174129b8bbcc70edcf0d6874262ce9e1e542351990d523d",
|
||||
"2cd6b44326828f23a2aa33699754bfa072c4883f39d53616f6a6b74149b664b6",
|
||||
"127f45d2eacb565c21c1030fe8054fd0a3a75705bc368924712aa145d414fa47",
|
||||
"19225e2dae6e1166f21cdab1290194470ded09df9b66f3faad3c1cc9ebcf340f",
|
||||
"b7b3f53f0539b2b4837b8bb9dae0ccbd200c8d36126d9f50199d68a4293a46d3",
|
||||
"6b6323be01f27d6d759d9670825e8ebb9c4cd8016351702328df91cef36cfec8",
|
||||
"020c31cfdfc5b22b10235745b89b311d271cf82f2ba16d03fdf7a8bc8538694b",
|
||||
"62573218530182b79e40d0113b7d281dace6da33bfcd0f9318558de5e5c76f08",
|
||||
"37d928416b15982f5bb8be40c5b62fae0b664e412c25891f8860c4242927e610",
|
||||
"b07ad11134a5c0542d2b418ef3863e8ea8477de68d9310681818ddd40825fdb0",
|
||||
"4af77cb76bab845b56470c95ce7b8cd84ce49a095984c1f3eed67b0ee344316e",
|
||||
"e3fdd4668d8726ba6adc401ac662c0cf6b5c1872082c488ed7da966d425fb1c0",
|
||||
"3dec71c81c7e78e879abc8da8b30e2446edbe98eeb8df9dafe9201ebb4c6a834",
|
||||
"7105467d9c5e855f1362fbddf820ed5e757997862efc9000317d3830a2f60ef3",
|
||||
"2821df94b021d3e77e8d9c0f3972340210f5ea2c0935cbf125cfc578d4d6722f",
|
||||
"114e5807accc337a22598bded30ebf3e0cfd75877e239f10cb043f829c315ab5",
|
||||
"d658a1c0354628cd7312593ab25d5b9083de8f0def6e8425f188101d256cd136",
|
||||
"4818d3be9b2a38fcc8c85d6c46f69b502943f79cf2462dfb0b6499e761bcc836",
|
||||
"92b8c943cb017b5f2d39264640c069f1ecced1d3ce9b3fd755d6df2fddb99458",
|
||||
"6edbd0fdf064fcbccd4a9e7a8ea520b87cb7faf867f7fe8a5f53625beb575119",
|
||||
"bf3b49c477dafb06af65bf09851c0fbef9dbc3152a7268d31b55a8e7a9a95860",
|
||||
"0e234dbadfda1393be2f068182615dbb83736f84f87710b5c7965bdce9f4a26a",
|
||||
"df5ceae34429e47b92bbd5505ba27666552e0eb619997f359c55699c3252b1ff",
|
||||
"08c1c7d940d699a91a83249bd578772e8958ffe23179e6150f07b96f1b47ce1e",
|
||||
"6f919a429270da0022d70062537bdc1b21c43a8abc552d8e366647e5b719d310",
|
||||
"63c66e5fd5d27f6fda87912ce46fa91a5e5b3634ed147fa2986330fc2696d3fa",
|
||||
"bde070b75296bca3aa494e7f549cd2bd1ff003776712bc98a3164b139b2054ab",
|
||||
"66694196dac5b60cf5e0ae05db8f3894fe04d65910686806551f471a0a0472e9",
|
||||
"0d2e97524b7ce4cf30b54e61b2689df036d099c53d42e2977b1671834bac39e7",
|
||||
"e081af76e923455f408127862be5c9baf7de6b19b952aa2a1da997d4dfe594c0",
|
||||
"121bf6ae1596983b703d62fecf60ea7dd3c3909acf1e0911652e7dadb420ed12",
|
||||
"a25e7b17464df71cd84ad08b17c5268520923bc33fe78c21b756f17353ea39a0",
|
||||
"e985f078fb44dbfdf3f4f34388f0f233a4e413e02297ee9a7dcc3fcceacd44f9",
|
||||
"b9184cf45e6e6b112cd863b1719de1bcab2137eb957e8028edca3a204a9ebb96",
|
||||
"157d177d5e4bcce0040eb4bddb681eacf9e2942e1c542a57ce851b4742a9cc4f",
|
||||
"0823e06635c9a1a69fd8833d1e48df98d711c1c47c06f27bb384932db1bbe9ee",
|
||||
"8beeec1fd1bcdecba235b449cc49abca69b6486ed1c0861a2bfb6a43c970b86f",
|
||||
"349f61a1cfc9112e537522858a0edae732a2f8434cf4780d3d2ec1e96f581cca",
|
||||
"587cdf72b5914d364f7e214a70481cf1131ee4a09e6b43e52428d2e56b000c13",
|
||||
"a6aa0c179316534c7b9ffb5f42a2af98d1d3a166bfb413199579f259c7b5e6df",
|
||||
"f9f3bb1ba8da5899b79186008ecfbd416b49f3b86d94045b91e34a40e41d5cff",
|
||||
"0cdda65a60b7b4d94e794c9397e01f69fb29309ce4fac83e7392dbba6bc497f9",
|
||||
"8fa5fce5ad09d43af7218ea5724cff2c4849a59ff73caf3bbca466e3c8538ba8",
|
||||
"8874ef46008753fcc0b77eb7a4a8560e35966bf5a12bcad4203ad2b4c1f8bfbe",
|
||||
"a8ee9a3aa2d0c08a951439ffb0e6d10315fc4776997b275de1ec19663e88c2c2",
|
||||
"9c184cbbff464ab4d5f6bfa78c39bf0880fb93b1574139306a97acb940d415c9",
|
||||
"5493a38c255c91ca49b958ed417f6c57e5bc444779d8f536f290596a31bc63d3",
|
||||
"3e1e82b96cc599d9fc55ae74330692ccbfb538a4cc923975fd8876efe4b81552",
|
||||
"16aaaf820c24c2726e349b0e49bbab72ca6eef7b3a2835de88d0cececa4da684",
|
||||
"7fa52ba349f7203c3dbc2249f9881101a3318d21869dd59f17abf953d234db65",
|
||||
"713d8018bb9ba3ab55c3a110120b9d7593514111075ef05f0fdb233ff2ceddc8",
|
||||
"56063afb495759a0942f1c33f28a4fb8320c6d376cb3c9513249453e45f24a04",
|
||||
"f9a6bacd9e055749b45174ecf3c3db18b78f3474761948a68adf601f54e59660",
|
||||
"7ddd7c6d41572f93fe07c0300c34e455b6d1f4372204933bf45035241c8b060c",
|
||||
"f81021b893a36b201de71330a2ea050b59dbf7560c62fa9cbea9261ab47a0ba2",
|
||||
"a01fbe4114c18fd534ae1621404d25c08e3b6775a2631ff40279bafd8c9304f4",
|
||||
"350fad8ebc938c6eb508a1483f385f577794a002bc1229db70a1b0131d174b9d",
|
||||
"570cb8bce87f532c5051d8c4c864012408e672a7d492669e660251fb1e066bec",
|
||||
"8cb6efbb129c84eba26d894c4293b476a6e9a1fe969c6ad18b554d2a57885f36",
|
||||
"f384a98467bf7f084ca31bea121a4ec76e530f523d3225c21ed25a18544a9916",
|
||||
"da127ab58ce557c2c95c20d6a291c2e5d880fff09dc28927b7bdfec97b995d72",
|
||||
"a4d95b4f74366ec920d0a0c5d81265688cc18733ffc444cac9b01ae2431568aa",
|
||||
"5ae2a71470570733422468bb733d53c85b1c8a6e7e6df5c05941556bcf342d1a",
|
||||
"65a2d161ff0e095d3afe37584dbbe649f1e9cd440755b5a3c5b2a252d5c0b8bc",
|
||||
"25ef70a8e41bb422ed7996a41160294e33238d6af17a532232f0a50b123431a2",
|
||||
"f1f0f76ee901664a65b97104296babb9c7422370e99bb677ae07c2ee420e7f40",
|
||||
"c3c66dda180b0330e75c8139b9f315a8c6b937f55d87d7be42e172bbac60d71e",
|
||||
"5881786695a9e58e19d79f790c7d9243a847c0269c5770bdd01f5149c2a62a88",
|
||||
"f2f816d3c8ebc7df06ab68d39223181aacc7be04364d1d4e69a56c33949bb983",
|
||||
"80a1c3b6b2778d4846ad9fe0bb2dd5afd99aa897f8231bfaac45fde43d602d9f",
|
||||
"72ad67cb043aa5df0c3dcc2464953a66893259d81c9cc7778c12bca3447fbd58",
|
||||
"ad72420a7963b8d4536d8eba00b4b989992247cd8c01660e242a8e71edaf0e19",
|
||||
"999d603d1cf6068e3bb6abe1bca976fa0ab84c4660b29ea8973de8b5cf5fd283",
|
||||
"e137a5910f02a764c3a3d8f1579ac0c7e3cc34e58933216868efe010332c1e6e",
|
||||
"10e0fa2362f59317626ae989bd1f962c583339d8d74d76c3e585243d152b91e8",
|
||||
"1951c652704962f5c6e33a4d4aadfee5d53ce2253644d1ed542da3e278524a07",
|
||||
"c938bccb7ba6c0217d8ba35ed91502aee051c8ae5bff05e88aab3b322aec936f",
|
||||
"4d6386c689785edd5beb55911a3a9fc8914838c8192184199589beef8b6ddf9f",
|
||||
"26f6f45a6468bc4b1f085fd28d63c264ee17564f9e247fc03ee179a0b579dcda",
|
||||
"235b7bb82b72c61acd5979ca5f2ca740aee805a780ba22e11aae5cd34f6ec760",
|
||||
"c027ffb585a1e4844b4907490b621b08c7e40a5e6f93e97bd4bb1b615bba9908",
|
||||
"aa77fc8053d139b998577319de29457b78b1cc8b35a5f3526c0621eaa42ce6e8",
|
||||
"afd0af9a11c5ae2a7c4a4571ce39ad57d8df70ef146ed83ad8eaff97b2387fb8",
|
||||
"a1f8fee9f1da9a2b306489d00edf754187b55e97f4fe6f249432fe6c7f44d6be",
|
||||
"4f12e8a123465a862060efb656299e6bef732e5954b02194308817b243e84d32",
|
||||
"6a1ca62f7d6952ad2eba1c64035260319baf03deabf856ca860744fc886b3d3a",
|
||||
"c72dd1fe890d6e4c1f7325a4f224e85aef6cdca8bf9441d228efaf126e02ba63",
|
||||
"2f6ddcea18d891ef4252e657989de68adcc43c2175d49c0c059c5e49b9dd5aed",
|
||||
"24efac0f240ed183c30398ee40307623f52113598f66c5864c90fc62643a2aec",
|
||||
"6ba3ebc935e7cf7fbb446e7f5c12b19c4455e6894412b0eedee4fc945e429e9a",
|
||||
"3519d6e5bc9649f97d07a07ef5471a553ffce35c7619f4f63e91a2ba38cbb729",
|
||||
"65e073df352fa9917e5c2475167e6c523b68c1406e1b6e81109e2d4cc87c740d",
|
||||
"d73bf816c3648a7d53d34be938c454e515efb0c974d5a225f33635540b2db90d",
|
||||
"bce167790fc86a273db011757d09e2d1148521ce242c2ded58f26cc49993aacb",
|
||||
"2d4286ed4039916f29602e86f47ea4c5b05998c0198509ca7799fcadfb337e8d",
|
||||
"9837c495b1af4f76b09177514a0f3e1dceb509c52b91712f3c7d29dc1b91d09b",
|
||||
"5c848b8291f39759903ce77f151acf40f3ab5afa2d4a45af62b320371c29a697",
|
||||
"b92df5016ee947ce6a21365d3361977f7f2f6c14025a983c44e13d3e8cc72152",
|
||||
"71d2f57222a39b1a7ed2df5e6fb23a964439b5a8e7d49b49d87e5cd5354baa75",
|
||||
"88b44d0198fb15b0c20a97f87e021c744606bfd35eae2874f35c447aa4ac3cd4",
|
||||
"29bb4c2557714119cd684da2867e689e37e3ca9c912db83ab84746816f6092ab",
|
||||
"b1836d98a288752675b133b9018fa1edf174f311921d01926c1e1a5900c21029",
|
||||
"a00645e090c7d96f3155ffbcfc41e526a763b0f53a98151ac4a7d4a5b14066b6",
|
||||
"78aab09919d17773b0d62799b37bd2e2970f72f5d1eb6472489c367b6135374f",
|
||||
"eb6123aeb28608f1c97b2bf62ef69f977cd0658a0ab491deebb1e972caa938c5",
|
||||
"8dd7ef1650b1b30cdf7814ae4d61a237eb0acc3ec3ce0f72b1c25780329c2d7d",
|
||||
"b1998419be3172858b990eea84fe10bb24b76c219cde277cb4305955fc7e0b65",
|
||||
"1b10560016c4bc506eef9056dedc2943a17179081e6eaf85b48d37dc20eac3cc",
|
||||
"1fb1d9d4d408a6734234910f554d272739a0d6fa401918d79b57be62c3f23ba2",
|
||||
"dec878f54ce36788289b61d32de0d9539032aba22cd15522752f729659c7cc5c",
|
||||
"fdbfd0773f5a66637b093dabf812197940d1134619a7e60a931b19915b7dab0a",
|
||||
"21bd2c9aae052a1c187947d2964f2be4afa7b30248409c41a75522e88a4e7977",
|
||||
"59326adab03416ec1d36699c18e5e4fa13ca1f2212d48c23bfdecb0be7263616",
|
||||
"bcf263d39457c0aef8ef42fd98f8131198ec4fb203155dd5bcd759e499a9ca5c",
|
||||
"f1ad083bcd8c7630eef93336d8a971ae8ae37166a6a00ac39684420c5f9afef8",
|
||||
"d82ee2ac41b36e3c1787a01835bf054070486dc20f6565efedbbc37cd3bf5fa5",
|
||||
"eba91a0dcbd3986299b0a3e66c116f77bd3421829291fd769522f01da26f107b",
|
||||
"11016558b7e8c6386c6a3e862691dcba47e33e257f0e7df38901ea7c0eba894c",
|
||||
"04f02795e34a0030e5186c8e700da8a46b1aa6bc0abed6b35c9c1cd6a73776b9",
|
||||
"2628dc8ad7fb731d59456b2755a99c6701467125fa69816c21bfccabc31edf6b",
|
||||
"9b7ca249ee5b45cd264492f30df09f708a7d9caed7beb9a5c6292f22e4c31f85",
|
||||
"5c42e7caedf382092faaf392174792b3cf5f2fe29cb586387ee55611af0617c9",
|
||||
"373f2fd5940a01feb79659c8b9099477f6d3e7b570ebb749c2ac336ea4be583d",
|
||||
"fea22887147adc3a659a14902080b03e86b4b8b16985fdf0bbacaed00d812422",
|
||||
"6a3e51a1443cff62af9fa12fafc8ea78ae74dac7792c9ae0f436f570ab33eb71",
|
||||
"796be21e213d6d0cd6fbe2de1555fb73d1cf9edc041a9f1ff1ad583c4ca92460",
|
||||
"03fcbcb31d3fd17f0eedb45ac5a51678c7c8b2b8498225d05f74e2892f017f72",
|
||||
"d28da07c6c22daf9ae987b3033c33d3140e5a56fa1ffd7dc5c7853d55a45bcc7",
|
||||
"fbb0ce02f50018741a12fc08eea80a18067d7bb0fcd96153d40bb8c808473aae",
|
||||
"2bf7c05a0209b4ea31314f04bd754cd01c58102d7cde8c496c655b6494924354",
|
||||
"1968a9e6e14ae86a1e02e6078fc4631851fce5dbac6aa34f860defd1ccfd0ded",
|
||||
"d886181329c9e06462a1407f547d77b38ff2c868b86d8976aa478e1cbb3d66d4",
|
||||
"0d465e02ff2f8eb0b5fb2fa9a38579c5d66337d4a16b58f8ed28d2d89fc02392",
|
||||
"3196419015289807880ef24b6781734822d654dc260c0560d00bac65eacd5219",
|
||||
"fa08390ddc333a2a12248d5ec3e51fff9b782227069fe5a0afbd8eba967ae8d1",
|
||||
"49ae36a791cb84516688d59a1ed3e5112851d65f265078aa2d433b45fa984c8a",
|
||||
"35daa428e12c59da6730760979aca3444d8b31149c6febd99fbfefa4b2372082",
|
||||
"5ef1d697beba612ff31d1dc139817c313a4e2ad3977775943b635c141ef0f2a1",
|
||||
"674256037ec00edb66b9355fb1d33a30a47a5d1f4bce2dd5475d89f1ea6502db",
|
||||
"7b6f017bc550933af91eec32a79464f540c5e0c208703e175843ee4e9ffc0a50",
|
||||
"bf0eb91da1d18dbb18fd9ff36c837387887ba142961176a44889718b2becb9dc",
|
||||
"3e5ac43a05164b074a2ff6353e9882917c5a3dbe168c2695de895f7decf1a56c",
|
||||
"35e8f004965347c2b18a000a83dd3a8084b8a4bf00522061ed1179aa1107c413",
|
||||
"fccb0fff3a24e555ec96f702ec11d420338910d148fc7b039d67568ad3a0e032",
|
||||
"5cab231048032dbf921b4fafa1951dd2da93bc3740667f31d5a1d5665b141261",
|
||||
"ffedb24be73441fbcd069f7785ebb865870e0f3ed228190732e4ffd5962bb82d",
|
||||
"a4fcfec18adf92f4ed822f64d2da9f5ae630885a1bfa626530f641db99aa7a30",
|
||||
"f98bcee41b0e3deafa1efaa1863750dbfd9bd7430b82529b670867d852230b5d",
|
||||
"8ab8d5fca047a52364a737c1af57bf656c9ad5049f08ef4c5aa252e61aa72123",
|
||||
"91318b39ad94c1d58143586b6d90dd6092a9d7487e321f4976967b6ac445ff43",
|
||||
"fabfbd4569ab018e12d5ffa9b1a40ca8eb2ca60a685817351d90eaa770d5eccb",
|
||||
"bbc5ef34428d980e2401942ceecfe07cdf21bfb1acae0596ea1d43fccf504f69",
|
||||
"26943e4201ea407a5667103fe07ca6e08ef76940f274349b0e2e776bcfb0acb6",
|
||||
"e3b305ffe33e72841f8e2a8688cc5cc27d42aee7624b33b7b6399b42db392437",
|
||||
"17c5a763dd57e6bcc7c4cf2db0eb5cf3e97116b67fe0dd519c97e4a4d55d5a62",
|
||||
"bbd260216879ce86af8318ffcf73c9e063ca76dd8bc35d3b6be45b2b4184888b",
|
||||
"41285591d0595bc42ab663051b410d51af39fe1720592e27acb1a8af72360a76",
|
||||
"f29acd6068ce494d0c0fe294cad91bb8968e3fff3f595a113227ab545c3ca3e6",
|
||||
"ec9013c6394528e7dd788ce7cc085ca79fcdfbb37565999d5b4b5a4e39452ecc",
|
||||
"27829bd7f1a8fcddcad0cc34a3b3fc67d62a2f3e09f8e75d35035c2281e83afd",
|
||||
"666bea9db4e15087204d076294d221d4cf5864f5d94de38f29132b1934a17ace",
|
||||
"a3a30924cad3dbda3446e5a6324e0a1390c70f795d5ecfe17ee5c70b14f7d87d",
|
||||
"19567fe5fdb10711d60aa4d9843e1c49c2a6d2fd1b5cf662e2105606bb7815d3",
|
||||
"b139f1c3a2f15596b9320334e37e4184d5d584c4a81e72d821a7edcad3aa62d5",
|
||||
"08f1531e0e3e8f8bae313b2c60a72d5601bf8b60d7a4d2f60e8481650340d250",
|
||||
"c5895669e1ff182bf1dd6c00dc955265e08ded0952b8ca62a1c63ba11c99f4ca",
|
||||
"84d1c28153f66c1a4eb5fa0df695e936d83294df31a08d8d8e2d4798d19d8ce0",
|
||||
"b8699f6af853fdbe897848feb46a05d733363f304eac4c8c1932e6ea4bc062cb",
|
||||
"10eb3f6c1d0661468d9ed83593e5e9c0b43c6feec6a5405a498194905ea6ed48",
|
||||
"509e215a600d9cadcbf5d62632ba321d7314764218db00ce8c907e425fccc445",
|
||||
"e62119b7be84c8eaad41ba7f4a35da403f4ed96b967a3134e89ee8b78f8792c2",
|
||||
"f790754a95d59ea5ffe6b9b5cc386c600a9e19e8bec997c192764365f1d05376",
|
||||
"990121b5aa4d6badfb7154db4cdbb4512124bc2f442bebac71ea90b5cc86f203",
|
||||
"b6983dedaa891eb14c964d84461e5cd37ed27b61771c64978ba83e3ecea194fa",
|
||||
"00fba1ceaa6aa1e378cd5b22a771d6070250ac37f4e17d7bf1a70b3139e9a860",
|
||||
"429854e7738abf2ecf46909454039e2fc5a080eb9a3c0c5ea13b07426dac3ad9",
|
||||
"ceb3e017944b0dd787be219d8629930b3f2e20e22b12dc88fd838488ebb896f3",
|
||||
"eb9e5d14424c63e675fe771b73ca865f7d38cf334d65e2426e12a0b88c1a2236",
|
||||
"556ee713449e6e59ac4b8b2e8310180c8f6280484e9db23456526cceb9216168",
|
||||
"bc89c3aa889e0144ac526a1f861227430dde7e439cc6a7e9b25c9a049c3ca7b3",
|
||||
"56d070c62ea99be66fff741a8e45fafda5f9ff783e84d5395b251f356ce4e16f",
|
||||
"ace15859c399e5ecd13b1420d3c3703c6a88dfb4a084f7225e7ba40a4b444fc8",
|
||||
"f03f1261ab6eb879fe9c5b0028cd400b3ffdfac4344e4c75f6cde3c05ded1f26",
|
||||
"955b2fda8d0068226f89270028b316b5adac871f1c1c85435479aba14a381b0f",
|
||||
"422509a98d7461a6b8ec87cbb173b2486577b59ea9b269e01c20567b38b3b3b2",
|
||||
"007d4de62ad89a4f5985f0cd9b76a7293acf383b4e9e734e813b9df1d57f986f",
|
||||
"13a04e32948225b7e22aa0137341ebbb811e0743032fac16be9d691a652db2eb",
|
||||
"8244b11d880a52f9f9e1830a822e6eeeaf0b12fc759f8261bc2f490cb0794f3b",
|
||||
"27d3415f8f8fd3048a1ee0d9487256dd1b0f9e31be663778efa5b3add63868ec",
|
||||
"0053f888db916a8905320e253fe2f0666355e6fb6de36f897231920a3edfe39f",
|
||||
"0bc5c0a2ea47fa3bb8be107e3b9d6b7226b1c8bd16ca1bab8f51b8e1de08aa8b",
|
||||
"4ca13aaa161c79025b5cd6c9a8ac33554f5ceb479fe293d9a342c865cd9c9948",
|
||||
"333afbe82e2a3df38bd1ef998f39c5feef2554697aa21b5410c0e95ef9156249",
|
||||
"587c4fcabd18ff890064171fce3d5be0c4aa1bba46893fb6a827a85ab54d20f3",
|
||||
"964328e4d51d67c4e2f1fd102a66b861d98199f81d18d660b1b4b52504cd772a",
|
||||
"196aad5594651efd679d30b9feb0f0d172cf977b4f89aa670ec741a8bf21e669",
|
||||
"9137bfd66bbf47bfa0bfcbb9f6e71b6eb3fd9776530e9fd30d3dab19e182f35d",
|
||||
"8217392c4ed2313188f295d94148a027a7f43824a5f5fba33a0b8c1045d509b4",
|
||||
"be9e12761519a4836e73015544163254877e1c4912fcea67a10e7026421dde75",
|
||||
"7b5220421a520b876cc6cdba0d3895104d7fac914dca5b93f9fe8b226566b71e",
|
||||
"5c83fccfeb4bf0eb8a94d43ebc84a81639a32f26c7ef77d0a2b626b7de7befdb",
|
||||
"132fd6c92cf176f975efdb5ded53470b462a48a2815c6f54a93ce4f935784cc7",
|
||||
"46a3dba364022d11aa616a2bc20e3be5c4390f38b9446edfa464d90d9af5d48f",
|
||||
"34b3f3fd8a83905a37762060f51d0b116377b4820b031b8e668e16f46c5b0285",
|
||||
"f0e397e033dabec859a4b9a9043c5f1fb0dba504764d6bcf2fe9bf2ffd318474",
|
||||
"85ecf59c7dd3b24ad17f591bc4737f32f1384c370a7a6f2add06a811dc824b6c",
|
||||
"4d03cdb1e6ad8e066a83654626d8c221433e8d4fd901c671300af37e000177f2",
|
||||
"61cb9c651893e6401b25f2bdf79c9f3ddc9ffe69cf6c791c420462bd73e347e1",
|
||||
"85f2686a42158cd5ad327781ecccd1bdcd346941dd4b4edc45f717de6a011800",
|
||||
"92de2ab82cac528e6d4ccd61e5b7c79591dcad9909c8ad3c8276ece6d48c0f08",
|
||||
"23a878a06bb94bff33083349149f3c860f2b00bc3fb28f04cbaf717c08af19a3",
|
||||
"1b1cce18ff0323566b192885d7ced30f9a9531a2580240f2c593a7d5b8580974",
|
||||
"08fcdec7ea1376d84f3b13a47a4b73c7781c9c7890bb28f712b58af4fd3f24fe",
|
||||
"03cc08fc4ece807c6495272c412be23b045622cc6b786ed8d5c94156ae678a0e",
|
||||
"c4d8a61dc3f5dcf4b83f27a90cbc37e816cf4754e12309626ec5679c99087c46",
|
||||
"b29d00681e29001cdd63c4bc50e5e25715faef692aeebb678c8050e1c095e888",
|
||||
"ac154617e93f2bb1afa232675f2135437a9cc9700c14c51c40084946596ba11a",
|
||||
"ce9549de8e68ae89f424dd9e1cde8a4eea2069da667cfcfbe837691d37366668",
|
||||
"426c45a98e2af35cc9708149f6c086ff5a3972e77d62c627d5e20de5d731cad8",
|
||||
"7e21bfe240a3d9b77a129c734a1d428dbc890379fbaf862853f48b2f7470b2b0",
|
||||
"fa090a71f77223a7210de6db18d9aa809e89fb15253aea28131df6c5a7639140",
|
||||
"7094ad044c5ab025e088b43aa0b947601fabe58ed700a412fd96e4b917ced0c8",
|
||||
"936d5cdc4f081b6fe36c356af4378d472cd7990303f2ea44da645afd7d5d7f9c",
|
||||
"05342037d3b69349dce7b95529d4b2a63ceb9d9393217a68f7cc8c958a96c3ea",
|
||||
"ff9e1c414ef27b1178b1de296526f50520b7ddb06286bf9c47792bfb449e40b6",
|
||||
"2f2b7bedb34d2854b17ccb702cddd8bc0157e39721d58be0b2ad54ee291fc9f1",
|
||||
"0d8db1f34140bbf7eb809137018a74af08cb3345b8a3e368cdda8521dab45791",
|
||||
"b109e4bfabcfe4a1c38be1156d9ca851c75e6aa2e57c0869e40cd9056f571e07",
|
||||
"5cb363547ca077c806fc69bc8c2006831ab89e72fd778ac1a48fa810934e350e",
|
||||
"85ee928bb110fd64eae54a91fc8548883e7fc4c60a3c61b505c31cea2d295c86",
|
||||
"1ec3df7d10ee6fd5f0532ad4fe771e6befc28b0bed0250bf523695d6d49a8246",
|
||||
"de9db2fc07c866bd7b885fb41522b63d550d0ce2e8ac5e14464a41733c2319e6",
|
||||
"9a27136422a8f56768db29ba172a7ba26c3c7aa910324e78e5ab3a3268ac3674",
|
||||
"60213c315119bf9005cb533d1a5b403b4a13c59982fe7773d30fdd8f519f4205",
|
||||
"40eb61ef1812eb8a4d389599bf449fc86653b2c4986061b952f46fc049de53f4",
|
||||
"658ef0d8140162b5f04591be13b47456245f531208bbca3260b857ca09b803c5",
|
||||
"02270fa66255048d724894e2206b4e773cc6a7b6d17ca090cdc25f317d5f53b9",
|
||||
"2ec6a0147f419161f7198d05be5f93152d9ccc10672db0ea47ff1687c0f0dd15",
|
||||
"4be1d8ceb96eb80ef7ce30079ded31163272aeccff5c18fe3aaa32ea2f5bed9d",
|
||||
"04ecaf48f44de87243b17b4c71ebff00020738639336010fa57435a54b623798",
|
||||
"e313a9feb7cfd1d56ec87b1f1062ff9a80da498f7b761af4bef0cecd1b4c385b",
|
||||
"ede3748f971f22341f7f5844dc60fc03cdb30c7cc720ebe13ae588c17a78aa94",
|
||||
"d90c0faa70e39b7c0a8c55457ed6e6478a4e4bf3707b08104326a1ee8377c3ab",
|
||||
"c79ffd0bbc8d004cc542e212990df6498abddd3deb50fd00ed00a2ff690974d6",
|
||||
"35c37d88cf73a89c4124b0ee537347c37fdb47156c8b0ecc509efc58236ed3f0",
|
||||
"a99182f343ccf05e557ffa6df71f03688b2afcf314c59daa774fe78db6f47add",
|
||||
"01115397a78af8a4ae2727ca7a01843235b626bd3db80888d3dfd0020d4135e2",
|
||||
"4a55aced578470d2f7280096d7fe8095f294095fba4778d1977d6db9270472f0",
|
||||
"4624adf8a5633f65b213b8ca46b55cb0ee36c41495f39b1ae70cbd545779b1a0",
|
||||
"d72bcd5b57a9c47e7bd5e9a1103657d10beb7b6c6d41f2b2985bc3bd3cc74860",
|
||||
"48baadb9a46293c92f29e7617846171356a42c3b5d18d49a05a7e173993785f7",
|
||||
"3da927737af8cb0e1c77097e35c54158d18aabfb3051c45bcc7ddfe00b157b1f",
|
||||
"b4a24bfdb2cb802c8d48a3a18fbfe18622a767fe7eddfca57d4555550ccd1643",
|
||||
"c58f82ac7c49dcba1721a88358f07636c9df60d3fd383e5789b808dc57a1dc9d",
|
||||
"5e1f756eff5155df073d30f4452bdafc4adaf4f35960771bf2c1e30137fd7a79",
|
||||
"be4a332f289338d67bd4834eae3128c488a61d255e972da484b6252b67a46b89",
|
||||
"d496e4a36238d03a83d8b45cf33d9388aa7568a279b034d1cdd87b457356cc5b",
|
||||
"a1c5212730ccda34de393210e276bbd44720dda777bcfd602315a3eee582f7dc",
|
||||
"08914ec63f6ef7fe1d678937dc0f6178883440b26b4aca29fce79068947e8397",
|
||||
"49e2cd2bd9b974074d9814f93eed371620bd4ea5fbf97a625065704e8fb382d7",
|
||||
"047c194111818b48ce93a4b006e4a09b9a2650757a87357111796e11e847bf23",
|
||||
"5955b0baa8265341f35a6f24fdc79066ba3ca9c5354c69b6b37a9ef3a26be556",
|
||||
"d7c962f3ea1938c5267cca4072548acf3afcce4d438ed62027caa211a5f98e8b",
|
||||
"c8cfba67cb4ce7e291b35154a50476d9a5c6bbb5d6cbaaa5d2408547fea7b02b",
|
||||
"de8a940d8a69a64ce264d2ab7320662aef2e391c587cb2aae22a86718d5dffbb",
|
||||
"94176f1310b26e54d4de48f87b74aa0b60532f184a2268508dece86dd7f85d36",
|
||||
"9ce6ee3fca56c9256a69df404782301300a6e5e7f5a25a1f6d68c0e9e42584c9",
|
||||
"7c423c4a220c6ff43ab6432f92b166323c58ee77f8c096ba0b00d52d7bd507e8",
|
||||
"0b62b9c1ae4d4988720e8d41d980b334458189de0a3dd01699338d7b07c3894e",
|
||||
"64f45f6f75110624506c53716f2fc1d5fe5f88f82a5bc6a7459ce70eae56dbb3",
|
||||
"12ffbeb8e52fed161af4d8a015d1a5c45dcb8240e5c8933ce3a88ba2c58f97e8",
|
||||
"2ee6b7b96043c8ded9fb52f87cdd0d0580ca6f8cef183c8a656394a11c0aa393",
|
||||
"aaef26b1f5726258bf9ce305a3e54bca65cf68779f90f9d24287245c27362e27",
|
||||
"ef59588dce57c35d010bea4d209f44c62f0b7c7e65bc0226c0e4971934da9435",
|
||||
"0e606c2f6f8dcd579faf4739312bd7327ac7796fa44a81780fe0d66fc7761fb9",
|
||||
"2f307198afdbde5f95989a17e06ce1bb9ff36c441cf3b2248431534fe13bb9fe",
|
||||
"51418e6df23d450aaacc74ef2df53a6b1693727b70bda9ebc43acfc23d8fb5ea",
|
||||
"6e9e3ac46705ed80520695b924435b00d2b3079598bf7faca7fd1524be777e5e",
|
||||
"1e96241e2876aad29ce64f5d7e7fbb8db7265449df816c0d30a96633778c5cb6",
|
||||
"81788f00eb72696d811f946e65d2c96528c45590874a1defdd46651e9b79a3a1",
|
||||
"d9aa5a9f1df50e933d7105a5d72b5fe96bfbb9fd4b5b0eaa5e80af12e72d497a",
|
||||
"e1b6976a732d27fc5d6a96b6d3d0d1d5eaa6ec46bae4665f17e7a43aefc75280",
|
||||
"9151c75edcec1cc90aa2d2c240ff657b0eef3f5f1ec37418c8854b2493114f1d",
|
||||
"3e7c12d0132421f08ea0a390cfa325e422a6b35120fb2eb650f108a165237934",
|
||||
"1ee0e85c7d8a91089c03f37318cdc9127026bf789e3ce4b75046eaa3eebd3458",
|
||||
"4ae64a3ef66cad847409ce175bd5365c9097fd21647a05730ac6b45841add3c8",
|
||||
"f0ea0f334cf1d64678a6dab08c07e2f94f339e8389bd17ebc882b5c8b736cbf2",
|
||||
"da904db96060546ff69e28993ce8183766da9402ac10fae9fc1f1d67ebd83c90",
|
||||
"db11820615f7b5e47778c45d2e083e77f49b608b587dc09ec26f077aba07a242",
|
||||
"ff5c726a83bd785484de75bb03b421f9e8e382bf2740120a2fcf72326aa01c75",
|
||||
"f8643a7efd6304980db323303ab73a6fd4f4ee1047520d39d571580395b97f21",
|
||||
"8facf9737d07838aedf6030593bfb247d8c29fe8d9b18b2913408627a4424d7e",
|
||||
"f0672964aa6e4c7dd4768e18827023787386927f4db89fd661444979afb43c18",
|
||||
"6fd3649c8401f2704ed2be18518b870eb6bf2b9a6689d1b336f05bd8b49017f6",
|
||||
"ed172dac7de827493e0c0fdd8d3299333acb678e72ed499e0224b389cc1e0fba",
|
||||
"7f9a8a8cc8e34add11934a1a5882be5978a6d28405cb0a053ec5699a502b1cef",
|
||||
"6ca829ebd2a0a40994f68c1db7978ec274b45c46e9b351df869a2bfe0630bbd4",
|
||||
"0bbb017c437573a55db88258a9d9a01188bdd23bb6b26903b137814871661f47",
|
||||
"9a6358d2541f46b6d05b80fe25a2cb025fbe9e4b227a6275908d5ee31c948569",
|
||||
"a75d26c6d4ce944024f10e6d23e8b5b888d680120e15dc0e4fee8d8833ee0c6a",
|
||||
"1d43d33556699b42c124b46e41243abf48727fe488428056fdd174a3861c1e3c",
|
||||
"7b5bd3fecbaa093f005c4f806ea67846c0df6b04df7729925cb14724f6a8b582",
|
||||
"6bdf2b54f2f5ab90191261d33dee80fede75896994016422b28db8ba62327d82",
|
||||
"1a16181b250085a91ccecc118473fa2ab98515e894a7b63b347c24b5be560c7a",
|
||||
"22d24891755910b48ad632358c26245bdcc375abc41f7e2c9fb3c7773dbf4e22",
|
||||
"5b70c5d4a373d541619c944fcc3b61259550b0e9fba3eca16f0879e5845b43b9",
|
||||
"b78f9098c9d76987b7409e63426a8d49972bb4e75289576c680cf96513d44b6d",
|
||||
"916b53b8e85eb7e0a2a76d6fc8d2163430e7183ccb103d6705f54af4bb070907",
|
||||
"dc3d78f43110d2aa9df83c5485ec33663ad5452b8cdeb1aeeac9d6b1487fb781",
|
||||
"3975539ed5402cb9f5ab503584524dd141cc4296b666ec66d807f94f62b1c026",
|
||||
"bd1f97fd89183643423073f22733880616456ca41960699f18e868cb9ac35508",
|
||||
"90b468ff0f83460c3dd8cfe778c39d32c6bb1eeff9ac5de7804a4050d3b8073e",
|
||||
"0e886d49d88b82c9f8dbdd2f38a535992f35ab16629724d746394db3898235fa",
|
||||
"76c22e965242d1ca5614e829d9028dcad9c4b09393bcbdd318b0365557335fb9",
|
||||
"59b168488ec8629f820a1efd8fc5a0c2adec4253e61d6a2945a68a9a43be9035",
|
||||
"ff172b42854eaf2865caa985d2fb6283c5ab19574126623ffd615a761a5bce72",
|
||||
"cb46ac9ccc024ee74c96e3cf1c13a6949a432e855dfa881b6a307c0e6daac59e",
|
||||
"9971574924c0f413bf4c0f96bb9c2fbdfea8f475e33a8fb6f15fa40903b63444",
|
||||
"1a95567deb0f45a8941e2248f33286485984a5e9d86d16c37d42169ad864dc36",
|
||||
"205fc7f7ec7a83f0bc22d5269c91762cd00adc7428456d799be5a0cd76f08b0f",
|
||||
"849dd41ef59a722901b7a0deb2c1fd3c110a91a726120a0a119cb7a15cf98438",
|
||||
"a32880917c714612101af95e5c8d8eb5fb046fdcc68bae76c05b829b3fa73c2e",
|
||||
"70b38d6d510d13b359dffa910329952c620a4bce4ee7a8552b9bb3a14572394d",
|
||||
"ef257ab2f4226faa6ba288a6793f026609068effb866c18496a847e8b60b102d",
|
||||
"e5196ab42ff53c8352288bde6b6b7312cd6f39f7d21b556b0db178d8470d5790",
|
||||
"ca98f128bf085f2b718f2b3c12da7c4d98887cc94251a2b1705b637611bd83bb",
|
||||
"79508f0b93a49ec19c5cb05906ca1ba3d3db8ed4f9c6884873d0d7e3e985ea51",
|
||||
"9088be3f47f9debc63e928739f7163182b49eab044518b151f0b89f6b6aefdd0",
|
||||
"46b2782fd669b6288a4d7348cf6671360277ba4864cc69bce3497369ac2ec31e",
|
||||
"0fa5131557db67b430d516530be939ff25882adf68a076602f3dfad8c77c963a",
|
||||
"3404302cc097d5457244453a4c9990804201ee8161188df811bcb32404998c71",
|
||||
"856939710dbb90a8eeda875a31f9a52af759bd932b88e7b08df35414c54d4721",
|
||||
"72569573b9b41d0ac5ce17764a139c6b8b36ef3ca6d92cec625dbcdae758ba22",
|
||||
"9746da344e435a008d6acb4847211bb676376ecc76c825b5d44a28b89ceeb40e",
|
||||
"3eafded1595516f032e33ec975f4c9c3a1055d13aa5575cf8a801d6103fdbeb4",
|
||||
"e88a6d2daa863c0787cc523a2cab45c546fad788951b10d75e2b0954db24cca7",
|
||||
"38f531e67f88f66de44d3357c8e8f2db456160ca31dd2024c9562f6afd260278",
|
||||
};
|
||||
// block 685498 (13 key images in one transaction)
|
||||
static const char * const key_images_685498[] =
|
||||
{
|
||||
"749b7277aa21c70c417f255fb181c3a30b44277edf657eaaebf28a2709dd2a90",
|
||||
"5a9b3e1a87332d735cedaa2b5623a6a5e99d99f5a2887c8fc84293577e8bf25c",
|
||||
"bea438768445eb3650cf619bf6758e94035abfe0ccda91d4a58c582df143d835",
|
||||
"376e237ff4da5e5cbd6e1bba4b01412fa751f2959c0c57006589f382413df429",
|
||||
"14ac2f2e044f8635a3a42ecb46c575424073c1f6e5ed5e905f516d57f63184b5",
|
||||
"2d1d2ecb77b69a2901de00897d0509c1b7855a3b2f8eb1afe419008fc03cd15a",
|
||||
"ea01658f0972b77ae9112d525ec073e3ec5c3b98d5ad912d95ab2636354b70b6",
|
||||
"d3934864a46101d8c242415282e7fc9ee73ad16cd40355535d226ab45ecdb61a",
|
||||
"ee379b05c5d02432330ebd4ea9c4f1c87d14c388568d526a0f8a22649a14e453",
|
||||
"aeb7b842b410b13ca4af7a5ffd5ae6caddc8bfec653df1b945e478839a2e0057",
|
||||
"451806929d9f5c3a7f365472703871abadc25b2a5a2d75472a45e86cd76c610b",
|
||||
"272d9b9fcc9e253c08da9caf8233471150019582eaefef461c1f9ceff7e2c337",
|
||||
"633cdedeb3b96ec4f234c670254c6f721e0b368d00b48c6b26759db7d62cf52d",
|
||||
};
|
||||
|
||||
if (height() > 202612 && strcmp(CRYPTONOTE_NAME, "monero")==0)
|
||||
{
|
||||
for (const auto &kis: key_images_202612)
|
||||
{
|
||||
crypto::key_image ki;
|
||||
epee::string_tools::hex_to_pod(kis, ki);
|
||||
if (!has_key_image(ki))
|
||||
{
|
||||
LOG_PRINT_L1("Fixup: adding missing spent key " << ki);
|
||||
add_spent_key(ki);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (height() > 685498 && strcmp(CRYPTONOTE_NAME, "monero")==0)
|
||||
{
|
||||
for (const auto &kis: key_images_685498)
|
||||
{
|
||||
crypto::key_image ki;
|
||||
epee::string_tools::hex_to_pod(kis, ki);
|
||||
if (!has_key_image(ki))
|
||||
{
|
||||
LOG_PRINT_L1("Fixup: adding missing spent key " << ki);
|
||||
add_spent_key(ki);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
batch_stop();
|
||||
}
|
||||
|
||||
} // namespace cryptonote
|
||||
|
||||
@@ -137,7 +137,7 @@ struct txpool_tx_meta_t
|
||||
{
|
||||
crypto::hash max_used_block_id;
|
||||
crypto::hash last_failed_id;
|
||||
uint64_t blob_size;
|
||||
uint64_t weight;
|
||||
uint64_t fee;
|
||||
uint64_t max_used_block_height;
|
||||
uint64_t last_failed_height;
|
||||
@@ -358,15 +358,18 @@ private:
|
||||
* subclass of DB_EXCEPTION
|
||||
*
|
||||
* @param blk the block to be added
|
||||
* @param block_size the size of the block (transactions and all)
|
||||
* @param block_weight the weight of the block (transactions and all)
|
||||
* @param long_term_block_weight the long term block weight of the block (transactions and all)
|
||||
* @param cumulative_difficulty the accumulated difficulty after this block
|
||||
* @param coins_generated the number of coins generated total after this block
|
||||
* @param blk_hash the hash of the block
|
||||
*/
|
||||
virtual void add_block( const block& blk
|
||||
, const size_t& block_size
|
||||
, size_t block_weight
|
||||
, uint64_t long_term_block_weight
|
||||
, const difficulty_type& cumulative_difficulty
|
||||
, const uint64_t& coins_generated
|
||||
, uint64_t num_rct_outs
|
||||
, const crypto::hash& blk_hash
|
||||
) = 0;
|
||||
|
||||
@@ -375,7 +378,7 @@ private:
|
||||
*
|
||||
* The subclass implementing this will remove the block data from the top
|
||||
* block in the chain. The data to be removed is that which was added in
|
||||
* BlockchainDB::add_block(const block& blk, const size_t& block_size, const difficulty_type& cumulative_difficulty, const uint64_t& coins_generated, const crypto::hash& blk_hash)
|
||||
* BlockchainDB::add_block(const block& blk, size_t block_weight, uint64_t long_term_block_weight, const difficulty_type& cumulative_difficulty, const uint64_t& coins_generated, const crypto::hash& blk_hash)
|
||||
*
|
||||
* If any of this cannot be done, the subclass should throw the corresponding
|
||||
* subclass of DB_EXCEPTION
|
||||
@@ -399,9 +402,10 @@ private:
|
||||
* @param blk_hash the hash of the block containing the transaction
|
||||
* @param tx the transaction to be added
|
||||
* @param tx_hash the hash of the transaction
|
||||
* @param tx_prunable_hash the hash of the prunable part of the transaction
|
||||
* @return the transaction ID
|
||||
*/
|
||||
virtual uint64_t add_transaction_data(const crypto::hash& blk_hash, const transaction& tx, const crypto::hash& tx_hash) = 0;
|
||||
virtual uint64_t add_transaction_data(const crypto::hash& blk_hash, const transaction& tx, const crypto::hash& tx_hash, const crypto::hash& tx_prunable_hash) = 0;
|
||||
|
||||
/**
|
||||
* @brief remove data about a transaction
|
||||
@@ -527,8 +531,9 @@ protected:
|
||||
* @param blk_hash hash of the block which has the transaction
|
||||
* @param tx the transaction to add
|
||||
* @param tx_hash_ptr the hash of the transaction, if already calculated
|
||||
* @param tx_prunable_hash_ptr the hash of the prunable part of the transaction, if already calculated
|
||||
*/
|
||||
void add_transaction(const crypto::hash& blk_hash, const transaction& tx, const crypto::hash* tx_hash_ptr = NULL);
|
||||
void add_transaction(const crypto::hash& blk_hash, const transaction& tx, const crypto::hash* tx_hash_ptr = NULL, const crypto::hash* tx_prunable_hash_ptr = NULL);
|
||||
|
||||
mutable uint64_t time_tx_exists = 0; //!< a performance metric
|
||||
uint64_t time_commit1 = 0; //!< a performance metric
|
||||
@@ -653,6 +658,20 @@ public:
|
||||
*/
|
||||
virtual std::vector<std::string> get_filenames() const = 0;
|
||||
|
||||
/**
|
||||
* @brief remove file(s) storing the database
|
||||
*
|
||||
* This function is for resetting the database (for core tests, functional tests, etc).
|
||||
* The function reset() is not usable because it needs to open the database file first
|
||||
* which can fail if the existing database file is in an incompatible format.
|
||||
* As such, this function needs to be called before calling open().
|
||||
*
|
||||
* @param folder The path of the folder containing the database file(s) which must not end with slash '/'.
|
||||
*
|
||||
* @return true if the operation is succesfull
|
||||
*/
|
||||
virtual bool remove_data_file(const std::string& folder) const = 0;
|
||||
|
||||
// return the name of the folder the db's file(s) should reside in
|
||||
/**
|
||||
* @brief gets the name of the folder the BlockchainDB's file(s) should be in
|
||||
@@ -772,7 +791,8 @@ public:
|
||||
* subclass of DB_EXCEPTION
|
||||
*
|
||||
* @param blk the block to be added
|
||||
* @param block_size the size of the block (transactions and all)
|
||||
* @param block_weight the size of the block (transactions and all)
|
||||
* @param long_term_block_weight the long term weight of the block (transactions and all)
|
||||
* @param cumulative_difficulty the accumulated difficulty after this block
|
||||
* @param coins_generated the number of coins generated total after this block
|
||||
* @param txs the transactions in the block
|
||||
@@ -780,7 +800,8 @@ public:
|
||||
* @return the height of the chain post-addition
|
||||
*/
|
||||
virtual uint64_t add_block( const block& blk
|
||||
, const size_t& block_size
|
||||
, size_t block_weight
|
||||
, uint64_t long_term_block_weight
|
||||
, const difficulty_type& cumulative_difficulty
|
||||
, const uint64_t& coins_generated
|
||||
, const std::vector<transaction>& txs
|
||||
@@ -889,6 +910,20 @@ public:
|
||||
*/
|
||||
virtual uint64_t get_block_timestamp(const uint64_t& height) const = 0;
|
||||
|
||||
/**
|
||||
* @brief fetch a block's cumulative number of rct outputs
|
||||
*
|
||||
* The subclass should return the numer of rct outputs in the blockchain
|
||||
* up to the block with the given height (inclusive).
|
||||
*
|
||||
* If the block does not exist, the subclass should throw BLOCK_DNE
|
||||
*
|
||||
* @param height the height requested
|
||||
*
|
||||
* @return the cumulative number of rct outputs
|
||||
*/
|
||||
virtual std::vector<uint64_t> get_block_cumulative_rct_outputs(const std::vector<uint64_t> &heights) const = 0;
|
||||
|
||||
/**
|
||||
* @brief fetch the top block's timestamp
|
||||
*
|
||||
@@ -899,18 +934,18 @@ public:
|
||||
virtual uint64_t get_top_block_timestamp() const = 0;
|
||||
|
||||
/**
|
||||
* @brief fetch a block's size
|
||||
* @brief fetch a block's weight
|
||||
*
|
||||
* The subclass should return the size of the block with the
|
||||
* The subclass should return the weight of the block with the
|
||||
* given height.
|
||||
*
|
||||
* If the block does not exist, the subclass should throw BLOCK_DNE
|
||||
*
|
||||
* @param height the height requested
|
||||
*
|
||||
* @return the size
|
||||
* @return the weight
|
||||
*/
|
||||
virtual size_t get_block_size(const uint64_t& height) const = 0;
|
||||
virtual size_t get_block_weight(const uint64_t& height) const = 0;
|
||||
|
||||
/**
|
||||
* @brief fetch a block's cumulative difficulty
|
||||
@@ -954,6 +989,17 @@ public:
|
||||
*/
|
||||
virtual uint64_t get_block_already_generated_coins(const uint64_t& height) const = 0;
|
||||
|
||||
/**
|
||||
* @brief fetch a block's long term weight
|
||||
*
|
||||
* If the block does not exist, the subclass should throw BLOCK_DNE
|
||||
*
|
||||
* @param height the height requested
|
||||
*
|
||||
* @return the long term weight
|
||||
*/
|
||||
virtual uint64_t get_block_long_term_weight(const uint64_t& height) const = 0;
|
||||
|
||||
/**
|
||||
* @brief fetch a block's hash
|
||||
*
|
||||
@@ -1120,6 +1166,33 @@ public:
|
||||
*/
|
||||
virtual bool get_tx_blob(const crypto::hash& h, cryptonote::blobdata &tx) const = 0;
|
||||
|
||||
/**
|
||||
* @brief fetches the pruned transaction blob with the given hash
|
||||
*
|
||||
* The subclass should return the pruned transaction stored which has the given
|
||||
* hash.
|
||||
*
|
||||
* If the transaction does not exist, the subclass should return false.
|
||||
*
|
||||
* @param h the hash to look for
|
||||
*
|
||||
* @return true iff the transaction was found
|
||||
*/
|
||||
virtual bool get_pruned_tx_blob(const crypto::hash& h, cryptonote::blobdata &tx) const = 0;
|
||||
|
||||
/**
|
||||
* @brief fetches the prunable transaction hash
|
||||
*
|
||||
* The subclass should return the hash of the prunable transaction data.
|
||||
*
|
||||
* If the transaction hash does not exist, the subclass should return false.
|
||||
*
|
||||
* @param h the tx hash to look for
|
||||
*
|
||||
* @return true iff the transaction was found
|
||||
*/
|
||||
virtual bool get_prunable_tx_hash(const crypto::hash& tx_hash, crypto::hash &prunable_hash) const = 0;
|
||||
|
||||
/**
|
||||
* @brief fetches the total number of transactions ever
|
||||
*
|
||||
@@ -1203,23 +1276,6 @@ public:
|
||||
*/
|
||||
virtual output_data_t get_output_key(const uint64_t& amount, const uint64_t& index) = 0;
|
||||
|
||||
/**
|
||||
* @brief get some of an output's data
|
||||
*
|
||||
* The subclass should return the public key, unlock time, and block height
|
||||
* for the output with the given global index, collected in a struct.
|
||||
*
|
||||
* If the output cannot be found, the subclass should throw OUTPUT_DNE.
|
||||
*
|
||||
* If any of these parts cannot be found, but some are, the subclass
|
||||
* should throw DB_ERROR with a message stating as much.
|
||||
*
|
||||
* @param global_index the output's index (global)
|
||||
*
|
||||
* @return the requested output data
|
||||
*/
|
||||
virtual output_data_t get_output_key(const uint64_t& global_index) const = 0;
|
||||
|
||||
/**
|
||||
* @brief gets an output's tx hash and index
|
||||
*
|
||||
@@ -1427,10 +1483,11 @@ public:
|
||||
* not found. Current implementations simply return false.
|
||||
*
|
||||
* @param std::function fn the function to run
|
||||
* @param bool pruned whether to only get pruned tx data, or the whole
|
||||
*
|
||||
* @return false if the function returns false for any transaction, otherwise true
|
||||
*/
|
||||
virtual bool for_all_transactions(std::function<bool(const crypto::hash&, const cryptonote::transaction&)>) const = 0;
|
||||
virtual bool for_all_transactions(std::function<bool(const crypto::hash&, const cryptonote::transaction&)>, bool pruned) const = 0;
|
||||
|
||||
/**
|
||||
* @brief runs a function over all outputs stored
|
||||
@@ -1506,6 +1563,13 @@ public:
|
||||
*/
|
||||
virtual bool is_read_only() const = 0;
|
||||
|
||||
/**
|
||||
* @brief get disk space requirements
|
||||
*
|
||||
* @return the size required
|
||||
*/
|
||||
virtual uint64_t get_database_size() const = 0;
|
||||
|
||||
// TODO: this should perhaps be (or call) a series of functions which
|
||||
// progressively update through version updates
|
||||
/**
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -50,6 +50,9 @@ typedef struct mdb_txn_cursors
|
||||
MDB_cursor *m_txc_output_amounts;
|
||||
|
||||
MDB_cursor *m_txc_txs;
|
||||
MDB_cursor *m_txc_txs_pruned;
|
||||
MDB_cursor *m_txc_txs_prunable;
|
||||
MDB_cursor *m_txc_txs_prunable_hash;
|
||||
MDB_cursor *m_txc_tx_indices;
|
||||
MDB_cursor *m_txc_tx_outputs;
|
||||
|
||||
@@ -67,6 +70,9 @@ typedef struct mdb_txn_cursors
|
||||
#define m_cur_output_txs m_cursors->m_txc_output_txs
|
||||
#define m_cur_output_amounts m_cursors->m_txc_output_amounts
|
||||
#define m_cur_txs m_cursors->m_txc_txs
|
||||
#define m_cur_txs_pruned m_cursors->m_txc_txs_pruned
|
||||
#define m_cur_txs_prunable m_cursors->m_txc_txs_prunable
|
||||
#define m_cur_txs_prunable_hash m_cursors->m_txc_txs_prunable_hash
|
||||
#define m_cur_tx_indices m_cursors->m_txc_tx_indices
|
||||
#define m_cur_tx_outputs m_cursors->m_txc_tx_outputs
|
||||
#define m_cur_spent_keys m_cursors->m_txc_spent_keys
|
||||
@@ -83,6 +89,9 @@ typedef struct mdb_rflags
|
||||
bool m_rf_output_txs;
|
||||
bool m_rf_output_amounts;
|
||||
bool m_rf_txs;
|
||||
bool m_rf_txs_pruned;
|
||||
bool m_rf_txs_prunable;
|
||||
bool m_rf_txs_prunable_hash;
|
||||
bool m_rf_tx_indices;
|
||||
bool m_rf_tx_outputs;
|
||||
bool m_rf_spent_keys;
|
||||
@@ -157,7 +166,7 @@ struct mdb_txn_safe
|
||||
class BlockchainLMDB : public BlockchainDB
|
||||
{
|
||||
public:
|
||||
BlockchainLMDB(bool batch_transactions=false);
|
||||
BlockchainLMDB(bool batch_transactions=true);
|
||||
~BlockchainLMDB();
|
||||
|
||||
virtual void open(const std::string& filename, const int mdb_flags=0);
|
||||
@@ -172,6 +181,8 @@ public:
|
||||
|
||||
virtual std::vector<std::string> get_filenames() const;
|
||||
|
||||
virtual bool remove_data_file(const std::string& folder) const;
|
||||
|
||||
virtual std::string get_db_name() const;
|
||||
|
||||
virtual bool lock();
|
||||
@@ -188,11 +199,13 @@ public:
|
||||
|
||||
virtual cryptonote::blobdata get_block_blob_from_height(const uint64_t& height) const;
|
||||
|
||||
virtual std::vector<uint64_t> get_block_cumulative_rct_outputs(const std::vector<uint64_t> &heights) const;
|
||||
|
||||
virtual uint64_t get_block_timestamp(const uint64_t& height) const;
|
||||
|
||||
virtual uint64_t get_top_block_timestamp() const;
|
||||
|
||||
virtual size_t get_block_size(const uint64_t& height) const;
|
||||
virtual size_t get_block_weight(const uint64_t& height) const;
|
||||
|
||||
virtual difficulty_type get_block_cumulative_difficulty(const uint64_t& height) const;
|
||||
|
||||
@@ -200,6 +213,8 @@ public:
|
||||
|
||||
virtual uint64_t get_block_already_generated_coins(const uint64_t& height) const;
|
||||
|
||||
virtual uint64_t get_block_long_term_weight(const uint64_t& height) const;
|
||||
|
||||
virtual crypto::hash get_block_hash_from_height(const uint64_t& height) const;
|
||||
|
||||
virtual std::vector<block> get_blocks_range(const uint64_t& h1, const uint64_t& h2) const;
|
||||
@@ -218,6 +233,8 @@ public:
|
||||
virtual uint64_t get_tx_unlock_time(const crypto::hash& h) const;
|
||||
|
||||
virtual bool get_tx_blob(const crypto::hash& h, cryptonote::blobdata &tx) const;
|
||||
virtual bool get_pruned_tx_blob(const crypto::hash& h, cryptonote::blobdata &tx) const;
|
||||
virtual bool get_prunable_tx_hash(const crypto::hash& tx_hash, crypto::hash &prunable_hash) const;
|
||||
|
||||
virtual uint64_t get_tx_count() const;
|
||||
|
||||
@@ -228,7 +245,6 @@ public:
|
||||
virtual uint64_t get_num_outputs(const uint64_t& amount) const;
|
||||
|
||||
virtual output_data_t get_output_key(const uint64_t& amount, const uint64_t& index);
|
||||
virtual output_data_t get_output_key(const uint64_t& global_index) const;
|
||||
virtual void get_output_key(const uint64_t &amount, const std::vector<uint64_t> &offsets, std::vector<output_data_t> &outputs, bool allow_partial = false);
|
||||
|
||||
virtual tx_out_index get_output_tx_and_index_from_global(const uint64_t& index) const;
|
||||
@@ -254,12 +270,13 @@ public:
|
||||
|
||||
virtual bool for_all_key_images(std::function<bool(const crypto::key_image&)>) const;
|
||||
virtual bool for_blocks_range(const uint64_t& h1, const uint64_t& h2, std::function<bool(uint64_t, const crypto::hash&, const cryptonote::block&)>) const;
|
||||
virtual bool for_all_transactions(std::function<bool(const crypto::hash&, const cryptonote::transaction&)>) const;
|
||||
virtual bool for_all_transactions(std::function<bool(const crypto::hash&, const cryptonote::transaction&)>, bool pruned) const;
|
||||
virtual bool for_all_outputs(std::function<bool(uint64_t amount, const crypto::hash &tx_hash, uint64_t height, size_t tx_idx)> f) const;
|
||||
virtual bool for_all_outputs(uint64_t amount, const std::function<bool(uint64_t height)> &f) const;
|
||||
|
||||
virtual uint64_t add_block( const block& blk
|
||||
, const size_t& block_size
|
||||
, size_t block_weight
|
||||
, uint64_t long_term_block_weight
|
||||
, const difficulty_type& cumulative_difficulty
|
||||
, const uint64_t& coins_generated
|
||||
, const std::vector<transaction>& txs
|
||||
@@ -303,15 +320,17 @@ private:
|
||||
uint64_t get_estimated_batch_size(uint64_t batch_num_blocks, uint64_t batch_bytes) const;
|
||||
|
||||
virtual void add_block( const block& blk
|
||||
, const size_t& block_size
|
||||
, size_t block_weight
|
||||
, uint64_t long_term_block_weight
|
||||
, const difficulty_type& cumulative_difficulty
|
||||
, const uint64_t& coins_generated
|
||||
, uint64_t num_rct_outs
|
||||
, const crypto::hash& block_hash
|
||||
);
|
||||
|
||||
virtual void remove_block();
|
||||
|
||||
virtual uint64_t add_transaction_data(const crypto::hash& blk_hash, const transaction& tx, const crypto::hash& tx_hash);
|
||||
virtual uint64_t add_transaction_data(const crypto::hash& blk_hash, const transaction& tx, const crypto::hash& tx_hash, const crypto::hash& tx_prunable_hash);
|
||||
|
||||
virtual void remove_transaction_data(const crypto::hash& tx_hash, const transaction& tx);
|
||||
|
||||
@@ -364,6 +383,8 @@ private:
|
||||
|
||||
virtual bool is_read_only() const;
|
||||
|
||||
virtual uint64_t get_database_size() const;
|
||||
|
||||
// fix up anything that may be wrong due to past bugs
|
||||
virtual void fixup();
|
||||
|
||||
@@ -373,6 +394,15 @@ private:
|
||||
// migrate from DB version 0 to 1
|
||||
void migrate_0_1();
|
||||
|
||||
// migrate from DB version 1 to 2
|
||||
void migrate_1_2();
|
||||
|
||||
// migrate from DB version 2 to 3
|
||||
void migrate_2_3();
|
||||
|
||||
// migrate from DB version 3 to 4
|
||||
void migrate_3_4();
|
||||
|
||||
void cleanup_batch();
|
||||
|
||||
private:
|
||||
@@ -383,6 +413,9 @@ private:
|
||||
MDB_dbi m_block_info;
|
||||
|
||||
MDB_dbi m_txs;
|
||||
MDB_dbi m_txs_pruned;
|
||||
MDB_dbi m_txs_prunable;
|
||||
MDB_dbi m_txs_prunable_hash;
|
||||
MDB_dbi m_tx_indices;
|
||||
MDB_dbi m_tx_outputs;
|
||||
|
||||
@@ -423,7 +456,7 @@ private:
|
||||
#endif
|
||||
#endif
|
||||
|
||||
constexpr static float RESIZE_PERCENT = 0.8f;
|
||||
constexpr static float RESIZE_PERCENT = 0.9f;
|
||||
};
|
||||
|
||||
} // namespace cryptonote
|
||||
|
||||
152
src/blockchain_db/testdb.h
Normal file
152
src/blockchain_db/testdb.h
Normal file
@@ -0,0 +1,152 @@
|
||||
// Copyright (c) 2014-2018, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
#include "blockchain_db.h"
|
||||
|
||||
namespace cryptonote
|
||||
{
|
||||
|
||||
class BaseTestDB: public cryptonote::BlockchainDB {
|
||||
public:
|
||||
BaseTestDB() {}
|
||||
virtual void open(const std::string& filename, const int db_flags = 0) { }
|
||||
virtual void close() {}
|
||||
virtual void sync() {}
|
||||
virtual void safesyncmode(const bool onoff) {}
|
||||
virtual void reset() {}
|
||||
virtual std::vector<std::string> get_filenames() const { return std::vector<std::string>(); }
|
||||
virtual bool remove_data_file(const std::string& folder) const { return true; }
|
||||
virtual std::string get_db_name() const { return std::string(); }
|
||||
virtual bool lock() { return true; }
|
||||
virtual void unlock() { }
|
||||
virtual bool batch_start(uint64_t batch_num_blocks=0, uint64_t batch_bytes=0) { return true; }
|
||||
virtual void batch_stop() {}
|
||||
virtual void set_batch_transactions(bool) {}
|
||||
virtual void block_txn_start(bool readonly=false) {}
|
||||
virtual void block_txn_stop() {}
|
||||
virtual void block_txn_abort() {}
|
||||
virtual void drop_hard_fork_info() {}
|
||||
virtual bool block_exists(const crypto::hash& h, uint64_t *height) const { return false; }
|
||||
virtual cryptonote::blobdata get_block_blob_from_height(const uint64_t& height) const { return cryptonote::t_serializable_object_to_blob(get_block_from_height(height)); }
|
||||
virtual cryptonote::blobdata get_block_blob(const crypto::hash& h) const { return cryptonote::blobdata(); }
|
||||
virtual bool get_tx_blob(const crypto::hash& h, cryptonote::blobdata &tx) const { return false; }
|
||||
virtual bool get_pruned_tx_blob(const crypto::hash& h, cryptonote::blobdata &tx) const { return false; }
|
||||
virtual bool get_prunable_tx_blob(const crypto::hash& h, cryptonote::blobdata &tx) const { return false; }
|
||||
virtual bool get_prunable_tx_hash(const crypto::hash& tx_hash, crypto::hash &prunable_hash) const { return false; }
|
||||
virtual uint64_t get_block_height(const crypto::hash& h) const { return 0; }
|
||||
virtual cryptonote::block_header get_block_header(const crypto::hash& h) const { return cryptonote::block_header(); }
|
||||
virtual uint64_t get_block_timestamp(const uint64_t& height) const { return 0; }
|
||||
virtual std::vector<uint64_t> get_block_cumulative_rct_outputs(const std::vector<uint64_t> &heights) const { return {}; }
|
||||
virtual uint64_t get_top_block_timestamp() const { return 0; }
|
||||
virtual size_t get_block_weight(const uint64_t& height) const { return 128; }
|
||||
virtual cryptonote::difficulty_type get_block_cumulative_difficulty(const uint64_t& height) const { return 10; }
|
||||
virtual cryptonote::difficulty_type get_block_difficulty(const uint64_t& height) const { return 0; }
|
||||
virtual uint64_t get_block_already_generated_coins(const uint64_t& height) const { return 10000000000; }
|
||||
virtual uint64_t get_block_long_term_weight(const uint64_t& height) const { return 128; }
|
||||
virtual crypto::hash get_block_hash_from_height(const uint64_t& height) const { return crypto::hash(); }
|
||||
virtual std::vector<cryptonote::block> get_blocks_range(const uint64_t& h1, const uint64_t& h2) const { return std::vector<cryptonote::block>(); }
|
||||
virtual std::vector<crypto::hash> get_hashes_range(const uint64_t& h1, const uint64_t& h2) const { return std::vector<crypto::hash>(); }
|
||||
virtual crypto::hash top_block_hash() const { return crypto::hash(); }
|
||||
virtual cryptonote::block get_top_block() const { return cryptonote::block(); }
|
||||
virtual uint64_t height() const { return 1; }
|
||||
virtual bool tx_exists(const crypto::hash& h) const { return false; }
|
||||
virtual bool tx_exists(const crypto::hash& h, uint64_t& tx_index) const { return false; }
|
||||
virtual uint64_t get_tx_unlock_time(const crypto::hash& h) const { return 0; }
|
||||
virtual cryptonote::transaction get_tx(const crypto::hash& h) const { return cryptonote::transaction(); }
|
||||
virtual bool get_tx(const crypto::hash& h, cryptonote::transaction &tx) const { return false; }
|
||||
virtual uint64_t get_tx_count() const { return 0; }
|
||||
virtual std::vector<cryptonote::transaction> get_tx_list(const std::vector<crypto::hash>& hlist) const { return std::vector<cryptonote::transaction>(); }
|
||||
virtual uint64_t get_tx_block_height(const crypto::hash& h) const { return 0; }
|
||||
virtual uint64_t get_num_outputs(const uint64_t& amount) const { return 1; }
|
||||
virtual uint64_t get_indexing_base() const { return 0; }
|
||||
virtual cryptonote::output_data_t get_output_key(const uint64_t& amount, const uint64_t& index) { return cryptonote::output_data_t(); }
|
||||
virtual cryptonote::tx_out_index get_output_tx_and_index_from_global(const uint64_t& index) const { return cryptonote::tx_out_index(); }
|
||||
virtual cryptonote::tx_out_index get_output_tx_and_index(const uint64_t& amount, const uint64_t& index) const { return cryptonote::tx_out_index(); }
|
||||
virtual void get_output_tx_and_index(const uint64_t& amount, const std::vector<uint64_t> &offsets, std::vector<cryptonote::tx_out_index> &indices) const {}
|
||||
virtual void get_output_key(const uint64_t &amount, const std::vector<uint64_t> &offsets, std::vector<cryptonote::output_data_t> &outputs, bool allow_partial = false) {}
|
||||
virtual bool can_thread_bulk_indices() const { return false; }
|
||||
virtual std::vector<uint64_t> get_tx_output_indices(const crypto::hash& h) const { return std::vector<uint64_t>(); }
|
||||
virtual std::vector<uint64_t> get_tx_amount_output_indices(const uint64_t tx_index) const { return std::vector<uint64_t>(); }
|
||||
virtual bool has_key_image(const crypto::key_image& img) const { return false; }
|
||||
virtual void remove_block() { }
|
||||
virtual uint64_t add_transaction_data(const crypto::hash& blk_hash, const cryptonote::transaction& tx, const crypto::hash& tx_hash, const crypto::hash& tx_prunable_hash) {return 0;}
|
||||
virtual void remove_transaction_data(const crypto::hash& tx_hash, const cryptonote::transaction& tx) {}
|
||||
virtual uint64_t add_output(const crypto::hash& tx_hash, const cryptonote::tx_out& tx_output, const uint64_t& local_index, const uint64_t unlock_time, const rct::key *commitment) {return 0;}
|
||||
virtual void add_tx_amount_output_indices(const uint64_t tx_index, const std::vector<uint64_t>& amount_output_indices) {}
|
||||
virtual void add_spent_key(const crypto::key_image& k_image) {}
|
||||
virtual void remove_spent_key(const crypto::key_image& k_image) {}
|
||||
|
||||
virtual bool for_all_key_images(std::function<bool(const crypto::key_image&)>) const { return true; }
|
||||
virtual bool for_blocks_range(const uint64_t&, const uint64_t&, std::function<bool(uint64_t, const crypto::hash&, const cryptonote::block&)>) const { return true; }
|
||||
virtual bool for_all_transactions(std::function<bool(const crypto::hash&, const cryptonote::transaction&)>, bool pruned) const { return true; }
|
||||
virtual bool for_all_outputs(std::function<bool(uint64_t amount, const crypto::hash &tx_hash, uint64_t height, size_t tx_idx)> f) const { return true; }
|
||||
virtual bool for_all_outputs(uint64_t amount, const std::function<bool(uint64_t height)> &f) const { return true; }
|
||||
virtual bool is_read_only() const { return false; }
|
||||
virtual std::map<uint64_t, std::tuple<uint64_t, uint64_t, uint64_t>> get_output_histogram(const std::vector<uint64_t> &amounts, bool unlocked, uint64_t recent_cutoff, uint64_t min_count) const { return std::map<uint64_t, std::tuple<uint64_t, uint64_t, uint64_t>>(); }
|
||||
virtual bool get_output_distribution(uint64_t amount, uint64_t from_height, uint64_t to_height, std::vector<uint64_t> &distribution, uint64_t &base) const { return false; }
|
||||
|
||||
virtual void add_txpool_tx(const cryptonote::transaction &tx, const cryptonote::txpool_tx_meta_t& details) {}
|
||||
virtual void update_txpool_tx(const crypto::hash &txid, const cryptonote::txpool_tx_meta_t& details) {}
|
||||
virtual uint64_t get_txpool_tx_count(bool include_unrelayed_txes = true) const { return 0; }
|
||||
virtual bool txpool_has_tx(const crypto::hash &txid) const { return false; }
|
||||
virtual void remove_txpool_tx(const crypto::hash& txid) {}
|
||||
virtual bool get_txpool_tx_meta(const crypto::hash& txid, cryptonote::txpool_tx_meta_t &meta) const { return false; }
|
||||
virtual bool get_txpool_tx_blob(const crypto::hash& txid, cryptonote::blobdata &bd) const { return false; }
|
||||
virtual uint64_t get_database_size() const { return 0; }
|
||||
virtual cryptonote::blobdata get_txpool_tx_blob(const crypto::hash& txid) const { return ""; }
|
||||
virtual bool for_all_txpool_txes(std::function<bool(const crypto::hash&, const cryptonote::txpool_tx_meta_t&, const cryptonote::blobdata*)>, bool include_blob = false, bool include_unrelayed_txes = false) const { return false; }
|
||||
|
||||
virtual void add_block( const cryptonote::block& blk
|
||||
, size_t block_weight
|
||||
, uint64_t long_term_block_weight
|
||||
, const cryptonote::difficulty_type& cumulative_difficulty
|
||||
, const uint64_t& coins_generated
|
||||
, uint64_t num_rct_outs
|
||||
, const crypto::hash& blk_hash
|
||||
) { }
|
||||
virtual cryptonote::block get_block_from_height(const uint64_t& height) const { return cryptonote::block(); }
|
||||
virtual void set_hard_fork_version(uint64_t height, uint8_t version) {}
|
||||
virtual uint8_t get_hard_fork_version(uint64_t height) const { return 0; }
|
||||
virtual void check_hard_fork_info() {}
|
||||
|
||||
virtual uint32_t get_blockchain_pruning_seed() const { return 0; }
|
||||
virtual bool prune_blockchain(uint32_t pruning_seed = 0) { return true; }
|
||||
virtual bool update_pruning() { return true; }
|
||||
virtual bool check_pruning() { return true; }
|
||||
virtual void prune_outputs(uint64_t amount) {}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -32,6 +32,8 @@ if(PER_BLOCK_CHECKPOINT)
|
||||
add_custom_command(OUTPUT blocksdat.o MAIN_DEPENDENCY ../blocks/checkpoints.dat COMMAND cd ${CMAKE_CURRENT_SOURCE_DIR} && touch stub.c && ${CMAKE_C_COMPILER} --target=x86_64-apple-darwin11 -o stub.o -c stub.c COMMAND cd ${CMAKE_CURRENT_SOURCE_DIR} && ${CMAKE_LINKER} -r -sectcreate __DATA __blocks_dat ../blocks/checkpoints.dat -o ${CMAKE_CURRENT_BINARY_DIR}/blocksdat.o stub.o && rm -f stub.*)
|
||||
elseif(APPLE AND NOT DEPENDS)
|
||||
add_custom_command(OUTPUT blocksdat.o MAIN_DEPENDENCY ../blocks/checkpoints.dat COMMAND cd ${CMAKE_CURRENT_SOURCE_DIR} && touch stub.c && ${CMAKE_C_COMPILER} -o stub.o -c stub.c COMMAND cd ${CMAKE_CURRENT_SOURCE_DIR} && ${CMAKE_LINKER} ${LD_RAW_FLAGS} -r -sectcreate __DATA __blocks_dat ../blocks/checkpoints.dat -o ${CMAKE_CURRENT_BINARY_DIR}/blocksdat.o stub.o && rm -f stub.*)
|
||||
elseif(LINUX_32)
|
||||
add_custom_command(OUTPUT blocksdat.o MAIN_DEPENDENCY ../blocks/checkpoints.dat COMMAND cd ${CMAKE_CURRENT_SOURCE_DIR} && cp ../blocks/checkpoints.dat blocks.dat && ${CMAKE_LINKER} -m elf_i386 ${LD_RAW_FLAGS} -r -b binary -o ${CMAKE_CURRENT_BINARY_DIR}/blocksdat.o blocks.dat && rm -f blocks.dat)
|
||||
else()
|
||||
add_custom_command(OUTPUT blocksdat.o MAIN_DEPENDENCY ../blocks/checkpoints.dat COMMAND cd ${CMAKE_CURRENT_SOURCE_DIR} && cp ../blocks/checkpoints.dat blocks.dat && ${CMAKE_LINKER} ${LD_RAW_FLAGS} -r -b binary -o ${CMAKE_CURRENT_BINARY_DIR}/blocksdat.o blocks.dat && rm -f blocks.dat)
|
||||
endif()
|
||||
@@ -93,6 +95,28 @@ monero_private_headers(blockchain_usage
|
||||
|
||||
|
||||
|
||||
set(blockchain_ancestry_sources
|
||||
blockchain_ancestry.cpp
|
||||
)
|
||||
|
||||
set(blockchain_ancestry_private_headers)
|
||||
|
||||
monero_private_headers(blockchain_ancestry
|
||||
${blockchain_ancestry_private_headers})
|
||||
|
||||
|
||||
|
||||
set(blockchain_depth_sources
|
||||
blockchain_depth.cpp
|
||||
)
|
||||
|
||||
set(blockchain_depth_private_headers)
|
||||
|
||||
monero_private_headers(blockchain_depth
|
||||
${blockchain_depth_private_headers})
|
||||
|
||||
|
||||
|
||||
monero_add_executable(blockchain_import
|
||||
${blockchain_import_sources}
|
||||
${blockchain_import_private_headers}
|
||||
@@ -102,7 +126,6 @@ target_link_libraries(blockchain_import
|
||||
PRIVATE
|
||||
cryptonote_core
|
||||
blockchain_db
|
||||
p2p
|
||||
version
|
||||
epee
|
||||
${Boost_FILESYSTEM_LIBRARY}
|
||||
@@ -129,7 +152,6 @@ target_link_libraries(blockchain_export
|
||||
PRIVATE
|
||||
cryptonote_core
|
||||
blockchain_db
|
||||
p2p
|
||||
version
|
||||
epee
|
||||
${Boost_FILESYSTEM_LIBRARY}
|
||||
@@ -152,7 +174,6 @@ target_link_libraries(blockchain_blackball
|
||||
wallet
|
||||
cryptonote_core
|
||||
blockchain_db
|
||||
p2p
|
||||
version
|
||||
epee
|
||||
${Boost_FILESYSTEM_LIBRARY}
|
||||
@@ -163,7 +184,7 @@ target_link_libraries(blockchain_blackball
|
||||
|
||||
set_property(TARGET blockchain_blackball
|
||||
PROPERTY
|
||||
OUTPUT_NAME "wownero-blockchain-blackball")
|
||||
OUTPUT_NAME "wownero-blockchain-mark-spent-outputs")
|
||||
install(TARGETS blockchain_blackball DESTINATION bin)
|
||||
|
||||
|
||||
@@ -175,7 +196,6 @@ target_link_libraries(blockchain_usage
|
||||
PRIVATE
|
||||
cryptonote_core
|
||||
blockchain_db
|
||||
p2p
|
||||
version
|
||||
epee
|
||||
${Boost_FILESYSTEM_LIBRARY}
|
||||
@@ -189,3 +209,45 @@ set_property(TARGET blockchain_usage
|
||||
OUTPUT_NAME "wownero-blockchain-usage")
|
||||
install(TARGETS blockchain_usage DESTINATION bin)
|
||||
|
||||
monero_add_executable(blockchain_ancestry
|
||||
${blockchain_ancestry_sources}
|
||||
${blockchain_ancestry_private_headers})
|
||||
|
||||
target_link_libraries(blockchain_ancestry
|
||||
PRIVATE
|
||||
cryptonote_core
|
||||
blockchain_db
|
||||
version
|
||||
epee
|
||||
${Boost_FILESYSTEM_LIBRARY}
|
||||
${Boost_SYSTEM_LIBRARY}
|
||||
${Boost_THREAD_LIBRARY}
|
||||
${CMAKE_THREAD_LIBS_INIT}
|
||||
${EXTRA_LIBRARIES})
|
||||
|
||||
set_property(TARGET blockchain_ancestry
|
||||
PROPERTY
|
||||
OUTPUT_NAME "wownero-blockchain-ancestry")
|
||||
install(TARGETS blockchain_ancestry DESTINATION bin)
|
||||
|
||||
monero_add_executable(blockchain_depth
|
||||
${blockchain_depth_sources}
|
||||
${blockchain_depth_private_headers})
|
||||
|
||||
target_link_libraries(blockchain_depth
|
||||
PRIVATE
|
||||
cryptonote_core
|
||||
blockchain_db
|
||||
version
|
||||
epee
|
||||
${Boost_FILESYSTEM_LIBRARY}
|
||||
${Boost_SYSTEM_LIBRARY}
|
||||
${Boost_THREAD_LIBRARY}
|
||||
${CMAKE_THREAD_LIBS_INIT}
|
||||
${EXTRA_LIBRARIES})
|
||||
|
||||
set_property(TARGET blockchain_depth
|
||||
PROPERTY
|
||||
OUTPUT_NAME "wownero-blockchain-depth")
|
||||
install(TARGETS blockchain_depth DESTINATION bin)
|
||||
|
||||
|
||||
@@ -12,16 +12,16 @@ See also each utility's "--help" option.
|
||||
|
||||
### Export an existing blockchain database
|
||||
|
||||
`$ wownero-blockchain-export`
|
||||
`$ monero-blockchain-export`
|
||||
|
||||
This loads the existing blockchain and exports it to `$MONERO_DATA_DIR/export/blockchain.raw`
|
||||
|
||||
### Import the exported file
|
||||
|
||||
`$ wownero-blockchain-import`
|
||||
`$ monero-blockchain-import`
|
||||
|
||||
This imports blocks from `$MONERO_DATA_DIR/export/blockchain.raw` (exported using the
|
||||
`wownero-blockchain-export` tool as described above) into the current database.
|
||||
`monero-blockchain-export` tool as described above) into the current database.
|
||||
|
||||
Defaults: `--batch on`, `--batch size 20000`, `--verify on`
|
||||
|
||||
@@ -30,14 +30,14 @@ Batch size refers to number of blocks and can be adjusted for performance based
|
||||
Verification should only be turned off if importing from a trusted blockchain.
|
||||
|
||||
If you encounter an error like "resizing not supported in batch mode", you can just re-run
|
||||
the `wownero-blockchain-import` command again, and it will restart from where it left off.
|
||||
the `monero-blockchain-import` command again, and it will restart from where it left off.
|
||||
|
||||
```bash
|
||||
## use default settings to import blockchain.raw into database
|
||||
$ wownero-blockchain-import
|
||||
$ monero-blockchain-import
|
||||
|
||||
## fast import with large batch size, database mode "fastest", verification off
|
||||
$ wownero-blockchain-import --batch-size 20000 --database lmdb#fastest --verify off
|
||||
$ monero-blockchain-import --batch-size 20000 --database lmdb#fastest --verify off
|
||||
|
||||
```
|
||||
|
||||
@@ -80,9 +80,9 @@ LMDB flags (more than one may be specified):
|
||||
## Examples:
|
||||
|
||||
```
|
||||
$ wownero-blockchain-import --database lmdb#fastest
|
||||
$ monero-blockchain-import --database lmdb#fastest
|
||||
|
||||
$ wownero-blockchain-import --database lmdb#nosync
|
||||
$ monero-blockchain-import --database lmdb#nosync
|
||||
|
||||
$ wownero-blockchain-import --database lmdb#nosync,nometasync
|
||||
$ monero-blockchain-import --database lmdb#nosync,nometasync
|
||||
```
|
||||
|
||||
772
src/blockchain_utilities/blockchain_ancestry.cpp
Normal file
772
src/blockchain_utilities/blockchain_ancestry.cpp
Normal file
@@ -0,0 +1,772 @@
|
||||
// Copyright (c) 2014-2018, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <boost/range/adaptor/transformed.hpp>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/archive/portable_binary_iarchive.hpp>
|
||||
#include <boost/archive/portable_binary_oarchive.hpp>
|
||||
#include "common/unordered_containers_boost_serialization.h"
|
||||
#include "common/command_line.h"
|
||||
#include "common/varint.h"
|
||||
#include "cryptonote_basic/cryptonote_boost_serialization.h"
|
||||
#include "cryptonote_core/tx_pool.h"
|
||||
#include "cryptonote_core/cryptonote_core.h"
|
||||
#include "cryptonote_core/blockchain.h"
|
||||
#include "blockchain_db/blockchain_db.h"
|
||||
#include "blockchain_db/db_types.h"
|
||||
#include "version.h"
|
||||
|
||||
#undef MONERO_DEFAULT_LOG_CATEGORY
|
||||
#define MONERO_DEFAULT_LOG_CATEGORY "bcutil"
|
||||
|
||||
namespace po = boost::program_options;
|
||||
using namespace epee;
|
||||
using namespace cryptonote;
|
||||
|
||||
static bool stop_requested = false;
|
||||
|
||||
struct ancestor
|
||||
{
|
||||
uint64_t amount;
|
||||
uint64_t offset;
|
||||
|
||||
bool operator==(const ancestor &other) const { return amount == other.amount && offset == other.offset; }
|
||||
|
||||
template <typename t_archive> void serialize(t_archive &a, const unsigned int ver)
|
||||
{
|
||||
a & amount;
|
||||
a & offset;
|
||||
}
|
||||
};
|
||||
BOOST_CLASS_VERSION(ancestor, 0)
|
||||
|
||||
namespace std
|
||||
{
|
||||
template<> struct hash<ancestor>
|
||||
{
|
||||
size_t operator()(const ancestor &a) const
|
||||
{
|
||||
return a.amount ^ a.offset; // not that bad, since amount almost always have a high bit set, and offset doesn't
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
struct tx_data_t
|
||||
{
|
||||
std::vector<std::pair<uint64_t, std::vector<uint64_t>>> vin;
|
||||
std::vector<crypto::public_key> vout;
|
||||
bool coinbase;
|
||||
|
||||
tx_data_t(): coinbase(false) {}
|
||||
tx_data_t(const cryptonote::transaction &tx)
|
||||
{
|
||||
coinbase = tx.vin.size() == 1 && tx.vin[0].type() == typeid(cryptonote::txin_gen);
|
||||
if (!coinbase)
|
||||
{
|
||||
vin.reserve(tx.vin.size());
|
||||
for (size_t ring = 0; ring < tx.vin.size(); ++ring)
|
||||
{
|
||||
if (tx.vin[ring].type() == typeid(cryptonote::txin_to_key))
|
||||
{
|
||||
const cryptonote::txin_to_key &txin = boost::get<cryptonote::txin_to_key>(tx.vin[ring]);
|
||||
vin.push_back(std::make_pair(txin.amount, cryptonote::relative_output_offsets_to_absolute(txin.key_offsets)));
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_PRINT_L0("Bad vin type in txid " << get_transaction_hash(tx));
|
||||
throw std::runtime_error("Bad vin type");
|
||||
}
|
||||
}
|
||||
}
|
||||
vout.reserve(tx.vout.size());
|
||||
for (size_t out = 0; out < tx.vout.size(); ++out)
|
||||
{
|
||||
if (tx.vout[out].target.type() == typeid(cryptonote::txout_to_key))
|
||||
{
|
||||
const auto &txout = boost::get<cryptonote::txout_to_key>(tx.vout[out].target);
|
||||
vout.push_back(txout.key);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_PRINT_L0("Bad vout type in txid " << get_transaction_hash(tx));
|
||||
throw std::runtime_error("Bad vout type");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename t_archive> void serialize(t_archive &a, const unsigned int ver)
|
||||
{
|
||||
a & coinbase;
|
||||
a & vin;
|
||||
a & vout;
|
||||
}
|
||||
};
|
||||
|
||||
struct ancestry_state_t
|
||||
{
|
||||
uint64_t height;
|
||||
std::unordered_map<crypto::hash, std::unordered_set<ancestor>> ancestry;
|
||||
std::unordered_map<ancestor, crypto::hash> output_cache;
|
||||
std::unordered_map<crypto::hash, ::tx_data_t> tx_cache;
|
||||
std::vector<cryptonote::block> block_cache;
|
||||
|
||||
template <typename t_archive> void serialize(t_archive &a, const unsigned int ver)
|
||||
{
|
||||
a & height;
|
||||
a & ancestry;
|
||||
a & output_cache;
|
||||
if (ver < 1)
|
||||
{
|
||||
std::unordered_map<crypto::hash, cryptonote::transaction> old_tx_cache;
|
||||
a & old_tx_cache;
|
||||
for (const auto i: old_tx_cache)
|
||||
tx_cache.insert(std::make_pair(i.first, ::tx_data_t(i.second)));
|
||||
}
|
||||
else
|
||||
{
|
||||
a & tx_cache;
|
||||
}
|
||||
if (ver < 2)
|
||||
{
|
||||
std::unordered_map<uint64_t, cryptonote::block> old_block_cache;
|
||||
a & old_block_cache;
|
||||
block_cache.resize(old_block_cache.size());
|
||||
for (const auto i: old_block_cache)
|
||||
block_cache[i.first] = i.second;
|
||||
}
|
||||
else
|
||||
{
|
||||
a & block_cache;
|
||||
}
|
||||
}
|
||||
};
|
||||
BOOST_CLASS_VERSION(ancestry_state_t, 2)
|
||||
|
||||
static void add_ancestor(std::unordered_map<ancestor, unsigned int> &ancestry, uint64_t amount, uint64_t offset)
|
||||
{
|
||||
std::pair<std::unordered_map<ancestor, unsigned int>::iterator, bool> p = ancestry.insert(std::make_pair(ancestor{amount, offset}, 1));
|
||||
if (!p.second)
|
||||
{
|
||||
++p.first->second;
|
||||
}
|
||||
}
|
||||
|
||||
static size_t get_full_ancestry(const std::unordered_map<ancestor, unsigned int> &ancestry)
|
||||
{
|
||||
size_t count = 0;
|
||||
for (const auto &i: ancestry)
|
||||
count += i.second;
|
||||
return count;
|
||||
}
|
||||
|
||||
static size_t get_deduplicated_ancestry(const std::unordered_map<ancestor, unsigned int> &ancestry)
|
||||
{
|
||||
return ancestry.size();
|
||||
}
|
||||
|
||||
static void add_ancestry(std::unordered_map<crypto::hash, std::unordered_set<ancestor>> &ancestry, const crypto::hash &txid, const std::unordered_set<ancestor> &ancestors)
|
||||
{
|
||||
std::pair<std::unordered_map<crypto::hash, std::unordered_set<ancestor>>::iterator, bool> p = ancestry.insert(std::make_pair(txid, ancestors));
|
||||
if (!p.second)
|
||||
{
|
||||
for (const auto &e: ancestors)
|
||||
p.first->second.insert(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void add_ancestry(std::unordered_map<crypto::hash, std::unordered_set<ancestor>> &ancestry, const crypto::hash &txid, const ancestor &new_ancestor)
|
||||
{
|
||||
std::pair<std::unordered_map<crypto::hash, std::unordered_set<ancestor>>::iterator, bool> p = ancestry.insert(std::make_pair(txid, std::unordered_set<ancestor>()));
|
||||
p.first->second.insert(new_ancestor);
|
||||
}
|
||||
|
||||
static std::unordered_set<ancestor> get_ancestry(const std::unordered_map<crypto::hash, std::unordered_set<ancestor>> &ancestry, const crypto::hash &txid)
|
||||
{
|
||||
std::unordered_map<crypto::hash, std::unordered_set<ancestor>>::const_iterator i = ancestry.find(txid);
|
||||
if (i == ancestry.end())
|
||||
{
|
||||
//MERROR("txid ancestry not found: " << txid);
|
||||
//throw std::runtime_error("txid ancestry not found");
|
||||
return std::unordered_set<ancestor>();
|
||||
}
|
||||
return i->second;
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
TRY_ENTRY();
|
||||
|
||||
epee::string_tools::set_module_name_and_folder(argv[0]);
|
||||
|
||||
std::string default_db_type = "lmdb";
|
||||
|
||||
std::string available_dbs = cryptonote::blockchain_db_types(", ");
|
||||
available_dbs = "available: " + available_dbs;
|
||||
|
||||
uint32_t log_level = 0;
|
||||
|
||||
tools::on_startup();
|
||||
|
||||
boost::filesystem::path output_file_path;
|
||||
|
||||
po::options_description desc_cmd_only("Command line options");
|
||||
po::options_description desc_cmd_sett("Command line options and settings options");
|
||||
const command_line::arg_descriptor<std::string> arg_log_level = {"log-level", "0-4 or categories", ""};
|
||||
const command_line::arg_descriptor<std::string> arg_database = {
|
||||
"database", available_dbs.c_str(), default_db_type
|
||||
};
|
||||
const command_line::arg_descriptor<std::string> arg_txid = {"txid", "Get ancestry for this txid", ""};
|
||||
const command_line::arg_descriptor<uint64_t> arg_height = {"height", "Get ancestry for all txes at this height", 0};
|
||||
const command_line::arg_descriptor<bool> arg_all = {"all", "Include the whole chain", false};
|
||||
const command_line::arg_descriptor<bool> arg_cache_outputs = {"cache-outputs", "Cache outputs (memory hungry)", false};
|
||||
const command_line::arg_descriptor<bool> arg_cache_txes = {"cache-txes", "Cache txes (memory hungry)", false};
|
||||
const command_line::arg_descriptor<bool> arg_cache_blocks = {"cache-blocks", "Cache blocks (memory hungry)", false};
|
||||
const command_line::arg_descriptor<bool> arg_include_coinbase = {"include-coinbase", "Including coinbase tx", false};
|
||||
const command_line::arg_descriptor<bool> arg_show_cache_stats = {"show-cache-stats", "Show cache statistics", false};
|
||||
|
||||
command_line::add_arg(desc_cmd_sett, cryptonote::arg_data_dir);
|
||||
command_line::add_arg(desc_cmd_sett, cryptonote::arg_testnet_on);
|
||||
command_line::add_arg(desc_cmd_sett, cryptonote::arg_stagenet_on);
|
||||
command_line::add_arg(desc_cmd_sett, arg_log_level);
|
||||
command_line::add_arg(desc_cmd_sett, arg_database);
|
||||
command_line::add_arg(desc_cmd_sett, arg_txid);
|
||||
command_line::add_arg(desc_cmd_sett, arg_height);
|
||||
command_line::add_arg(desc_cmd_sett, arg_all);
|
||||
command_line::add_arg(desc_cmd_sett, arg_cache_outputs);
|
||||
command_line::add_arg(desc_cmd_sett, arg_cache_txes);
|
||||
command_line::add_arg(desc_cmd_sett, arg_cache_blocks);
|
||||
command_line::add_arg(desc_cmd_sett, arg_include_coinbase);
|
||||
command_line::add_arg(desc_cmd_sett, arg_show_cache_stats);
|
||||
command_line::add_arg(desc_cmd_only, command_line::arg_help);
|
||||
|
||||
po::options_description desc_options("Allowed options");
|
||||
desc_options.add(desc_cmd_only).add(desc_cmd_sett);
|
||||
|
||||
po::variables_map vm;
|
||||
bool r = command_line::handle_error_helper(desc_options, [&]()
|
||||
{
|
||||
auto parser = po::command_line_parser(argc, argv).options(desc_options);
|
||||
po::store(parser.run(), vm);
|
||||
po::notify(vm);
|
||||
return true;
|
||||
});
|
||||
if (! r)
|
||||
return 1;
|
||||
|
||||
if (command_line::get_arg(vm, command_line::arg_help))
|
||||
{
|
||||
std::cout << "Wownero '" << MONERO_RELEASE_NAME << "' (v" << MONERO_VERSION_FULL << ")" << ENDL << ENDL;
|
||||
std::cout << desc_options << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
mlog_configure(mlog_get_default_log_path("wownero-blockchain-ancestry.log"), true);
|
||||
if (!command_line::is_arg_defaulted(vm, arg_log_level))
|
||||
mlog_set_log(command_line::get_arg(vm, arg_log_level).c_str());
|
||||
else
|
||||
mlog_set_log(std::string(std::to_string(log_level) + ",bcutil:INFO").c_str());
|
||||
|
||||
LOG_PRINT_L0("Starting...");
|
||||
|
||||
std::string opt_data_dir = command_line::get_arg(vm, cryptonote::arg_data_dir);
|
||||
bool opt_testnet = command_line::get_arg(vm, cryptonote::arg_testnet_on);
|
||||
bool opt_stagenet = command_line::get_arg(vm, cryptonote::arg_stagenet_on);
|
||||
network_type net_type = opt_testnet ? TESTNET : opt_stagenet ? STAGENET : MAINNET;
|
||||
std::string opt_txid_string = command_line::get_arg(vm, arg_txid);
|
||||
uint64_t opt_height = command_line::get_arg(vm, arg_height);
|
||||
bool opt_all = command_line::get_arg(vm, arg_all);
|
||||
bool opt_cache_outputs = command_line::get_arg(vm, arg_cache_outputs);
|
||||
bool opt_cache_txes = command_line::get_arg(vm, arg_cache_txes);
|
||||
bool opt_cache_blocks = command_line::get_arg(vm, arg_cache_blocks);
|
||||
bool opt_include_coinbase = command_line::get_arg(vm, arg_include_coinbase);
|
||||
bool opt_show_cache_stats = command_line::get_arg(vm, arg_show_cache_stats);
|
||||
|
||||
if ((!opt_txid_string.empty()) + !!opt_height + !!opt_all > 1)
|
||||
{
|
||||
std::cerr << "Only one of --txid, --height and --all can be given" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
crypto::hash opt_txid = crypto::null_hash;
|
||||
if (!opt_txid_string.empty())
|
||||
{
|
||||
if (!epee::string_tools::hex_to_pod(opt_txid_string, opt_txid))
|
||||
{
|
||||
std::cerr << "Invalid txid" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
std::string db_type = command_line::get_arg(vm, arg_database);
|
||||
if (!cryptonote::blockchain_valid_db_type(db_type))
|
||||
{
|
||||
std::cerr << "Invalid database type: " << db_type << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// If we wanted to use the memory pool, we would set up a fake_core.
|
||||
|
||||
// Use Blockchain instead of lower-level BlockchainDB for two reasons:
|
||||
// 1. Blockchain has the init() method for easy setup
|
||||
// 2. exporter needs to use get_current_blockchain_height(), get_block_id_by_height(), get_block_by_hash()
|
||||
//
|
||||
// cannot match blockchain_storage setup above with just one line,
|
||||
// e.g.
|
||||
// Blockchain* core_storage = new Blockchain(NULL);
|
||||
// because unlike blockchain_storage constructor, which takes a pointer to
|
||||
// tx_memory_pool, Blockchain's constructor takes tx_memory_pool object.
|
||||
LOG_PRINT_L0("Initializing source blockchain (BlockchainDB)");
|
||||
std::unique_ptr<Blockchain> core_storage;
|
||||
tx_memory_pool m_mempool(*core_storage);
|
||||
core_storage.reset(new Blockchain(m_mempool));
|
||||
BlockchainDB *db = new_db(db_type);
|
||||
if (db == NULL)
|
||||
{
|
||||
LOG_ERROR("Attempted to use non-existent database type: " << db_type);
|
||||
throw std::runtime_error("Attempting to use non-existent database type");
|
||||
}
|
||||
LOG_PRINT_L0("database: " << db_type);
|
||||
|
||||
const std::string filename = (boost::filesystem::path(opt_data_dir) / db->get_db_name()).string();
|
||||
LOG_PRINT_L0("Loading blockchain from folder " << filename << " ...");
|
||||
|
||||
try
|
||||
{
|
||||
db->open(filename, DBF_RDONLY);
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
LOG_PRINT_L0("Error opening database: " << e.what());
|
||||
return 1;
|
||||
}
|
||||
r = core_storage->init(db, net_type);
|
||||
|
||||
CHECK_AND_ASSERT_MES(r, 1, "Failed to initialize source blockchain storage");
|
||||
LOG_PRINT_L0("Source blockchain storage initialized OK");
|
||||
|
||||
std::vector<crypto::hash> start_txids;
|
||||
|
||||
// forward method
|
||||
if (opt_all)
|
||||
{
|
||||
uint64_t cached_txes = 0, cached_blocks = 0, cached_outputs = 0, total_txes = 0, total_blocks = 0, total_outputs = 0;
|
||||
ancestry_state_t state;
|
||||
|
||||
const std::string state_file_path = (boost::filesystem::path(opt_data_dir) / "ancestry-state.bin").string();
|
||||
LOG_PRINT_L0("Loading state data from " << state_file_path);
|
||||
std::ifstream state_data_in;
|
||||
state_data_in.open(state_file_path, std::ios_base::binary | std::ios_base::in);
|
||||
if (!state_data_in.fail())
|
||||
{
|
||||
try
|
||||
{
|
||||
boost::archive::portable_binary_iarchive a(state_data_in);
|
||||
a >> state;
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
MERROR("Failed to load state data from " << state_file_path << ", restarting from scratch");
|
||||
state = ancestry_state_t();
|
||||
}
|
||||
state_data_in.close();
|
||||
}
|
||||
|
||||
tools::signal_handler::install([](int type) {
|
||||
stop_requested = true;
|
||||
});
|
||||
|
||||
MINFO("Starting from height " << state.height);
|
||||
const uint64_t db_height = db->height();
|
||||
state.block_cache.reserve(db_height);
|
||||
for (uint64_t h = state.height; h < db_height; ++h)
|
||||
{
|
||||
size_t block_ancestry_size = 0;
|
||||
const crypto::hash block_hash = db->get_block_hash_from_height(h);
|
||||
const cryptonote::blobdata bd = db->get_block_blob(block_hash);
|
||||
++total_blocks;
|
||||
cryptonote::block b;
|
||||
if (!cryptonote::parse_and_validate_block_from_blob(bd, b))
|
||||
{
|
||||
LOG_PRINT_L0("Bad block from db");
|
||||
return 1;
|
||||
}
|
||||
if (opt_cache_blocks)
|
||||
{
|
||||
state.block_cache.resize(h + 1);
|
||||
state.block_cache[h] = b;
|
||||
}
|
||||
std::vector<crypto::hash> txids;
|
||||
txids.reserve(1 + b.tx_hashes.size());
|
||||
if (opt_include_coinbase)
|
||||
txids.push_back(cryptonote::get_transaction_hash(b.miner_tx));
|
||||
for (const auto &h: b.tx_hashes)
|
||||
txids.push_back(h);
|
||||
for (const crypto::hash &txid: txids)
|
||||
{
|
||||
printf("%lu/%lu \r", (unsigned long)h, (unsigned long)db_height);
|
||||
fflush(stdout);
|
||||
::tx_data_t tx_data;
|
||||
std::unordered_map<crypto::hash, ::tx_data_t>::const_iterator i = state.tx_cache.find(txid);
|
||||
++total_txes;
|
||||
if (i != state.tx_cache.end())
|
||||
{
|
||||
++cached_txes;
|
||||
tx_data = i->second;
|
||||
}
|
||||
else
|
||||
{
|
||||
cryptonote::blobdata bd;
|
||||
if (!db->get_pruned_tx_blob(txid, bd))
|
||||
{
|
||||
LOG_PRINT_L0("Failed to get txid " << txid << " from db");
|
||||
return 1;
|
||||
}
|
||||
cryptonote::transaction tx;
|
||||
if (!cryptonote::parse_and_validate_tx_base_from_blob(bd, tx))
|
||||
{
|
||||
LOG_PRINT_L0("Bad tx: " << txid);
|
||||
return 1;
|
||||
}
|
||||
tx_data = ::tx_data_t(tx);
|
||||
if (opt_cache_txes)
|
||||
state.tx_cache.insert(std::make_pair(txid, tx_data));
|
||||
}
|
||||
if (tx_data.coinbase)
|
||||
{
|
||||
add_ancestry(state.ancestry, txid, std::unordered_set<ancestor>());
|
||||
}
|
||||
else
|
||||
{
|
||||
for (size_t ring = 0; ring < tx_data.vin.size(); ++ring)
|
||||
{
|
||||
if (1)
|
||||
{
|
||||
const uint64_t amount = tx_data.vin[ring].first;
|
||||
const std::vector<uint64_t> &absolute_offsets = tx_data.vin[ring].second;
|
||||
for (uint64_t offset: absolute_offsets)
|
||||
{
|
||||
const output_data_t od = db->get_output_key(amount, offset);
|
||||
add_ancestry(state.ancestry, txid, ancestor{amount, offset});
|
||||
cryptonote::block b;
|
||||
++total_blocks;
|
||||
if (state.block_cache.size() > od.height && !state.block_cache[od.height].miner_tx.vin.empty())
|
||||
{
|
||||
++cached_blocks;
|
||||
b = state.block_cache[od.height];
|
||||
}
|
||||
else
|
||||
{
|
||||
const crypto::hash block_hash = db->get_block_hash_from_height(od.height);
|
||||
cryptonote::blobdata bd = db->get_block_blob(block_hash);
|
||||
if (!cryptonote::parse_and_validate_block_from_blob(bd, b))
|
||||
{
|
||||
LOG_PRINT_L0("Bad block from db");
|
||||
return 1;
|
||||
}
|
||||
if (opt_cache_blocks)
|
||||
{
|
||||
state.block_cache.resize(od.height + 1);
|
||||
state.block_cache[od.height] = b;
|
||||
}
|
||||
}
|
||||
// find the tx which created this output
|
||||
bool found = false;
|
||||
std::unordered_map<ancestor, crypto::hash>::const_iterator i = state.output_cache.find({amount, offset});
|
||||
++total_outputs;
|
||||
if (i != state.output_cache.end())
|
||||
{
|
||||
++cached_outputs;
|
||||
add_ancestry(state.ancestry, txid, get_ancestry(state.ancestry, i->second));
|
||||
found = true;
|
||||
}
|
||||
else for (size_t out = 0; out < b.miner_tx.vout.size(); ++out)
|
||||
{
|
||||
if (b.miner_tx.vout[out].target.type() == typeid(cryptonote::txout_to_key))
|
||||
{
|
||||
const auto &txout = boost::get<cryptonote::txout_to_key>(b.miner_tx.vout[out].target);
|
||||
if (txout.key == od.pubkey)
|
||||
{
|
||||
found = true;
|
||||
add_ancestry(state.ancestry, txid, get_ancestry(state.ancestry, cryptonote::get_transaction_hash(b.miner_tx)));
|
||||
if (opt_cache_outputs)
|
||||
state.output_cache.insert(std::make_pair(ancestor{amount, offset}, cryptonote::get_transaction_hash(b.miner_tx)));
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_PRINT_L0("Bad vout type in txid " << cryptonote::get_transaction_hash(b.miner_tx));
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
for (const crypto::hash &block_txid: b.tx_hashes)
|
||||
{
|
||||
if (found)
|
||||
break;
|
||||
::tx_data_t tx_data2;
|
||||
std::unordered_map<crypto::hash, ::tx_data_t>::const_iterator i = state.tx_cache.find(block_txid);
|
||||
++total_txes;
|
||||
if (i != state.tx_cache.end())
|
||||
{
|
||||
++cached_txes;
|
||||
tx_data2 = i->second;
|
||||
}
|
||||
else
|
||||
{
|
||||
cryptonote::blobdata bd;
|
||||
if (!db->get_pruned_tx_blob(block_txid, bd))
|
||||
{
|
||||
LOG_PRINT_L0("Failed to get txid " << block_txid << " from db");
|
||||
return 1;
|
||||
}
|
||||
cryptonote::transaction tx;
|
||||
if (!cryptonote::parse_and_validate_tx_base_from_blob(bd, tx))
|
||||
{
|
||||
LOG_PRINT_L0("Bad tx: " << block_txid);
|
||||
return 1;
|
||||
}
|
||||
tx_data2 = ::tx_data_t(tx);
|
||||
if (opt_cache_txes)
|
||||
state.tx_cache.insert(std::make_pair(block_txid, tx_data2));
|
||||
}
|
||||
for (size_t out = 0; out < tx_data2.vout.size(); ++out)
|
||||
{
|
||||
if (tx_data2.vout[out] == od.pubkey)
|
||||
{
|
||||
found = true;
|
||||
add_ancestry(state.ancestry, txid, get_ancestry(state.ancestry, block_txid));
|
||||
if (opt_cache_outputs)
|
||||
state.output_cache.insert(std::make_pair(ancestor{amount, offset}, block_txid));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
{
|
||||
LOG_PRINT_L0("Output originating transaction not found");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
const size_t ancestry_size = get_ancestry(state.ancestry, txid).size();
|
||||
block_ancestry_size += ancestry_size;
|
||||
MINFO(txid << ": " << ancestry_size);
|
||||
}
|
||||
if (!txids.empty())
|
||||
{
|
||||
std::string stats_msg;
|
||||
if (opt_show_cache_stats)
|
||||
stats_msg = std::string(", cache: txes ") + std::to_string(cached_txes*100./total_txes)
|
||||
+ ", blocks " + std::to_string(cached_blocks*100./total_blocks) + ", outputs "
|
||||
+ std::to_string(cached_outputs*100./total_outputs);
|
||||
MINFO("Height " << h << ": " << (block_ancestry_size / txids.size()) << " average over " << txids.size() << stats_msg);
|
||||
}
|
||||
state.height = h;
|
||||
if (stop_requested)
|
||||
break;
|
||||
}
|
||||
|
||||
LOG_PRINT_L0("Saving state data to " << state_file_path);
|
||||
std::ofstream state_data_out;
|
||||
state_data_out.open(state_file_path, std::ios_base::binary | std::ios_base::out | std::ios::trunc);
|
||||
if (!state_data_out.fail())
|
||||
{
|
||||
try
|
||||
{
|
||||
boost::archive::portable_binary_oarchive a(state_data_out);
|
||||
a << state;
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
MERROR("Failed to save state data to " << state_file_path);
|
||||
}
|
||||
state_data_out.close();
|
||||
}
|
||||
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (!opt_txid_string.empty())
|
||||
{
|
||||
start_txids.push_back(opt_txid);
|
||||
}
|
||||
else
|
||||
{
|
||||
const crypto::hash block_hash = db->get_block_hash_from_height(opt_height);
|
||||
const cryptonote::blobdata bd = db->get_block_blob(block_hash);
|
||||
cryptonote::block b;
|
||||
if (!cryptonote::parse_and_validate_block_from_blob(bd, b))
|
||||
{
|
||||
LOG_PRINT_L0("Bad block from db");
|
||||
return 1;
|
||||
}
|
||||
for (const crypto::hash &txid: b.tx_hashes)
|
||||
start_txids.push_back(txid);
|
||||
}
|
||||
|
||||
if (start_txids.empty())
|
||||
{
|
||||
LOG_PRINT_L0("No transaction(s) to check");
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (const crypto::hash &start_txid: start_txids)
|
||||
{
|
||||
LOG_PRINT_L0("Checking ancestry for txid " << start_txid);
|
||||
|
||||
std::unordered_map<ancestor, unsigned int> ancestry;
|
||||
|
||||
std::list<crypto::hash> txids;
|
||||
txids.push_back(start_txid);
|
||||
while (!txids.empty())
|
||||
{
|
||||
const crypto::hash txid = txids.front();
|
||||
txids.pop_front();
|
||||
|
||||
cryptonote::blobdata bd;
|
||||
if (!db->get_pruned_tx_blob(txid, bd))
|
||||
{
|
||||
LOG_PRINT_L0("Failed to get txid " << txid << " from db");
|
||||
return 1;
|
||||
}
|
||||
cryptonote::transaction tx;
|
||||
if (!cryptonote::parse_and_validate_tx_base_from_blob(bd, tx))
|
||||
{
|
||||
LOG_PRINT_L0("Bad tx: " << txid);
|
||||
return 1;
|
||||
}
|
||||
const bool coinbase = tx.vin.size() == 1 && tx.vin[0].type() == typeid(cryptonote::txin_gen);
|
||||
if (coinbase)
|
||||
continue;
|
||||
|
||||
for (size_t ring = 0; ring < tx.vin.size(); ++ring)
|
||||
{
|
||||
if (tx.vin[ring].type() == typeid(cryptonote::txin_to_key))
|
||||
{
|
||||
const cryptonote::txin_to_key &txin = boost::get<cryptonote::txin_to_key>(tx.vin[ring]);
|
||||
const uint64_t amount = txin.amount;
|
||||
auto absolute_offsets = cryptonote::relative_output_offsets_to_absolute(txin.key_offsets);
|
||||
for (uint64_t offset: absolute_offsets)
|
||||
{
|
||||
add_ancestor(ancestry, amount, offset);
|
||||
const output_data_t od = db->get_output_key(amount, offset);
|
||||
const crypto::hash block_hash = db->get_block_hash_from_height(od.height);
|
||||
bd = db->get_block_blob(block_hash);
|
||||
cryptonote::block b;
|
||||
if (!cryptonote::parse_and_validate_block_from_blob(bd, b))
|
||||
{
|
||||
LOG_PRINT_L0("Bad block from db");
|
||||
return 1;
|
||||
}
|
||||
// find the tx which created this output
|
||||
bool found = false;
|
||||
for (size_t out = 0; out < b.miner_tx.vout.size(); ++out)
|
||||
{
|
||||
if (b.miner_tx.vout[out].target.type() == typeid(cryptonote::txout_to_key))
|
||||
{
|
||||
const auto &txout = boost::get<cryptonote::txout_to_key>(b.miner_tx.vout[out].target);
|
||||
if (txout.key == od.pubkey)
|
||||
{
|
||||
found = true;
|
||||
txids.push_back(cryptonote::get_transaction_hash(b.miner_tx));
|
||||
MDEBUG("adding txid: " << cryptonote::get_transaction_hash(b.miner_tx));
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_PRINT_L0("Bad vout type in txid " << cryptonote::get_transaction_hash(b.miner_tx));
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
for (const crypto::hash &block_txid: b.tx_hashes)
|
||||
{
|
||||
if (found)
|
||||
break;
|
||||
if (!db->get_pruned_tx_blob(block_txid, bd))
|
||||
{
|
||||
LOG_PRINT_L0("Failed to get txid " << block_txid << " from db");
|
||||
return 1;
|
||||
}
|
||||
cryptonote::transaction tx2;
|
||||
if (!cryptonote::parse_and_validate_tx_base_from_blob(bd, tx2))
|
||||
{
|
||||
LOG_PRINT_L0("Bad tx: " << block_txid);
|
||||
return 1;
|
||||
}
|
||||
for (size_t out = 0; out < tx2.vout.size(); ++out)
|
||||
{
|
||||
if (tx2.vout[out].target.type() == typeid(cryptonote::txout_to_key))
|
||||
{
|
||||
const auto &txout = boost::get<cryptonote::txout_to_key>(tx2.vout[out].target);
|
||||
if (txout.key == od.pubkey)
|
||||
{
|
||||
found = true;
|
||||
txids.push_back(block_txid);
|
||||
MDEBUG("adding txid: " << block_txid);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_PRINT_L0("Bad vout type in txid " << block_txid);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
{
|
||||
LOG_PRINT_L0("Output originating transaction not found");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_PRINT_L0("Bad vin type in txid " << txid);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MINFO("Ancestry for " << start_txid << ": " << get_deduplicated_ancestry(ancestry) << " / " << get_full_ancestry(ancestry));
|
||||
for (const auto &i: ancestry)
|
||||
{
|
||||
MINFO(cryptonote::print_money(i.first.amount) << "/" << i.first.offset << ": " << i.second);
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
core_storage->deinit();
|
||||
return 0;
|
||||
|
||||
CATCH_ENTRY("Depth query error", 1);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
351
src/blockchain_utilities/blockchain_depth.cpp
Normal file
351
src/blockchain_utilities/blockchain_depth.cpp
Normal file
@@ -0,0 +1,351 @@
|
||||
// Copyright (c) 2014-2018, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include <boost/range/adaptor/transformed.hpp>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include "common/command_line.h"
|
||||
#include "common/varint.h"
|
||||
#include "cryptonote_core/tx_pool.h"
|
||||
#include "cryptonote_core/cryptonote_core.h"
|
||||
#include "cryptonote_core/blockchain.h"
|
||||
#include "blockchain_db/blockchain_db.h"
|
||||
#include "blockchain_db/db_types.h"
|
||||
#include "version.h"
|
||||
|
||||
#undef MONERO_DEFAULT_LOG_CATEGORY
|
||||
#define MONERO_DEFAULT_LOG_CATEGORY "bcutil"
|
||||
|
||||
namespace po = boost::program_options;
|
||||
using namespace epee;
|
||||
using namespace cryptonote;
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
TRY_ENTRY();
|
||||
|
||||
epee::string_tools::set_module_name_and_folder(argv[0]);
|
||||
|
||||
std::string default_db_type = "lmdb";
|
||||
|
||||
std::string available_dbs = cryptonote::blockchain_db_types(", ");
|
||||
available_dbs = "available: " + available_dbs;
|
||||
|
||||
uint32_t log_level = 0;
|
||||
|
||||
tools::on_startup();
|
||||
|
||||
boost::filesystem::path output_file_path;
|
||||
|
||||
po::options_description desc_cmd_only("Command line options");
|
||||
po::options_description desc_cmd_sett("Command line options and settings options");
|
||||
const command_line::arg_descriptor<std::string> arg_log_level = {"log-level", "0-4 or categories", ""};
|
||||
const command_line::arg_descriptor<std::string> arg_database = {
|
||||
"database", available_dbs.c_str(), default_db_type
|
||||
};
|
||||
const command_line::arg_descriptor<std::string> arg_txid = {"txid", "Get min depth for this txid", ""};
|
||||
const command_line::arg_descriptor<uint64_t> arg_height = {"height", "Get min depth for all txes at this height", 0};
|
||||
const command_line::arg_descriptor<bool> arg_include_coinbase = {"include-coinbase", "Include coinbase in the average", false};
|
||||
|
||||
command_line::add_arg(desc_cmd_sett, cryptonote::arg_data_dir);
|
||||
command_line::add_arg(desc_cmd_sett, cryptonote::arg_testnet_on);
|
||||
command_line::add_arg(desc_cmd_sett, cryptonote::arg_stagenet_on);
|
||||
command_line::add_arg(desc_cmd_sett, arg_log_level);
|
||||
command_line::add_arg(desc_cmd_sett, arg_database);
|
||||
command_line::add_arg(desc_cmd_sett, arg_txid);
|
||||
command_line::add_arg(desc_cmd_sett, arg_height);
|
||||
command_line::add_arg(desc_cmd_sett, arg_include_coinbase);
|
||||
command_line::add_arg(desc_cmd_only, command_line::arg_help);
|
||||
|
||||
po::options_description desc_options("Allowed options");
|
||||
desc_options.add(desc_cmd_only).add(desc_cmd_sett);
|
||||
|
||||
po::variables_map vm;
|
||||
bool r = command_line::handle_error_helper(desc_options, [&]()
|
||||
{
|
||||
auto parser = po::command_line_parser(argc, argv).options(desc_options);
|
||||
po::store(parser.run(), vm);
|
||||
po::notify(vm);
|
||||
return true;
|
||||
});
|
||||
if (! r)
|
||||
return 1;
|
||||
|
||||
if (command_line::get_arg(vm, command_line::arg_help))
|
||||
{
|
||||
std::cout << "Wownero '" << MONERO_RELEASE_NAME << "' (v" << MONERO_VERSION_FULL << ")" << ENDL << ENDL;
|
||||
std::cout << desc_options << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
mlog_configure(mlog_get_default_log_path("wownero-blockchain-depth.log"), true);
|
||||
if (!command_line::is_arg_defaulted(vm, arg_log_level))
|
||||
mlog_set_log(command_line::get_arg(vm, arg_log_level).c_str());
|
||||
else
|
||||
mlog_set_log(std::string(std::to_string(log_level) + ",bcutil:INFO").c_str());
|
||||
|
||||
LOG_PRINT_L0("Starting...");
|
||||
|
||||
std::string opt_data_dir = command_line::get_arg(vm, cryptonote::arg_data_dir);
|
||||
bool opt_testnet = command_line::get_arg(vm, cryptonote::arg_testnet_on);
|
||||
bool opt_stagenet = command_line::get_arg(vm, cryptonote::arg_stagenet_on);
|
||||
network_type net_type = opt_testnet ? TESTNET : opt_stagenet ? STAGENET : MAINNET;
|
||||
std::string opt_txid_string = command_line::get_arg(vm, arg_txid);
|
||||
uint64_t opt_height = command_line::get_arg(vm, arg_height);
|
||||
bool opt_include_coinbase = command_line::get_arg(vm, arg_include_coinbase);
|
||||
|
||||
if (!opt_txid_string.empty() && opt_height)
|
||||
{
|
||||
std::cerr << "txid and height cannot be given at the same time" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
crypto::hash opt_txid = crypto::null_hash;
|
||||
if (!opt_txid_string.empty())
|
||||
{
|
||||
if (!epee::string_tools::hex_to_pod(opt_txid_string, opt_txid))
|
||||
{
|
||||
std::cerr << "Invalid txid" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
std::string db_type = command_line::get_arg(vm, arg_database);
|
||||
if (!cryptonote::blockchain_valid_db_type(db_type))
|
||||
{
|
||||
std::cerr << "Invalid database type: " << db_type << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// If we wanted to use the memory pool, we would set up a fake_core.
|
||||
|
||||
// Use Blockchain instead of lower-level BlockchainDB for two reasons:
|
||||
// 1. Blockchain has the init() method for easy setup
|
||||
// 2. exporter needs to use get_current_blockchain_height(), get_block_id_by_height(), get_block_by_hash()
|
||||
//
|
||||
// cannot match blockchain_storage setup above with just one line,
|
||||
// e.g.
|
||||
// Blockchain* core_storage = new Blockchain(NULL);
|
||||
// because unlike blockchain_storage constructor, which takes a pointer to
|
||||
// tx_memory_pool, Blockchain's constructor takes tx_memory_pool object.
|
||||
LOG_PRINT_L0("Initializing source blockchain (BlockchainDB)");
|
||||
std::unique_ptr<Blockchain> core_storage;
|
||||
tx_memory_pool m_mempool(*core_storage);
|
||||
core_storage.reset(new Blockchain(m_mempool));
|
||||
BlockchainDB *db = new_db(db_type);
|
||||
if (db == NULL)
|
||||
{
|
||||
LOG_ERROR("Attempted to use non-existent database type: " << db_type);
|
||||
throw std::runtime_error("Attempting to use non-existent database type");
|
||||
}
|
||||
LOG_PRINT_L0("database: " << db_type);
|
||||
|
||||
const std::string filename = (boost::filesystem::path(opt_data_dir) / db->get_db_name()).string();
|
||||
LOG_PRINT_L0("Loading blockchain from folder " << filename << " ...");
|
||||
|
||||
try
|
||||
{
|
||||
db->open(filename, DBF_RDONLY);
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
LOG_PRINT_L0("Error opening database: " << e.what());
|
||||
return 1;
|
||||
}
|
||||
r = core_storage->init(db, net_type);
|
||||
|
||||
CHECK_AND_ASSERT_MES(r, 1, "Failed to initialize source blockchain storage");
|
||||
LOG_PRINT_L0("Source blockchain storage initialized OK");
|
||||
|
||||
std::vector<crypto::hash> start_txids;
|
||||
if (!opt_txid_string.empty())
|
||||
{
|
||||
start_txids.push_back(opt_txid);
|
||||
}
|
||||
else
|
||||
{
|
||||
const crypto::hash block_hash = db->get_block_hash_from_height(opt_height);
|
||||
const cryptonote::blobdata bd = db->get_block_blob(block_hash);
|
||||
cryptonote::block b;
|
||||
if (!cryptonote::parse_and_validate_block_from_blob(bd, b))
|
||||
{
|
||||
LOG_PRINT_L0("Bad block from db");
|
||||
return 1;
|
||||
}
|
||||
for (const crypto::hash &txid: b.tx_hashes)
|
||||
start_txids.push_back(txid);
|
||||
if (opt_include_coinbase)
|
||||
start_txids.push_back(cryptonote::get_transaction_hash(b.miner_tx));
|
||||
}
|
||||
|
||||
if (start_txids.empty())
|
||||
{
|
||||
LOG_PRINT_L0("No transaction(s) to check");
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::vector<uint64_t> depths;
|
||||
for (const crypto::hash &start_txid: start_txids)
|
||||
{
|
||||
uint64_t depth = 0;
|
||||
bool coinbase = false;
|
||||
|
||||
LOG_PRINT_L0("Checking depth for txid " << start_txid);
|
||||
std::vector<crypto::hash> txids(1, start_txid);
|
||||
while (!coinbase)
|
||||
{
|
||||
LOG_PRINT_L0("Considering "<< txids.size() << " transaction(s) at depth " << depth);
|
||||
std::vector<crypto::hash> new_txids;
|
||||
for (const crypto::hash &txid: txids)
|
||||
{
|
||||
cryptonote::blobdata bd;
|
||||
if (!db->get_pruned_tx_blob(txid, bd))
|
||||
{
|
||||
LOG_PRINT_L0("Failed to get txid " << txid << " from db");
|
||||
return 1;
|
||||
}
|
||||
cryptonote::transaction tx;
|
||||
if (!cryptonote::parse_and_validate_tx_base_from_blob(bd, tx))
|
||||
{
|
||||
LOG_PRINT_L0("Bad tx: " << txid);
|
||||
return 1;
|
||||
}
|
||||
for (size_t ring = 0; ring < tx.vin.size(); ++ring)
|
||||
{
|
||||
if (tx.vin[ring].type() == typeid(cryptonote::txin_gen))
|
||||
{
|
||||
MDEBUG(txid << " is a coinbase transaction");
|
||||
coinbase = true;
|
||||
goto done;
|
||||
}
|
||||
if (tx.vin[ring].type() == typeid(cryptonote::txin_to_key))
|
||||
{
|
||||
const cryptonote::txin_to_key &txin = boost::get<cryptonote::txin_to_key>(tx.vin[ring]);
|
||||
const uint64_t amount = txin.amount;
|
||||
auto absolute_offsets = cryptonote::relative_output_offsets_to_absolute(txin.key_offsets);
|
||||
for (uint64_t offset: absolute_offsets)
|
||||
{
|
||||
const output_data_t od = db->get_output_key(amount, offset);
|
||||
const crypto::hash block_hash = db->get_block_hash_from_height(od.height);
|
||||
bd = db->get_block_blob(block_hash);
|
||||
cryptonote::block b;
|
||||
if (!cryptonote::parse_and_validate_block_from_blob(bd, b))
|
||||
{
|
||||
LOG_PRINT_L0("Bad block from db");
|
||||
return 1;
|
||||
}
|
||||
// find the tx which created this output
|
||||
bool found = false;
|
||||
for (size_t out = 0; out < b.miner_tx.vout.size(); ++out)
|
||||
{
|
||||
if (b.miner_tx.vout[out].target.type() == typeid(cryptonote::txout_to_key))
|
||||
{
|
||||
const auto &txout = boost::get<cryptonote::txout_to_key>(b.miner_tx.vout[out].target);
|
||||
if (txout.key == od.pubkey)
|
||||
{
|
||||
found = true;
|
||||
new_txids.push_back(cryptonote::get_transaction_hash(b.miner_tx));
|
||||
MDEBUG("adding txid: " << cryptonote::get_transaction_hash(b.miner_tx));
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_PRINT_L0("Bad vout type in txid " << cryptonote::get_transaction_hash(b.miner_tx));
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
for (const crypto::hash &block_txid: b.tx_hashes)
|
||||
{
|
||||
if (found)
|
||||
break;
|
||||
if (!db->get_pruned_tx_blob(block_txid, bd))
|
||||
{
|
||||
LOG_PRINT_L0("Failed to get txid " << block_txid << " from db");
|
||||
return 1;
|
||||
}
|
||||
cryptonote::transaction tx2;
|
||||
if (!cryptonote::parse_and_validate_tx_base_from_blob(bd, tx2))
|
||||
{
|
||||
LOG_PRINT_L0("Bad tx: " << block_txid);
|
||||
return 1;
|
||||
}
|
||||
for (size_t out = 0; out < tx2.vout.size(); ++out)
|
||||
{
|
||||
if (tx2.vout[out].target.type() == typeid(cryptonote::txout_to_key))
|
||||
{
|
||||
const auto &txout = boost::get<cryptonote::txout_to_key>(tx2.vout[out].target);
|
||||
if (txout.key == od.pubkey)
|
||||
{
|
||||
found = true;
|
||||
new_txids.push_back(block_txid);
|
||||
MDEBUG("adding txid: " << block_txid);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_PRINT_L0("Bad vout type in txid " << block_txid);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
{
|
||||
LOG_PRINT_L0("Output originating transaction not found");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_PRINT_L0("Bad vin type in txid " << txid);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!coinbase)
|
||||
{
|
||||
std::swap(txids, new_txids);
|
||||
++depth;
|
||||
}
|
||||
}
|
||||
done:
|
||||
LOG_PRINT_L0("Min depth for txid " << start_txid << ": " << depth);
|
||||
depths.push_back(depth);
|
||||
}
|
||||
|
||||
uint64_t cumulative_depth = 0;
|
||||
for (uint64_t depth: depths)
|
||||
cumulative_depth += depth;
|
||||
LOG_PRINT_L0("Average min depth for " << start_txids.size() << " transaction(s): " << cumulative_depth/(float)depths.size());
|
||||
LOG_PRINT_L0("Median min depth for " << start_txids.size() << " transaction(s): " << epee::misc_utils::median(depths));
|
||||
|
||||
core_storage->deinit();
|
||||
return 0;
|
||||
|
||||
CATCH_ENTRY("Depth query error", 1);
|
||||
}
|
||||
@@ -33,6 +33,7 @@
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <unistd.h>
|
||||
#include "misc_log_ex.h"
|
||||
#include "bootstrap_file.h"
|
||||
#include "bootstrap_serialization.h"
|
||||
@@ -164,7 +165,7 @@ int pop_blocks(cryptonote::core& core, int num_blocks)
|
||||
return num_blocks;
|
||||
}
|
||||
|
||||
int check_flush(cryptonote::core &core, std::list<block_complete_entry> &blocks, bool force)
|
||||
int check_flush(cryptonote::core &core, std::vector<block_complete_entry> &blocks, bool force)
|
||||
{
|
||||
if (blocks.empty())
|
||||
return 0;
|
||||
@@ -176,7 +177,7 @@ int check_flush(cryptonote::core &core, std::list<block_complete_entry> &blocks,
|
||||
if (!force && new_height % HASH_OF_HASHES_STEP)
|
||||
return 0;
|
||||
|
||||
std::list<crypto::hash> hashes;
|
||||
std::vector<crypto::hash> hashes;
|
||||
for (const auto &b: blocks)
|
||||
{
|
||||
cryptonote::block block;
|
||||
@@ -312,7 +313,7 @@ int import_from_file(cryptonote::core& core, const std::string& import_file_path
|
||||
MINFO("Reading blockchain from bootstrap file...");
|
||||
std::cout << ENDL;
|
||||
|
||||
std::list<block_complete_entry> blocks;
|
||||
std::vector<block_complete_entry> blocks;
|
||||
|
||||
// Skip to start_height before we start adding.
|
||||
{
|
||||
@@ -437,7 +438,7 @@ int import_from_file(cryptonote::core& core, const std::string& import_file_path
|
||||
{
|
||||
cryptonote::blobdata block;
|
||||
cryptonote::block_to_blob(bp.block, block);
|
||||
std::list<cryptonote::blobdata> txs;
|
||||
std::vector<cryptonote::blobdata> txs;
|
||||
for (const auto &tx: bp.txs)
|
||||
{
|
||||
txs.push_back(cryptonote::blobdata());
|
||||
@@ -473,17 +474,18 @@ int import_from_file(cryptonote::core& core, const std::string& import_file_path
|
||||
txs.push_back(tx);
|
||||
}
|
||||
|
||||
size_t block_size;
|
||||
size_t block_weight;
|
||||
difficulty_type cumulative_difficulty;
|
||||
uint64_t coins_generated;
|
||||
|
||||
block_size = bp.block_size;
|
||||
block_weight = bp.block_weight;
|
||||
cumulative_difficulty = bp.cumulative_difficulty;
|
||||
coins_generated = bp.coins_generated;
|
||||
|
||||
try
|
||||
{
|
||||
core.get_blockchain_storage().get_db().add_block(b, block_size, cumulative_difficulty, coins_generated, txs);
|
||||
uint64_t long_term_block_weight = core.get_blockchain_storage().get_next_long_term_block_weight(block_weight);
|
||||
core.get_blockchain_storage().get_db().add_block(b, block_weight, long_term_block_weight, cumulative_difficulty, coins_generated, txs);
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
@@ -593,8 +595,8 @@ int main(int argc, char* argv[])
|
||||
const command_line::arg_descriptor<std::string> arg_database = {
|
||||
"database", available_dbs.c_str(), default_db_type
|
||||
};
|
||||
const command_line::arg_descriptor<bool> arg_verify = {"guard-against-pwnage",
|
||||
"Verify blocks and transactions during import (only disable if you exported the file yourself)", true};
|
||||
const command_line::arg_descriptor<bool> arg_noverify = {"dangerous-unverified-import",
|
||||
"Blindly trust the import file and use potentially malicious blocks and transactions during import (only enable if you exported the file yourself)", false};
|
||||
const command_line::arg_descriptor<bool> arg_batch = {"batch",
|
||||
"Batch transactions for faster import", true};
|
||||
const command_line::arg_descriptor<bool> arg_resume = {"resume",
|
||||
@@ -614,7 +616,7 @@ int main(int argc, char* argv[])
|
||||
// call add_options() directly for these arguments since
|
||||
// command_line helpers support only boolean switch, not boolean argument
|
||||
desc_cmd_sett.add_options()
|
||||
(arg_verify.name, make_semantic(arg_verify), arg_verify.description)
|
||||
(arg_noverify.name, make_semantic(arg_noverify), arg_noverify.description)
|
||||
(arg_batch.name, make_semantic(arg_batch), arg_batch.description)
|
||||
(arg_resume.name, make_semantic(arg_resume), arg_resume.description)
|
||||
;
|
||||
@@ -633,7 +635,7 @@ int main(int argc, char* argv[])
|
||||
if (! r)
|
||||
return 1;
|
||||
|
||||
opt_verify = command_line::get_arg(vm, arg_verify);
|
||||
opt_verify = !command_line::get_arg(vm, arg_noverify);
|
||||
opt_batch = command_line::get_arg(vm, arg_batch);
|
||||
opt_resume = command_line::get_arg(vm, arg_resume);
|
||||
block_stop = command_line::get_arg(vm, arg_block_stop);
|
||||
@@ -738,6 +740,18 @@ int main(int argc, char* argv[])
|
||||
MINFO("bootstrap file path: " << import_file_path);
|
||||
MINFO("database path: " << m_config_folder);
|
||||
|
||||
if (!opt_verify)
|
||||
{
|
||||
MCLOG_RED(el::Level::Warning, "global", "\n"
|
||||
"Import is set to proceed WITHOUT VERIFICATION.\n"
|
||||
"This is a DANGEROUS operation: if the file was tampered with in transit, or obtained from a malicious source,\n"
|
||||
"you could end up with a compromised database. It is recommended to NOT use " << arg_noverify.name << ".\n"
|
||||
"*****************************************************************************************\n"
|
||||
"You have 90 seconds to press ^C or terminate this program before unverified import starts\n"
|
||||
"*****************************************************************************************");
|
||||
sleep(90);
|
||||
}
|
||||
|
||||
cryptonote::cryptonote_protocol_stub pr; //TODO: stub only for this kind of test, make real validation of relayed objects
|
||||
cryptonote::core core(&pr);
|
||||
|
||||
|
||||
@@ -234,7 +234,7 @@ int main(int argc, char* argv[])
|
||||
}
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}, true);
|
||||
|
||||
std::unordered_map<uint64_t, uint64_t> counts;
|
||||
size_t total = 0;
|
||||
@@ -243,10 +243,17 @@ int main(int argc, char* argv[])
|
||||
counts[out.second.size()]++;
|
||||
total++;
|
||||
}
|
||||
for (const auto &c: counts)
|
||||
if (total > 0)
|
||||
{
|
||||
float percent = 100.f * c.second / total;
|
||||
MINFO(std::to_string(c.second) << " outputs used " << c.first << " times (" << percent << "%)");
|
||||
for (const auto &c: counts)
|
||||
{
|
||||
float percent = 100.f * c.second / total;
|
||||
MINFO(std::to_string(c.second) << " outputs used " << c.first << " times (" << percent << "%)");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
MINFO("No outputs to process");
|
||||
}
|
||||
|
||||
LOG_PRINT_L0("Blockchain usage exported OK");
|
||||
|
||||
@@ -236,11 +236,11 @@ void BootstrapFile::write_block(block& block)
|
||||
bool include_extra_block_data = true;
|
||||
if (include_extra_block_data)
|
||||
{
|
||||
size_t block_size = m_blockchain_storage->get_db().get_block_size(block_height);
|
||||
size_t block_weight = m_blockchain_storage->get_db().get_block_weight(block_height);
|
||||
difficulty_type cumulative_difficulty = m_blockchain_storage->get_db().get_block_cumulative_difficulty(block_height);
|
||||
uint64_t coins_generated = m_blockchain_storage->get_db().get_block_already_generated_coins(block_height);
|
||||
|
||||
bp.block_size = block_size;
|
||||
bp.block_weight = block_weight;
|
||||
bp.cumulative_difficulty = cumulative_difficulty;
|
||||
bp.coins_generated = coins_generated;
|
||||
}
|
||||
@@ -400,18 +400,18 @@ uint64_t BootstrapFile::count_bytes(std::ifstream& import_file, uint64_t blocks,
|
||||
{
|
||||
std::cout << refresh_string;
|
||||
MWARNING("WARNING: chunk_size " << chunk_size << " > BUFFER_SIZE " << BUFFER_SIZE
|
||||
<< " height: " << h-1);
|
||||
<< " height: " << h-1 << ", offset " << bytes_read);
|
||||
throw std::runtime_error("Aborting: chunk size exceeds buffer size");
|
||||
}
|
||||
if (chunk_size > CHUNK_SIZE_WARNING_THRESHOLD)
|
||||
{
|
||||
std::cout << refresh_string;
|
||||
MDEBUG("NOTE: chunk_size " << chunk_size << " > " << CHUNK_SIZE_WARNING_THRESHOLD << " << height: "
|
||||
<< h-1);
|
||||
<< h-1 << ", offset " << bytes_read);
|
||||
}
|
||||
else if (chunk_size <= 0) {
|
||||
std::cout << refresh_string;
|
||||
MDEBUG("ERROR: chunk_size " << chunk_size << " <= 0" << " height: " << h-1);
|
||||
MDEBUG("ERROR: chunk_size " << chunk_size << " <= 0" << " height: " << h-1 << ", offset " << bytes_read);
|
||||
throw std::runtime_error("Aborting");
|
||||
}
|
||||
// skip to next expected block size value
|
||||
|
||||
@@ -70,14 +70,14 @@ namespace cryptonote
|
||||
{
|
||||
cryptonote::block block;
|
||||
std::vector<transaction> txs;
|
||||
size_t block_size;
|
||||
size_t block_weight;
|
||||
difficulty_type cumulative_difficulty;
|
||||
uint64_t coins_generated;
|
||||
|
||||
BEGIN_SERIALIZE()
|
||||
FIELD(block)
|
||||
FIELD(txs)
|
||||
VARINT_FIELD(block_size)
|
||||
VARINT_FIELD(block_weight)
|
||||
VARINT_FIELD(cumulative_difficulty)
|
||||
VARINT_FIELD(coins_generated)
|
||||
END_SERIALIZE()
|
||||
|
||||
@@ -30,9 +30,15 @@ if(APPLE)
|
||||
add_library(blocks STATIC blockexports.c)
|
||||
set_target_properties(blocks PROPERTIES LINKER_LANGUAGE C)
|
||||
else()
|
||||
add_custom_command(OUTPUT blocks.o MAIN_DEPENDENCY blocks.dat COMMAND cd ${CMAKE_CURRENT_SOURCE_DIR} && ${CMAKE_LINKER} ${LD_RAW_FLAGS} -r -b binary -o ${CMAKE_CURRENT_BINARY_DIR}/blocks.o blocks.dat)
|
||||
add_custom_command(OUTPUT testnet_blocks.o MAIN_DEPENDENCY testnet_blocks.dat COMMAND cd ${CMAKE_CURRENT_SOURCE_DIR} && ${CMAKE_LINKER} ${LD_RAW_FLAGS} -r -b binary -o ${CMAKE_CURRENT_BINARY_DIR}/testnet_blocks.o testnet_blocks.dat)
|
||||
add_custom_command(OUTPUT stagenet_blocks.o MAIN_DEPENDENCY stagenet_blocks.dat COMMAND cd ${CMAKE_CURRENT_SOURCE_DIR} && ${CMAKE_LINKER} ${LD_RAW_FLAGS} -r -b binary -o ${CMAKE_CURRENT_BINARY_DIR}/stagenet_blocks.o stagenet_blocks.dat)
|
||||
if(LINUX_32)
|
||||
add_custom_command(OUTPUT blocks.o MAIN_DEPENDENCY blocks.dat COMMAND cd ${CMAKE_CURRENT_SOURCE_DIR} && ${CMAKE_LINKER} -m elf_i386 ${LD_RAW_FLAGS} -r -b binary -o ${CMAKE_CURRENT_BINARY_DIR}/blocks.o blocks.dat)
|
||||
add_custom_command(OUTPUT testnet_blocks.o MAIN_DEPENDENCY testnet_blocks.dat COMMAND cd ${CMAKE_CURRENT_SOURCE_DIR} && ${CMAKE_LINKER} -m elf_i386 ${LD_RAW_FLAGS} -r -b binary -o ${CMAKE_CURRENT_BINARY_DIR}/testnet_blocks.o testnet_blocks.dat)
|
||||
add_custom_command(OUTPUT stagenet_blocks.o MAIN_DEPENDENCY stagenet_blocks.dat COMMAND cd ${CMAKE_CURRENT_SOURCE_DIR} && ${CMAKE_LINKER} -m elf_i386 ${LD_RAW_FLAGS} -r -b binary -o ${CMAKE_CURRENT_BINARY_DIR}/stagenet_blocks.o stagenet_blocks.dat)
|
||||
else()
|
||||
add_custom_command(OUTPUT blocks.o MAIN_DEPENDENCY blocks.dat COMMAND cd ${CMAKE_CURRENT_SOURCE_DIR} && ${CMAKE_LINKER} ${LD_RAW_FLAGS} -r -b binary -o ${CMAKE_CURRENT_BINARY_DIR}/blocks.o blocks.dat)
|
||||
add_custom_command(OUTPUT testnet_blocks.o MAIN_DEPENDENCY testnet_blocks.dat COMMAND cd ${CMAKE_CURRENT_SOURCE_DIR} && ${CMAKE_LINKER} ${LD_RAW_FLAGS} -r -b binary -o ${CMAKE_CURRENT_BINARY_DIR}/testnet_blocks.o testnet_blocks.dat)
|
||||
add_custom_command(OUTPUT stagenet_blocks.o MAIN_DEPENDENCY stagenet_blocks.dat COMMAND cd ${CMAKE_CURRENT_SOURCE_DIR} && ${CMAKE_LINKER} ${LD_RAW_FLAGS} -r -b binary -o ${CMAKE_CURRENT_BINARY_DIR}/stagenet_blocks.o stagenet_blocks.dat)
|
||||
endif()
|
||||
add_library(blocks STATIC blocks.o testnet_blocks.o stagenet_blocks.o blockexports.c)
|
||||
set_target_properties(blocks PROPERTIES LINKER_LANGUAGE C)
|
||||
endif()
|
||||
|
||||
Binary file not shown.
52
src/checkpoints/checkpoints.cpp
Executable file → Normal file
52
src/checkpoints/checkpoints.cpp
Executable file → Normal file
@@ -169,18 +169,18 @@ namespace cryptonote
|
||||
{
|
||||
return true;
|
||||
}
|
||||
ADD_CHECKPOINT(1, "97f4ce4d7879b3bea54dcec738cd2ebb7952b4e9bb9743262310cd5fec749340");
|
||||
ADD_CHECKPOINT(10, "305472c87ff86d8afb3ec42634828462b0ed3d929fc05fa1ae668c3bee04837a");
|
||||
ADD_CHECKPOINT(100, "a92b9deae26e19322041cbc2f850fa905748ae1e5bf69b35ca90b247c5cbfc04");
|
||||
ADD_CHECKPOINT(1000, "62921e13030b29264439cafaf8320cf8aa039ee6ba7ba29c72f11b50a079269a");
|
||||
ADD_CHECKPOINT(2000, "b3e1d73e3d0243239481aa76cb075cf2428556f5dc4f2e30428ea2ba36693e97");
|
||||
ADD_CHECKPOINT(3000, "83a6e1ab394e80b8442b7b70b0e4c3a9fa0143e0ca51a33e829537ef5dd1bf13");
|
||||
ADD_CHECKPOINT(4000, "7c70722d8cb8106b4bec67e1790614cc6e98db7afd0843b96cdff6960a0e0073");
|
||||
ADD_CHECKPOINT(5000, "331ee74008e174e5fd1956f64c52793961b321a1366f7c6f7d324e8265df34f6");
|
||||
ADD_CHECKPOINT(6969, "aa7b66e8c461065139b55c29538a39c33ceda93e587f84d490ed573d80511c87"); //Hard fork to v8
|
||||
ADD_CHECKPOINT(7000, "2711bd33b107f744ad8bf98c1acefa18658780079496bd2f3a36f2e20b261f8e");
|
||||
ADD_CHECKPOINT(7500, "5975967c4624f13f058acafe7adf9355e03e8e802eeadc84ccb22ea588bc0762");
|
||||
ADD_CHECKPOINT(7900, "d9bc18cb35feb6b26bc5a19bbdbf7c852d9cc02883acb5bbce2e87d8b2c86069");
|
||||
ADD_CHECKPOINT(1, "97f4ce4d7879b3bea54dcec738cd2ebb7952b4e9bb9743262310cd5fec749340");
|
||||
ADD_CHECKPOINT(10, "305472c87ff86d8afb3ec42634828462b0ed3d929fc05fa1ae668c3bee04837a");
|
||||
ADD_CHECKPOINT(100, "a92b9deae26e19322041cbc2f850fa905748ae1e5bf69b35ca90b247c5cbfc04");
|
||||
ADD_CHECKPOINT(1000, "62921e13030b29264439cafaf8320cf8aa039ee6ba7ba29c72f11b50a079269a");
|
||||
ADD_CHECKPOINT(2000, "b3e1d73e3d0243239481aa76cb075cf2428556f5dc4f2e30428ea2ba36693e97");
|
||||
ADD_CHECKPOINT(3000, "83a6e1ab394e80b8442b7b70b0e4c3a9fa0143e0ca51a33e829537ef5dd1bf13");
|
||||
ADD_CHECKPOINT(4000, "7c70722d8cb8106b4bec67e1790614cc6e98db7afd0843b96cdff6960a0e0073");
|
||||
ADD_CHECKPOINT(5000, "331ee74008e174e5fd1956f64c52793961b321a1366f7c6f7d324e8265df34f6");
|
||||
ADD_CHECKPOINT(6969, "aa7b66e8c461065139b55c29538a39c33ceda93e587f84d490ed573d80511c87"); //Hard fork to v8
|
||||
ADD_CHECKPOINT(7000, "2711bd33b107f744ad8bf98c1acefa18658780079496bd2f3a36f2e20b261f8e");
|
||||
ADD_CHECKPOINT(7500, "5975967c4624f13f058acafe7adf9355e03e8e802eeadc84ccb22ea588bc0762");
|
||||
ADD_CHECKPOINT(7900, "d9bc18cb35feb6b26bc5a19bbdbf7c852d9cc02883acb5bbce2e87d8b2c86069");
|
||||
ADD_CHECKPOINT(10000, "bc5bfbf1b26c8f976d1d792ece4c6a7e93064bec62b72f1d5beae74c3f273b3b");
|
||||
ADD_CHECKPOINT(20000, "52cc7edcb49eb02f28a653b824089a726f4050eb210263ee6f4180d388a1e5cc");
|
||||
ADD_CHECKPOINT(30000, "d22fde5dd240ade16d3250eb0aa5d1c16dc7cb51c20484e05eb274911032b3fa");
|
||||
@@ -207,12 +207,21 @@ namespace cryptonote
|
||||
ADD_CHECKPOINT(62720, "f871cddd75951e2fe24c282d2bd28396fc922ea519b354ace992a0162cb333ff");
|
||||
ADD_CHECKPOINT(62733, "8331dbeeaf23173d2235a062373a437befadb6492cceb7640127bf18653a9e61");
|
||||
ADD_CHECKPOINT(62877, "62d44adc05d7d4fd9d15239c5575612207beab0bcf2da49158bf89e365441ca1");
|
||||
ADD_CHECKPOINT(63469, "4e33a9343fc5b86661ec0affaeb5b5a065290602c02d817337e4a979fe5747d8"); //Hard fork to v10
|
||||
ADD_CHECKPOINT(69800, "5c65428a664738bc083d1ccd6a1b5ff4305f98e7633f44033816801429b33ce1");
|
||||
ADD_CHECKPOINT(75000, "e93492f79b5344e7edb31537ee65b3e908bf71110cff8188c0c62fefc015d342");
|
||||
ADD_CHECKPOINT(79500, "9bbfd6f2257ce9084de30179944b7695c9b918c9c03a8a63306ab6c5828ff857");
|
||||
ADD_CHECKPOINT(80920, "8fca818344f97ea3912557cbd8be659cf6a5bc1203514c27338e234251d72dfb");
|
||||
ADD_CHECKPOINT(81769, "41db9fef8d0ccfa78b570ee9525d4f55de77b510c3ae4b08a1d51b9aec9ade1d"); //Hard fork to v11
|
||||
ADD_CHECKPOINT(82069, "fdea800d23d0b2eea19dec8af31e453e883e8315c97e25c8bb3e88ca164f8369"); //Hard fork to v12
|
||||
ADD_CHECKPOINT(85000, "31d62ab75470b15aedee6674b78767b53f10951786e991c26035743c267b247a");
|
||||
ADD_CHECKPOINT(87000, "a788e5a7233ca2198ad6446ddc454b05d578e72253ed2bbca969527230f6eec2");
|
||||
ADD_CHECKPOINT(88200, "50bb43d5d563524d6b9f308a2483b80934bab2ab5250757558318834476f1cfb");
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool checkpoints::load_checkpoints_from_json(const std::string &json_hashfile_fullpath)
|
||||
|
||||
bool checkpoints::load_checkpoints_from_json(const std::string &json_hashfile_fullpath)
|
||||
{
|
||||
boost::system::error_code errcode;
|
||||
if (! (boost::filesystem::exists(json_hashfile_fullpath, errcode)))
|
||||
@@ -253,13 +262,11 @@ bool checkpoints::load_checkpoints_from_json(const std::string &json_hashfile_fu
|
||||
std::vector<std::string> records;
|
||||
|
||||
// All four MoneroPulse domains have DNSSEC on and valid
|
||||
static const std::vector<std::string> dns_urls = {
|
||||
};
|
||||
|
||||
|
||||
static const std::vector<std::string> testnet_dns_urls = {
|
||||
};
|
||||
static const std::vector<std::string> dns_urls = {
|
||||
};
|
||||
|
||||
static const std::vector<std::string> testnet_dns_urls = {
|
||||
};
|
||||
|
||||
static const std::vector<std::string> stagenet_dns_urls = {
|
||||
};
|
||||
@@ -310,6 +317,3 @@ bool checkpoints::load_checkpoints_from_json(const std::string &json_hashfile_fu
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -33,12 +33,17 @@ set(common_sources
|
||||
command_line.cpp
|
||||
dns_utils.cpp
|
||||
download.cpp
|
||||
error.cpp
|
||||
expect.cpp
|
||||
util.cpp
|
||||
i18n.cpp
|
||||
notify.cpp
|
||||
password.cpp
|
||||
perf_timer.cpp
|
||||
spawn.cpp
|
||||
threadpool.cpp
|
||||
updates.cpp)
|
||||
updates.cpp
|
||||
aligned.c)
|
||||
|
||||
if (STACK_TRACE)
|
||||
list(APPEND common_sources stack_trace.cpp)
|
||||
@@ -54,8 +59,11 @@ set(common_private_headers
|
||||
common_fwd.h
|
||||
dns_utils.h
|
||||
download.h
|
||||
error.h
|
||||
expect.h
|
||||
http_connection.h
|
||||
int-util.h
|
||||
notify.h
|
||||
pod-class.h
|
||||
rpc_client.h
|
||||
scoped_message_writer.h
|
||||
@@ -65,9 +73,11 @@ set(common_private_headers
|
||||
i18n.h
|
||||
password.h
|
||||
perf_timer.h
|
||||
spawn.h
|
||||
stack_trace.h
|
||||
threadpool.h
|
||||
updates.h)
|
||||
updates.h
|
||||
aligned.h)
|
||||
|
||||
monero_private_headers(common
|
||||
${common_private_headers})
|
||||
@@ -78,7 +88,6 @@ monero_add_library(common
|
||||
DEPENDS generate_translations_header)
|
||||
target_link_libraries(common
|
||||
PUBLIC
|
||||
epee
|
||||
cncrypto
|
||||
${UNBOUND_LIBRARY}
|
||||
${LIBUNWIND_LIBRARIES}
|
||||
|
||||
139
src/common/aligned.c
Normal file
139
src/common/aligned.c
Normal file
@@ -0,0 +1,139 @@
|
||||
// Copyright (c) 2017-2018, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include "aligned.h"
|
||||
|
||||
static inline int is_power_of_2(size_t n) { return n && (n & (n-1)) == 0; }
|
||||
|
||||
#define MAGIC 0xaa0817161500ff81
|
||||
#define MAGIC_FREED 0xaa0817161500ff82
|
||||
|
||||
static void local_abort(const char *msg)
|
||||
{
|
||||
fprintf(stderr, "%s\n", msg);
|
||||
#ifdef NDEBUG
|
||||
_exit(1);
|
||||
#else
|
||||
abort();
|
||||
#endif
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint64_t magic;
|
||||
void *raw;
|
||||
size_t bytes;
|
||||
size_t align;
|
||||
} control;
|
||||
|
||||
void *aligned_malloc(size_t bytes, size_t align)
|
||||
{
|
||||
void *raw, *ptr;
|
||||
control *ctrl;
|
||||
|
||||
if (!is_power_of_2(align))
|
||||
return NULL;
|
||||
if (bytes > (size_t)-1 - align)
|
||||
return NULL;
|
||||
if (bytes + align > (size_t)-1 - sizeof(control))
|
||||
return NULL;
|
||||
|
||||
raw = malloc(bytes + sizeof(control) + align);
|
||||
if (!raw)
|
||||
return NULL;
|
||||
ptr = (void*)(((uintptr_t)raw + align + sizeof(control) - 1) & ~(align-1));
|
||||
ctrl = ((control*)ptr) - 1;
|
||||
ctrl->magic = MAGIC;
|
||||
ctrl->raw = raw;
|
||||
ctrl->bytes = bytes;
|
||||
ctrl->align = align;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void *aligned_realloc(void *ptr, size_t bytes, size_t align)
|
||||
{
|
||||
void *raw, *ptr2;
|
||||
control *ctrl, *ctrl2;
|
||||
|
||||
if (!ptr)
|
||||
return aligned_malloc(bytes, align);
|
||||
if (!bytes)
|
||||
{
|
||||
aligned_free(ptr);
|
||||
return NULL;
|
||||
}
|
||||
if (!is_power_of_2(align))
|
||||
return NULL;
|
||||
|
||||
ctrl = ((control*)ptr) - 1;
|
||||
if (ctrl->magic == MAGIC_FREED)
|
||||
local_abort("Double free detected");
|
||||
if (ctrl->magic != MAGIC)
|
||||
local_abort("Freeing unallocated memory");
|
||||
if (ctrl->align != align)
|
||||
return NULL;
|
||||
if (ctrl->bytes >= bytes)
|
||||
return ptr;
|
||||
|
||||
if (ctrl->bytes > (size_t)-1 - ctrl->align)
|
||||
return NULL;
|
||||
if (ctrl->bytes + ctrl->align > (size_t)-1 - sizeof(control))
|
||||
return NULL;
|
||||
|
||||
raw = malloc(bytes + sizeof(control) + ctrl->align);
|
||||
if (!raw)
|
||||
return NULL;
|
||||
ptr2 = (void*)(((uintptr_t)raw + ctrl->align + sizeof(control) - 1) & ~(ctrl->align-1));
|
||||
memcpy(ptr2, ptr, ctrl->bytes);
|
||||
ctrl2 = ((control*)ptr2) - 1;
|
||||
ctrl2->magic = MAGIC;
|
||||
ctrl2->raw = raw;
|
||||
ctrl2->bytes = bytes;
|
||||
ctrl2->align = ctrl->align;
|
||||
ctrl->magic = MAGIC_FREED;
|
||||
free(ctrl->raw);
|
||||
return ptr2;
|
||||
}
|
||||
|
||||
void aligned_free(void *ptr)
|
||||
{
|
||||
if (!ptr)
|
||||
return;
|
||||
control *ctrl = ((control*)ptr) - 1;
|
||||
if (ctrl->magic == MAGIC_FREED)
|
||||
local_abort("Double free detected");
|
||||
if (ctrl->magic != MAGIC)
|
||||
local_abort("Freeing unallocated memory");
|
||||
ctrl->magic = MAGIC_FREED;
|
||||
free(ctrl->raw);
|
||||
}
|
||||
41
src/common/aligned.h
Normal file
41
src/common/aligned.h
Normal file
@@ -0,0 +1,41 @@
|
||||
// Copyright (c) 2018, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void *aligned_malloc(size_t bytes, size_t align);
|
||||
void *aligned_realloc(void *ptr, size_t bytes, size_t align);
|
||||
void aligned_free(void *ptr);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -46,10 +46,11 @@ namespace bf = boost::filesystem;
|
||||
static const char *DEFAULT_DNS_PUBLIC_ADDR[] =
|
||||
{
|
||||
"194.150.168.168", // CCC (Germany)
|
||||
"81.3.27.54", // Lightning Wire Labs (Germany)
|
||||
"31.3.135.232", // OpenNIC (Switzerland)
|
||||
"80.67.169.40", // FDN (France)
|
||||
"209.58.179.186", // Cyberghost (Singapore)
|
||||
"89.233.43.71", // http://censurfridns.dk (Denmark)
|
||||
"109.69.8.51", // punCAT (Spain)
|
||||
"77.109.148.137", // Xiala.net (Switzerland)
|
||||
"193.58.251.251", // SkyDNS (Russia)
|
||||
};
|
||||
|
||||
static boost::mutex instance_lock;
|
||||
@@ -97,11 +98,14 @@ get_builtin_cert(void)
|
||||
*/
|
||||
|
||||
/** return the built in root DS trust anchor */
|
||||
static const char*
|
||||
static const char* const*
|
||||
get_builtin_ds(void)
|
||||
{
|
||||
return
|
||||
". IN DS 19036 8 2 49AAC11D7B6F6446702E54A1607371607A1A41855200FD2CE1CDDE32F24E8FB5\n";
|
||||
static const char * const ds[] =
|
||||
{
|
||||
NULL
|
||||
};
|
||||
return ds;
|
||||
}
|
||||
|
||||
/************************************************************
|
||||
@@ -240,7 +244,12 @@ DNSResolver::DNSResolver() : m_data(new DNSResolverData())
|
||||
ub_ctx_hosts(m_data->m_ub_context, NULL);
|
||||
}
|
||||
|
||||
ub_ctx_add_ta(m_data->m_ub_context, string_copy(::get_builtin_ds()));
|
||||
const char * const *ds = ::get_builtin_ds();
|
||||
while (*ds)
|
||||
{
|
||||
MINFO("adding trust anchor: " << *ds);
|
||||
ub_ctx_add_ta(m_data->m_ub_context, string_copy(*ds++));
|
||||
}
|
||||
}
|
||||
|
||||
DNSResolver::~DNSResolver()
|
||||
@@ -505,7 +514,7 @@ bool load_txt_records_from_dns(std::vector<std::string> &good_records, const std
|
||||
|
||||
if (num_valid_records < 2)
|
||||
{
|
||||
LOG_PRINT_L2("WARNING: no two valid Wownero DNS checkpoint records were received");
|
||||
LOG_PRINT_L0("WARNING: no two valid MoneroPulse DNS checkpoint records were received");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -527,7 +536,7 @@ bool load_txt_records_from_dns(std::vector<std::string> &good_records, const std
|
||||
|
||||
if (good_records_index < 0)
|
||||
{
|
||||
LOG_PRINT_L2("WARNING: no two Wownero DNS checkpoint records matched");
|
||||
LOG_PRINT_L0("WARNING: no two MoneroPulse DNS checkpoint records matched");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
75
src/common/error.cpp
Normal file
75
src/common/error.cpp
Normal file
@@ -0,0 +1,75 @@
|
||||
// Copyright (c) 2018, The Monero Project
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include "error.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace
|
||||
{
|
||||
struct category final : std::error_category
|
||||
{
|
||||
virtual const char* name() const noexcept override final
|
||||
{
|
||||
return "common_category()";
|
||||
}
|
||||
|
||||
virtual std::string message(int value) const override final
|
||||
{
|
||||
switch (common_error(value))
|
||||
{
|
||||
case common_error::kInvalidArgument:
|
||||
return make_error_code(std::errc::invalid_argument).message();
|
||||
case common_error::kInvalidErrorCode:
|
||||
return "expect<T> was given an error value of zero";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return "Unknown basic_category() value";
|
||||
}
|
||||
|
||||
virtual std::error_condition default_error_condition(int value) const noexcept override final
|
||||
{
|
||||
// maps specific errors to generic `std::errc` cases.
|
||||
switch (common_error(value))
|
||||
{
|
||||
case common_error::kInvalidArgument:
|
||||
case common_error::kInvalidErrorCode:
|
||||
return std::errc::invalid_argument;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return std::error_condition{value, *this};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
std::error_category const& common_category() noexcept
|
||||
{
|
||||
static const category instance{};
|
||||
return instance;
|
||||
}
|
||||
|
||||
52
src/common/error.h
Normal file
52
src/common/error.h
Normal file
@@ -0,0 +1,52 @@
|
||||
// Copyright (c) 2018, The Monero Project
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#pragma once
|
||||
|
||||
#include <system_error>
|
||||
#include <type_traits>
|
||||
|
||||
enum class common_error : int
|
||||
{
|
||||
// 0 is reserved for no error, as per expect<T>
|
||||
kInvalidArgument = 1, //!< A function argument is invalid
|
||||
kInvalidErrorCode //!< Default `std::error_code` given to `expect<T>`
|
||||
};
|
||||
|
||||
std::error_category const& common_category() noexcept;
|
||||
|
||||
inline std::error_code make_error_code(::common_error value) noexcept
|
||||
{
|
||||
return std::error_code{int(value), common_category()};
|
||||
}
|
||||
|
||||
namespace std
|
||||
{
|
||||
template<>
|
||||
struct is_error_code_enum<::common_error>
|
||||
: true_type
|
||||
{};
|
||||
}
|
||||
70
src/common/expect.cpp
Normal file
70
src/common/expect.cpp
Normal file
@@ -0,0 +1,70 @@
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include "expect.h"
|
||||
|
||||
#include <easylogging++.h>
|
||||
#include <string>
|
||||
|
||||
namespace detail
|
||||
{
|
||||
namespace
|
||||
{
|
||||
std::string generate_error(const char* msg, const char* file, unsigned line)
|
||||
{
|
||||
std::string error_msg{};
|
||||
if (msg)
|
||||
{
|
||||
error_msg.append(msg);
|
||||
if (file)
|
||||
error_msg.append(" (");
|
||||
}
|
||||
if (file)
|
||||
{
|
||||
error_msg.append("thrown at ");
|
||||
|
||||
// remove path, get just filename + extension
|
||||
char buff[256] = {0};
|
||||
el::base::utils::File::buildBaseFilename(file, buff, sizeof(buff) - 1);
|
||||
error_msg.append(buff);
|
||||
|
||||
error_msg.push_back(':');
|
||||
error_msg.append(std::to_string(line));
|
||||
}
|
||||
if (msg && file)
|
||||
error_msg.push_back(')');
|
||||
return error_msg;
|
||||
}
|
||||
}
|
||||
|
||||
void expect::throw_(std::error_code ec, const char* msg, const char* file, unsigned line)
|
||||
{
|
||||
if (msg || file)
|
||||
throw std::system_error{ec, generate_error(msg, file, line)};
|
||||
throw std::system_error{ec};
|
||||
}
|
||||
} // detail
|
||||
449
src/common/expect.h
Normal file
449
src/common/expect.h
Normal file
@@ -0,0 +1,449 @@
|
||||
// Copyright (c) 2018, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cassert>
|
||||
#include <system_error>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "common/error.h"
|
||||
|
||||
//! If precondition fails, return `::error::kInvalidArgument` in current scope.
|
||||
#define MONERO_PRECOND(...) \
|
||||
do \
|
||||
{ \
|
||||
if (!( __VA_ARGS__ )) \
|
||||
return {::common_error::kInvalidArgument}; \
|
||||
} while (0)
|
||||
|
||||
//! Check `expect<void>` and return errors in current scope.
|
||||
#define MONERO_CHECK(...) \
|
||||
do \
|
||||
{ \
|
||||
const ::expect<void> result = __VA_ARGS__ ; \
|
||||
if (!result) \
|
||||
return result.error(); \
|
||||
} while (0)
|
||||
|
||||
/*! Get `T` from `expect<T>` by `std::move` as-if by function call.
|
||||
`expect<void>` returns nothing.
|
||||
|
||||
\throw std::system_error with `expect<T>::error()`, filename and line
|
||||
number when `expect<T>::has_error() == true`.*/
|
||||
#define MONERO_UNWRAP(...) \
|
||||
::detail::expect::unwrap( __VA_ARGS__ , nullptr, __FILE__ , __LINE__ )
|
||||
|
||||
/* \throw std::system_error with `code` and `msg` as part of the details. The
|
||||
filename and line number will automatically be injected into the explanation
|
||||
string. `code` can be any enum convertible to `std::error_code`. */
|
||||
#define MONERO_THROW(code, msg) \
|
||||
::detail::expect::throw_( code , msg , __FILE__ , __LINE__ )
|
||||
|
||||
|
||||
template<typename> class expect;
|
||||
|
||||
namespace detail
|
||||
{
|
||||
// Shortens the characters in the places that `enable_if` is used below.
|
||||
template<bool C>
|
||||
using enable_if = typename std::enable_if<C>::type;
|
||||
|
||||
struct expect
|
||||
{
|
||||
//! \throw std::system_error with `ec`, optional `msg` and/or optional `file` + `line`.
|
||||
static void throw_(std::error_code ec, const char* msg, const char* file, unsigned line);
|
||||
|
||||
//! If `result.has_error()` call `throw_`. Otherwise, \return `*result` by move.
|
||||
template<typename T>
|
||||
static T unwrap(::expect<T>&& result, const char* error_msg, const char* file, unsigned line)
|
||||
{
|
||||
if (!result)
|
||||
throw_(result.error(), error_msg, file, line);
|
||||
return std::move(*result);
|
||||
}
|
||||
|
||||
//! If `result.has_error()` call `throw_`.
|
||||
static void unwrap(::expect<void>&& result, const char* error_msg, const char* file, unsigned line);
|
||||
};
|
||||
}
|
||||
|
||||
/*!
|
||||
`expect<T>` is a value or error implementation, similar to Rust std::result
|
||||
or various C++ proposals (boost::expected, boost::outcome). This
|
||||
implementation currently has a strict error type, `std::error_code`, and a
|
||||
templated value type `T`. `expect<T>` is implicitly convertible from `T`
|
||||
or `std::error_code`, and one `expect<T>` object type is implicitly
|
||||
convertible to another `expect<U>` object iff the destination value type
|
||||
can be implicitly constructed from the source value type (i.e.
|
||||
`struct U { ... U(T src) { ...} ... };`).
|
||||
|
||||
`operator==` and `operator!=` are the only comparison operators provided;
|
||||
comparison between different value types is allowed provided the two values
|
||||
types have a `operator==` defined between them (i.e.
|
||||
`assert(expect<int>{100} == expect<short>{100});`). Comparisons can also be
|
||||
done against `std::error_code` objects or error code enums directly (i.e.
|
||||
`assert(expect<int>{make_error_code(common_error::kInvalidArgument)} == error::kInvalidArgument)`).
|
||||
Comparison of default constructed `std::error_code` will always fail.
|
||||
"Generic" comparisons can be done with `std::error_condition` via the `matches`
|
||||
method only (i.e.
|
||||
`assert(expect<int>{make_error_code{common_error::kInvalidErrorCode}.matches(std::errc::invalid_argument))`),
|
||||
`operator==` and `operator!=` will not work with `std::errc` or
|
||||
`std::error_condition`. A comparison with `matches` is more expensive
|
||||
because an equivalency between error categories is computed, but is
|
||||
recommended when an error can be one of several categories (this is going
|
||||
to be the case in nearly every situation when calling a function from
|
||||
another C++ struct/class).
|
||||
|
||||
`expect<void>` is a special case with no stored value. It is used by
|
||||
functions that can fail, but otherwise would return `void`. It is useful
|
||||
for consistency; all macros, standalone functions, and comparison operators
|
||||
work with `expect<void>`.
|
||||
|
||||
\note See `src/common/error.h` for creating a custom error enum.
|
||||
*/
|
||||
template<typename T>
|
||||
class expect
|
||||
{
|
||||
static_assert(std::is_nothrow_destructible<T>(), "T must have a nothrow destructor");
|
||||
|
||||
template<typename U>
|
||||
static constexpr bool is_convertible() noexcept
|
||||
{
|
||||
return std::is_constructible<T, U>() &&
|
||||
std::is_convertible<U, T>();
|
||||
}
|
||||
|
||||
// MEMBERS
|
||||
std::error_code code_;
|
||||
typename std::aligned_storage<sizeof(T), alignof(T)>::type storage_;
|
||||
// MEMBERS
|
||||
|
||||
T& get() noexcept
|
||||
{
|
||||
assert(has_value());
|
||||
return *reinterpret_cast<T*>(std::addressof(storage_));
|
||||
}
|
||||
|
||||
T const& get() const noexcept
|
||||
{
|
||||
assert(has_value());
|
||||
return *reinterpret_cast<T const*>(std::addressof(storage_));
|
||||
}
|
||||
|
||||
template<typename U>
|
||||
void store(U&& value) noexcept(std::is_nothrow_constructible<T, U>())
|
||||
{
|
||||
new (std::addressof(storage_)) T{std::forward<U>(value)};
|
||||
code_ = std::error_code{};
|
||||
}
|
||||
|
||||
void maybe_throw() const
|
||||
{
|
||||
if (has_error())
|
||||
::detail::expect::throw_(error(), nullptr, nullptr, 0);
|
||||
}
|
||||
|
||||
public:
|
||||
using value_type = T;
|
||||
using error_type = std::error_code;
|
||||
|
||||
expect() = delete;
|
||||
|
||||
/*! Store an error, `code`, in the `expect` object. If `code` creates a
|
||||
`std::error_code` object whose `.value() == 0`, then `error()` will be set
|
||||
to `::common_error::kInvalidErrorCode`. */
|
||||
expect(std::error_code const& code) noexcept
|
||||
: code_(code), storage_()
|
||||
{
|
||||
if (!has_error())
|
||||
code_ = ::common_error::kInvalidErrorCode;
|
||||
}
|
||||
|
||||
//! Store a value, `val`, in the `expect` object.
|
||||
expect(T val) noexcept(std::is_nothrow_move_constructible<T>())
|
||||
: code_(), storage_()
|
||||
{
|
||||
store(std::move(val));
|
||||
}
|
||||
|
||||
expect(expect const& src) noexcept(std::is_nothrow_copy_constructible<T>())
|
||||
: code_(src.error()), storage_()
|
||||
{
|
||||
if (src.has_value())
|
||||
store(src.get());
|
||||
}
|
||||
|
||||
//! Copy conversion from `U` to `T`.
|
||||
template<typename U, typename = detail::enable_if<is_convertible<U const&>()>>
|
||||
expect(expect<U> const& src) noexcept(std::is_nothrow_constructible<T, U const&>())
|
||||
: code_(src.error()), storage_()
|
||||
{
|
||||
if (src.has_value())
|
||||
store(*src);
|
||||
}
|
||||
|
||||
expect(expect&& src) noexcept(std::is_nothrow_move_constructible<T>())
|
||||
: code_(src.error()), storage_()
|
||||
{
|
||||
if (src.has_value())
|
||||
store(std::move(src.get()));
|
||||
}
|
||||
|
||||
//! Move conversion from `U` to `T`.
|
||||
template<typename U, typename = detail::enable_if<is_convertible<U>()>>
|
||||
expect(expect<U>&& src) noexcept(std::is_nothrow_constructible<T, U>())
|
||||
: code_(src.error()), storage_()
|
||||
{
|
||||
if (src.has_value())
|
||||
store(std::move(*src));
|
||||
}
|
||||
|
||||
~expect() noexcept
|
||||
{
|
||||
if (has_value())
|
||||
get().~T();
|
||||
}
|
||||
|
||||
expect& operator=(expect const& src) noexcept(std::is_nothrow_copy_constructible<T>() && std::is_nothrow_copy_assignable<T>())
|
||||
{
|
||||
if (this != std::addressof(src))
|
||||
{
|
||||
if (has_value() && src.has_value())
|
||||
get() = src.get();
|
||||
else if (has_value())
|
||||
get().~T();
|
||||
else if (src.has_value())
|
||||
store(src.get());
|
||||
code_ = src.error();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*! Move `src` into `this`. If `src.has_value() && addressof(src) != this`
|
||||
then `src.value() will be in a "moved from state". */
|
||||
expect& operator=(expect&& src) noexcept(std::is_nothrow_move_constructible<T>() && std::is_nothrow_move_assignable<T>())
|
||||
{
|
||||
if (this != std::addressof(src))
|
||||
{
|
||||
if (has_value() && src.has_value())
|
||||
get() = std::move(src.get());
|
||||
else if (has_value())
|
||||
get().~T();
|
||||
else if (src.has_value())
|
||||
store(std::move(src.get()));
|
||||
code_ = src.error();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! \return True if `this` is storing a value instead of an error.
|
||||
explicit operator bool() const noexcept { return has_value(); }
|
||||
|
||||
//! \return True if `this` is storing an error instead of a value.
|
||||
bool has_error() const noexcept { return bool(code_); }
|
||||
|
||||
//! \return True if `this` is storing a value instead of an error.
|
||||
bool has_value() const noexcept { return !has_error(); }
|
||||
|
||||
//! \return Error - always safe to call. Empty when `!has_error()`.
|
||||
std::error_code error() const noexcept { return code_; }
|
||||
|
||||
//! \return Value if `has_value()` otherwise \throw `std::system_error{error()}`.
|
||||
T& value() &
|
||||
{
|
||||
maybe_throw();
|
||||
return get();
|
||||
}
|
||||
|
||||
//! \return Value if `has_value()` otherwise \throw `std::system_error{error()}`.
|
||||
T const& value() const &
|
||||
{
|
||||
maybe_throw();
|
||||
return get();
|
||||
}
|
||||
|
||||
/*! Same as other overloads, but expressions such as `foo(bar().value())`
|
||||
will automatically perform moves with no copies. */
|
||||
T&& value() &&
|
||||
{
|
||||
maybe_throw();
|
||||
return std::move(get());
|
||||
}
|
||||
|
||||
//! \return Value, \pre `has_value()`.
|
||||
T* operator->() noexcept { return std::addressof(get()); }
|
||||
//! \return Value, \pre `has_value()`.
|
||||
T const* operator->() const noexcept { return std::addressof(get()); }
|
||||
//! \return Value, \pre `has_value()`.
|
||||
T& operator*() noexcept { return get(); }
|
||||
//! \return Value, \pre `has_value()`.
|
||||
T const& operator*() const noexcept { return get(); }
|
||||
|
||||
/*!
|
||||
\note This function is `noexcept` when `U == T` is `noexcept`.
|
||||
\return True if `has_value() == rhs.has_value()` and if values or errors are equal.
|
||||
*/
|
||||
template<typename U>
|
||||
bool equal(expect<U> const& rhs) const noexcept(noexcept(*std::declval<expect<T>>() == *rhs))
|
||||
{
|
||||
return has_value() && rhs.has_value() ?
|
||||
get() == *rhs : error() == rhs.error();
|
||||
}
|
||||
|
||||
//! \return False if `has_value()`, otherwise `error() == rhs`.
|
||||
bool equal(std::error_code const& rhs) const noexcept
|
||||
{
|
||||
return has_error() && error() == rhs;
|
||||
}
|
||||
|
||||
/*!
|
||||
\note This function is `noexcept` when `U == T` is `noexcept`.
|
||||
\return False if `has_error()`, otherwise `value() == rhs`.
|
||||
*/
|
||||
template<typename U, typename = detail::enable_if<!std::is_constructible<std::error_code, U>::value>>
|
||||
bool equal(U const& rhs) const noexcept(noexcept(*std::declval<expect<T>>() == rhs))
|
||||
{
|
||||
return has_value() && get() == rhs;
|
||||
}
|
||||
|
||||
//! \return False if `has_value()`, otherwise `error() == rhs`.
|
||||
bool matches(std::error_condition const& rhs) const noexcept
|
||||
{
|
||||
return has_error() && error() == rhs;
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
class expect<void>
|
||||
{
|
||||
std::error_code code_;
|
||||
|
||||
public:
|
||||
using value_type = void;
|
||||
using error_type = std::error_code;
|
||||
|
||||
//! Create a successful object.
|
||||
expect() noexcept
|
||||
: code_()
|
||||
{}
|
||||
|
||||
expect(std::error_code const& code) noexcept
|
||||
: code_(code)
|
||||
{
|
||||
if (!has_error())
|
||||
code_ = ::common_error::kInvalidErrorCode;
|
||||
}
|
||||
|
||||
expect(expect const&) = default;
|
||||
~expect() = default;
|
||||
expect& operator=(expect const&) = default;
|
||||
|
||||
//! \return True if `this` is storing a value instead of an error.
|
||||
explicit operator bool() const noexcept { return !has_error(); }
|
||||
|
||||
//! \return True if `this` is storing an error instead of a value.
|
||||
bool has_error() const noexcept { return bool(code_); }
|
||||
|
||||
//! \return Error - alway
|
||||
std::error_code error() const noexcept { return code_; }
|
||||
|
||||
//! \return `error() == rhs.error()`.
|
||||
bool equal(expect const& rhs) const noexcept
|
||||
{
|
||||
return error() == rhs.error();
|
||||
}
|
||||
|
||||
//! \return `has_error() && error() == rhs`.
|
||||
bool equal(std::error_code const& rhs) const noexcept
|
||||
{
|
||||
return has_error() && error() == rhs;
|
||||
}
|
||||
|
||||
//! \return False if `has_value()`, otherwise `error() == rhs`.
|
||||
bool matches(std::error_condition const& rhs) const noexcept
|
||||
{
|
||||
return has_error() && error() == rhs;
|
||||
}
|
||||
};
|
||||
|
||||
//! \return An `expect<void>` object with `!has_error()`.
|
||||
inline expect<void> success() noexcept { return expect<void>{}; }
|
||||
|
||||
template<typename T, typename U>
|
||||
inline
|
||||
bool operator==(expect<T> const& lhs, expect<U> const& rhs) noexcept(noexcept(lhs.equal(rhs)))
|
||||
{
|
||||
return lhs.equal(rhs);
|
||||
}
|
||||
|
||||
template<typename T, typename U>
|
||||
inline
|
||||
bool operator==(expect<T> const& lhs, U const& rhs) noexcept(noexcept(lhs.equal(rhs)))
|
||||
{
|
||||
return lhs.equal(rhs);
|
||||
}
|
||||
|
||||
template<typename T, typename U>
|
||||
inline
|
||||
bool operator==(T const& lhs, expect<U> const& rhs) noexcept(noexcept(rhs.equal(lhs)))
|
||||
{
|
||||
return rhs.equal(lhs);
|
||||
}
|
||||
|
||||
template<typename T, typename U>
|
||||
inline
|
||||
bool operator!=(expect<T> const& lhs, expect<U> const& rhs) noexcept(noexcept(lhs.equal(rhs)))
|
||||
{
|
||||
return !lhs.equal(rhs);
|
||||
}
|
||||
|
||||
template<typename T, typename U>
|
||||
inline
|
||||
bool operator!=(expect<T> const& lhs, U const& rhs) noexcept(noexcept(lhs.equal(rhs)))
|
||||
{
|
||||
return !lhs.equal(rhs);
|
||||
}
|
||||
|
||||
template<typename T, typename U>
|
||||
inline
|
||||
bool operator!=(T const& lhs, expect<U> const& rhs) noexcept(noexcept(rhs.equal(lhs)))
|
||||
{
|
||||
return !rhs.equal(lhs);
|
||||
}
|
||||
|
||||
namespace detail
|
||||
{
|
||||
inline void expect::unwrap(::expect<void>&& result, const char* error_msg, const char* file, unsigned line)
|
||||
{
|
||||
if (!result)
|
||||
throw_(result.error(), error_msg, file, line);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,14 +29,14 @@
|
||||
#pragma once
|
||||
|
||||
#define GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, name, type, jtype, mandatory, def) \
|
||||
type field_##name = def; \
|
||||
type field_##name = static_cast<type>(def); \
|
||||
bool field_##name##_found = false; \
|
||||
(void)field_##name##_found; \
|
||||
do if (json.HasMember(#name)) \
|
||||
{ \
|
||||
if (json[#name].Is##jtype()) \
|
||||
{ \
|
||||
field_##name = json[#name].Get##jtype(); \
|
||||
field_##name = static_cast<type>(json[#name].Get##jtype()); \
|
||||
field_##name##_found = true; \
|
||||
} \
|
||||
else \
|
||||
|
||||
78
src/common/notify.cpp
Normal file
78
src/common/notify.cpp
Normal file
@@ -0,0 +1,78 @@
|
||||
// Copyright (c) 2018, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <stdarg.h>
|
||||
#include "misc_log_ex.h"
|
||||
#include "file_io_utils.h"
|
||||
#include "spawn.h"
|
||||
#include "notify.h"
|
||||
|
||||
namespace tools
|
||||
{
|
||||
|
||||
/*
|
||||
TODO:
|
||||
- Improve tokenization to handle paths containing whitespaces, quotes, etc.
|
||||
- Windows unicode support (implies implementing unicode command line parsing code)
|
||||
*/
|
||||
Notify::Notify(const char *spec)
|
||||
{
|
||||
CHECK_AND_ASSERT_THROW_MES(spec, "Null spec");
|
||||
|
||||
boost::split(args, spec, boost::is_any_of(" \t"), boost::token_compress_on);
|
||||
CHECK_AND_ASSERT_THROW_MES(args.size() > 0, "Failed to parse spec");
|
||||
filename = args[0];
|
||||
CHECK_AND_ASSERT_THROW_MES(epee::file_io_utils::is_file_exist(filename), "File not found: " << filename);
|
||||
}
|
||||
|
||||
static void replace(std::vector<std::string> &v, const char *tag, const char *s)
|
||||
{
|
||||
for (std::string &str: v)
|
||||
boost::replace_all(str, tag, s);
|
||||
}
|
||||
|
||||
int Notify::notify(const char *tag, const char *s, ...)
|
||||
{
|
||||
std::vector<std::string> margs = args;
|
||||
|
||||
replace(margs, tag, s);
|
||||
|
||||
va_list ap;
|
||||
va_start(ap, s);
|
||||
while ((tag = va_arg(ap, const char*)))
|
||||
{
|
||||
s = va_arg(ap, const char*);
|
||||
replace(margs, tag, s);
|
||||
}
|
||||
va_end(ap);
|
||||
|
||||
return tools::spawn(filename.c_str(), margs, false);
|
||||
}
|
||||
|
||||
}
|
||||
49
src/common/notify.h
Normal file
49
src/common/notify.h
Normal file
@@ -0,0 +1,49 @@
|
||||
// Copyright (c) 2018, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace tools
|
||||
{
|
||||
|
||||
class Notify
|
||||
{
|
||||
public:
|
||||
Notify(const char *spec);
|
||||
|
||||
int notify(const char *tag, const char *s, ...);
|
||||
|
||||
private:
|
||||
std::string filename;
|
||||
std::vector<std::string> args;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -54,45 +54,61 @@ namespace
|
||||
return 0 != _isatty(_fileno(stdin));
|
||||
}
|
||||
|
||||
bool read_from_tty(epee::wipeable_string& pass)
|
||||
bool read_from_tty(epee::wipeable_string& pass, bool hide_input)
|
||||
{
|
||||
static constexpr const char BACKSPACE = 8;
|
||||
|
||||
HANDLE h_cin = ::GetStdHandle(STD_INPUT_HANDLE);
|
||||
|
||||
DWORD mode_old;
|
||||
::GetConsoleMode(h_cin, &mode_old);
|
||||
DWORD mode_new = mode_old & ~(ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT);
|
||||
DWORD mode_new = mode_old & ~(hide_input ? ENABLE_ECHO_INPUT : 0);
|
||||
::SetConsoleMode(h_cin, mode_new);
|
||||
|
||||
bool r = true;
|
||||
pass.reserve(tools::password_container::max_password_size);
|
||||
std::vector<int> chlen;
|
||||
chlen.reserve(tools::password_container::max_password_size);
|
||||
while (pass.size() < tools::password_container::max_password_size)
|
||||
{
|
||||
DWORD read;
|
||||
char ch;
|
||||
r = (TRUE == ::ReadConsoleA(h_cin, &ch, 1, &read, NULL));
|
||||
wchar_t ucs2_ch;
|
||||
r = (TRUE == ::ReadConsoleW(h_cin, &ucs2_ch, 1, &read, NULL));
|
||||
r &= (1 == read);
|
||||
|
||||
if (!r)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else if (ch == '\n' || ch == '\r')
|
||||
else if (ucs2_ch == L'\r')
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else if (ucs2_ch == L'\n')
|
||||
{
|
||||
std::cout << std::endl;
|
||||
break;
|
||||
}
|
||||
else if (ch == BACKSPACE)
|
||||
else if (ucs2_ch == L'\b')
|
||||
{
|
||||
if (!pass.empty())
|
||||
{
|
||||
pass.pop_back();
|
||||
int len = chlen.back();
|
||||
chlen.pop_back();
|
||||
while(len-- > 0)
|
||||
pass.pop_back();
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
pass.push_back(ch);
|
||||
}
|
||||
|
||||
char utf8_ch[8] = {0};
|
||||
int len;
|
||||
if((len = WideCharToMultiByte(CP_UTF8, 0, &ucs2_ch, 1, utf8_ch, sizeof(utf8_ch), NULL, NULL)) <= 0)
|
||||
break;
|
||||
|
||||
if(pass.size() + len >= tools::password_container::max_password_size)
|
||||
break;
|
||||
|
||||
chlen.push_back(len);
|
||||
pass += utf8_ch;
|
||||
}
|
||||
|
||||
::SetConsoleMode(h_cin, mode_old);
|
||||
@@ -107,14 +123,14 @@ namespace
|
||||
return 0 != isatty(fileno(stdin));
|
||||
}
|
||||
|
||||
int getch() noexcept
|
||||
int getch(bool hide_input) noexcept
|
||||
{
|
||||
struct termios tty_old;
|
||||
tcgetattr(STDIN_FILENO, &tty_old);
|
||||
|
||||
struct termios tty_new;
|
||||
tty_new = tty_old;
|
||||
tty_new.c_lflag &= ~(ICANON | ECHO);
|
||||
tty_new.c_lflag &= ~(ICANON | (hide_input ? ECHO : 0));
|
||||
tcsetattr(STDIN_FILENO, TCSANOW, &tty_new);
|
||||
|
||||
int ch = getchar();
|
||||
@@ -124,14 +140,14 @@ namespace
|
||||
return ch;
|
||||
}
|
||||
|
||||
bool read_from_tty(epee::wipeable_string& aPass)
|
||||
bool read_from_tty(epee::wipeable_string& aPass, bool hide_input)
|
||||
{
|
||||
static constexpr const char BACKSPACE = 127;
|
||||
|
||||
aPass.reserve(tools::password_container::max_password_size);
|
||||
while (aPass.size() < tools::password_container::max_password_size)
|
||||
{
|
||||
int ch = getch();
|
||||
int ch = getch(hide_input);
|
||||
if (EOF == ch || ch == EOT)
|
||||
{
|
||||
return false;
|
||||
@@ -146,6 +162,13 @@ namespace
|
||||
if (!aPass.empty())
|
||||
{
|
||||
aPass.pop_back();
|
||||
if (!hide_input)
|
||||
std::cout << "\b\b\b \b\b\b" << std::flush;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!hide_input)
|
||||
std::cout << "\b\b \b\b" << std::flush;
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -159,18 +182,18 @@ namespace
|
||||
|
||||
#endif // end !WIN32
|
||||
|
||||
bool read_from_tty(const bool verify, const char *message, epee::wipeable_string& pass1, epee::wipeable_string& pass2)
|
||||
bool read_from_tty(const bool verify, const char *message, bool hide_input, epee::wipeable_string& pass1, epee::wipeable_string& pass2)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (message)
|
||||
std::cout << message <<": " << std::flush;
|
||||
if (!read_from_tty(pass1))
|
||||
if (!read_from_tty(pass1, hide_input))
|
||||
return false;
|
||||
if (verify)
|
||||
{
|
||||
std::cout << "Confirm password: ";
|
||||
if (!read_from_tty(pass2))
|
||||
if (!read_from_tty(pass2, hide_input))
|
||||
return false;
|
||||
if(pass1!=pass2)
|
||||
{
|
||||
@@ -221,6 +244,10 @@ namespace tools
|
||||
: m_password(std::move(password))
|
||||
{
|
||||
}
|
||||
password_container::password_container(const epee::wipeable_string& password) noexcept
|
||||
: m_password(password)
|
||||
{
|
||||
}
|
||||
|
||||
password_container::~password_container() noexcept
|
||||
{
|
||||
@@ -229,12 +256,12 @@ namespace tools
|
||||
|
||||
std::atomic<bool> password_container::is_prompting(false);
|
||||
|
||||
boost::optional<password_container> password_container::prompt(const bool verify, const char *message)
|
||||
boost::optional<password_container> password_container::prompt(const bool verify, const char *message, bool hide_input)
|
||||
{
|
||||
is_prompting = true;
|
||||
password_container pass1{};
|
||||
password_container pass2{};
|
||||
if (is_cin_tty() ? read_from_tty(verify, message, pass1.m_password, pass2.m_password) : read_from_file(pass1.m_password))
|
||||
if (is_cin_tty() ? read_from_tty(verify, message, hide_input, pass1.m_password, pass2.m_password) : read_from_file(pass1.m_password))
|
||||
{
|
||||
is_prompting = false;
|
||||
return {std::move(pass1)};
|
||||
|
||||
@@ -47,9 +47,10 @@ namespace tools
|
||||
|
||||
//! `password` is used as password
|
||||
password_container(std::string&& password) noexcept;
|
||||
password_container(const epee::wipeable_string& password) noexcept;
|
||||
|
||||
//! \return A password from stdin TTY prompt or `std::cin` pipe.
|
||||
static boost::optional<password_container> prompt(bool verify, const char *mesage = "Password");
|
||||
static boost::optional<password_container> prompt(bool verify, const char *mesage = "Password", bool hide_input = true);
|
||||
static std::atomic<bool> is_prompting;
|
||||
|
||||
password_container(const password_container&) = delete;
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
#undef MONERO_DEFAULT_LOG_CATEGORY
|
||||
#define MONERO_DEFAULT_LOG_CATEGORY "perf"
|
||||
|
||||
namespace
|
||||
namespace tools
|
||||
{
|
||||
uint64_t get_tick_count()
|
||||
{
|
||||
@@ -83,7 +83,7 @@ namespace tools
|
||||
|
||||
el::Level performance_timer_log_level = el::Level::Debug;
|
||||
|
||||
static __thread std::vector<PerformanceTimer*> *performance_timers = NULL;
|
||||
static __thread std::vector<LoggingPerformanceTimer*> *performance_timers = NULL;
|
||||
|
||||
void set_performance_timer_log_level(el::Level level)
|
||||
{
|
||||
@@ -96,17 +96,24 @@ void set_performance_timer_log_level(el::Level level)
|
||||
performance_timer_log_level = level;
|
||||
}
|
||||
|
||||
PerformanceTimer::PerformanceTimer(const std::string &s, uint64_t unit, el::Level l): name(s), unit(unit), level(l), started(false), paused(false)
|
||||
PerformanceTimer::PerformanceTimer(bool paused): started(true), paused(paused)
|
||||
{
|
||||
if (paused)
|
||||
ticks = 0;
|
||||
else
|
||||
ticks = get_tick_count();
|
||||
}
|
||||
|
||||
LoggingPerformanceTimer::LoggingPerformanceTimer(const std::string &s, uint64_t unit, el::Level l): PerformanceTimer(), name(s), unit(unit), level(l)
|
||||
{
|
||||
ticks = get_tick_count();
|
||||
if (!performance_timers)
|
||||
{
|
||||
MLOG(level, "PERF ----------");
|
||||
performance_timers = new std::vector<PerformanceTimer*>();
|
||||
performance_timers = new std::vector<LoggingPerformanceTimer*>();
|
||||
}
|
||||
else
|
||||
{
|
||||
PerformanceTimer *pt = performance_timers->back();
|
||||
LoggingPerformanceTimer *pt = performance_timers->back();
|
||||
if (!pt->started && !pt->paused)
|
||||
{
|
||||
size_t size = 0; for (const auto *tmp: *performance_timers) if (!tmp->paused) ++size;
|
||||
@@ -119,9 +126,14 @@ PerformanceTimer::PerformanceTimer(const std::string &s, uint64_t unit, el::Leve
|
||||
|
||||
PerformanceTimer::~PerformanceTimer()
|
||||
{
|
||||
performance_timers->pop_back();
|
||||
if (!paused)
|
||||
ticks = get_tick_count() - ticks;
|
||||
}
|
||||
|
||||
LoggingPerformanceTimer::~LoggingPerformanceTimer()
|
||||
{
|
||||
pause();
|
||||
performance_timers->pop_back();
|
||||
char s[12];
|
||||
snprintf(s, sizeof(s), "%8llu ", (unsigned long long)(ticks_to_ns(ticks) / (1000000000 / unit)));
|
||||
size_t size = 0; for (const auto *tmp: *performance_timers) if (!tmp->paused || tmp==this) ++size;
|
||||
|
||||
@@ -43,30 +43,46 @@ class PerformanceTimer;
|
||||
|
||||
extern el::Level performance_timer_log_level;
|
||||
|
||||
uint64_t get_tick_count();
|
||||
uint64_t get_ticks_per_ns();
|
||||
uint64_t ticks_to_ns(uint64_t ticks);
|
||||
|
||||
class PerformanceTimer
|
||||
{
|
||||
public:
|
||||
PerformanceTimer(const std::string &s, uint64_t unit, el::Level l = el::Level::Debug);
|
||||
PerformanceTimer(bool paused = false);
|
||||
~PerformanceTimer();
|
||||
void pause();
|
||||
void resume();
|
||||
|
||||
private:
|
||||
std::string name;
|
||||
uint64_t unit;
|
||||
el::Level level;
|
||||
uint64_t value() const { return ticks; }
|
||||
void set(uint64_t v){ticks=v;}
|
||||
|
||||
protected:
|
||||
uint64_t ticks;
|
||||
bool started;
|
||||
bool paused;
|
||||
};
|
||||
|
||||
class LoggingPerformanceTimer: public PerformanceTimer
|
||||
{
|
||||
public:
|
||||
LoggingPerformanceTimer(const std::string &s, uint64_t unit, el::Level l = el::Level::Debug);
|
||||
~LoggingPerformanceTimer();
|
||||
|
||||
private:
|
||||
std::string name;
|
||||
uint64_t unit;
|
||||
el::Level level;
|
||||
};
|
||||
|
||||
void set_performance_timer_log_level(el::Level level);
|
||||
|
||||
#define PERF_TIMER_UNIT(name, unit) tools::PerformanceTimer pt_##name(#name, unit, tools::performance_timer_log_level)
|
||||
#define PERF_TIMER_UNIT_L(name, unit, l) tools::PerformanceTimer pt_##name(#name, unit, l)
|
||||
#define PERF_TIMER_UNIT(name, unit) tools::LoggingPerformanceTimer pt_##name(#name, unit, tools::performance_timer_log_level)
|
||||
#define PERF_TIMER_UNIT_L(name, unit, l) tools::LoggingPerformanceTimer pt_##name(#name, unit, l)
|
||||
#define PERF_TIMER(name) PERF_TIMER_UNIT(name, 1000)
|
||||
#define PERF_TIMER_L(name, l) PERF_TIMER_UNIT_L(name, 1000, l)
|
||||
#define PERF_TIMER_START_UNIT(name, unit) std::unique_ptr<tools::PerformanceTimer> pt_##name(new tools::PerformanceTimer(#name, unit, el::Level::Info))
|
||||
#define PERF_TIMER_START_UNIT(name, unit) std::unique_ptr<tools::LoggingPerformanceTimer> pt_##name(new tools::LoggingPerformanceTimer(#name, unit, el::Level::Info))
|
||||
#define PERF_TIMER_START(name) PERF_TIMER_START_UNIT(name, 1000)
|
||||
#define PERF_TIMER_STOP(name) do { pt_##name.reset(NULL); } while(0)
|
||||
#define PERF_TIMER_PAUSE(name) pt_##name->pause()
|
||||
|
||||
@@ -73,7 +73,7 @@ public:
|
||||
#if defined(_MSC_VER)
|
||||
, m_oss(std::move(rhs.m_oss))
|
||||
#else
|
||||
// GCC bug: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=54316
|
||||
// GCC bug: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=54316
|
||||
, m_oss(rhs.m_oss.str(), std::ios_base::out | std::ios_base::ate)
|
||||
#endif
|
||||
, m_color(std::move(rhs.m_color))
|
||||
|
||||
148
src/common/spawn.cpp
Normal file
148
src/common/spawn.cpp
Normal file
@@ -0,0 +1,148 @@
|
||||
// Copyright (c) 2018, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#ifdef _WIN32
|
||||
#include <boost/algorithm/string/join.hpp>
|
||||
#include <boost/scope_exit.hpp>
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <sys/wait.h>
|
||||
#include <signal.h>
|
||||
#endif
|
||||
|
||||
#include "misc_log_ex.h"
|
||||
#include "util.h"
|
||||
#include "spawn.h"
|
||||
|
||||
namespace tools
|
||||
{
|
||||
|
||||
int spawn(const char *filename, const std::vector<std::string>& args, bool wait)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
std::string joined = boost::algorithm::join(args, " ");
|
||||
char *commandLine = !joined.empty() ? &joined[0] : nullptr;
|
||||
STARTUPINFOA si = {};
|
||||
si.cb = sizeof(si);
|
||||
PROCESS_INFORMATION pi;
|
||||
if (!CreateProcessA(filename, commandLine, nullptr, nullptr, false, 0, nullptr, nullptr, &si, &pi))
|
||||
{
|
||||
MERROR("CreateProcess failed. Error code " << GetLastError());
|
||||
return -1;
|
||||
}
|
||||
|
||||
BOOST_SCOPE_EXIT(&pi)
|
||||
{
|
||||
CloseHandle(pi.hThread);
|
||||
CloseHandle(pi.hProcess);
|
||||
}
|
||||
BOOST_SCOPE_EXIT_END
|
||||
|
||||
if (!wait)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
DWORD result = WaitForSingleObject(pi.hProcess, INFINITE);
|
||||
if (result != WAIT_OBJECT_0)
|
||||
{
|
||||
MERROR("WaitForSingleObject failed. Result " << result << ", error code " << GetLastError());
|
||||
return -1;
|
||||
}
|
||||
|
||||
DWORD exitCode;
|
||||
if (!GetExitCodeProcess(pi.hProcess, &exitCode))
|
||||
{
|
||||
MERROR("GetExitCodeProcess failed. Error code " << GetLastError());
|
||||
return -1;
|
||||
}
|
||||
|
||||
MINFO("Child exited with " << exitCode);
|
||||
return static_cast<int>(exitCode);
|
||||
#else
|
||||
char **argv = (char**)alloca(sizeof(char*) * (args.size() + 1));
|
||||
for (size_t n = 0; n < args.size(); ++n)
|
||||
argv[n] = (char*)args[n].c_str();
|
||||
argv[args.size()] = NULL;
|
||||
|
||||
pid_t pid = fork();
|
||||
if (pid < 0)
|
||||
{
|
||||
MERROR("Error forking: " << strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
// child
|
||||
if (pid == 0)
|
||||
{
|
||||
tools::closefrom(3);
|
||||
close(0);
|
||||
char *envp[] = {NULL};
|
||||
execve(filename, argv, envp);
|
||||
MERROR("Failed to execve: " << strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
// parent
|
||||
if (pid > 0)
|
||||
{
|
||||
if (!wait)
|
||||
{
|
||||
signal(SIGCHLD, SIG_IGN);
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (1)
|
||||
{
|
||||
int wstatus = 0;
|
||||
pid_t w = waitpid(pid, &wstatus, WUNTRACED | WCONTINUED);
|
||||
if (w < 0) {
|
||||
MERROR("Error waiting for child: " << strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
if (WIFEXITED(wstatus))
|
||||
{
|
||||
MINFO("Child exited with " << WEXITSTATUS(wstatus));
|
||||
return WEXITSTATUS(wstatus);
|
||||
}
|
||||
if (WIFSIGNALED(wstatus))
|
||||
{
|
||||
MINFO("Child killed by " << WEXITSTATUS(wstatus));
|
||||
return WEXITSTATUS(wstatus);
|
||||
}
|
||||
}
|
||||
}
|
||||
MERROR("Secret passage found");
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
36
src/common/spawn.h
Normal file
36
src/common/spawn.h
Normal file
@@ -0,0 +1,36 @@
|
||||
// Copyright (c) 2018, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace tools
|
||||
{
|
||||
|
||||
int spawn(const char *filename, const std::vector<std::string>& args, bool wait);
|
||||
|
||||
}
|
||||
@@ -49,9 +49,18 @@
|
||||
#undef MONERO_DEFAULT_LOG_CATEGORY
|
||||
#define MONERO_DEFAULT_LOG_CATEGORY "stacktrace"
|
||||
|
||||
#define ST_LOG(x) CINFO(el::base::Writer,el::base::DispatchAction::FileOnlyLog,MONERO_DEFAULT_LOG_CATEGORY) << x
|
||||
#define ST_LOG(x) \
|
||||
do { \
|
||||
auto elpp = ELPP; \
|
||||
if (elpp) { \
|
||||
CINFO(el::base::Writer,el::base::DispatchAction::FileOnlyLog,MONERO_DEFAULT_LOG_CATEGORY) << x; \
|
||||
} \
|
||||
else { \
|
||||
std::cout << x << std::endl; \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
// from http://stackoverflow.com/questions/11665829/how-can-i-print-stack-trace-for-caught-exceptions-in-c-code-injection-in-c
|
||||
// from https://stackoverflow.com/questions/11665829/how-can-i-print-stack-trace-for-caught-exceptions-in-c-code-injection-in-c
|
||||
|
||||
// The decl of __cxa_throw in /usr/include/.../cxxabi.h uses
|
||||
// 'std::type_info *', but GCC's built-in protype uses 'void *'.
|
||||
|
||||
@@ -36,16 +36,17 @@
|
||||
#include "common/util.h"
|
||||
|
||||
static __thread int depth = 0;
|
||||
static __thread bool is_leaf = false;
|
||||
|
||||
namespace tools
|
||||
{
|
||||
threadpool::threadpool() : running(true), active(0) {
|
||||
threadpool::threadpool(unsigned int max_threads) : running(true), active(0) {
|
||||
boost::thread::attributes attrs;
|
||||
attrs.set_stack_size(THREAD_STACK_SIZE);
|
||||
max = tools::get_max_concurrency();
|
||||
size_t i = max;
|
||||
max = max_threads ? max_threads : tools::get_max_concurrency();
|
||||
size_t i = max ? max - 1 : 0;
|
||||
while(i--) {
|
||||
threads.push_back(boost::thread(attrs, boost::bind(&threadpool::run, this)));
|
||||
threads.push_back(boost::thread(attrs, boost::bind(&threadpool::run, this, false)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,29 +57,35 @@ threadpool::~threadpool() {
|
||||
has_work.notify_all();
|
||||
}
|
||||
for (size_t i = 0; i<threads.size(); i++) {
|
||||
threads[i].join();
|
||||
try { threads[i].join(); }
|
||||
catch (...) { /* ignore */ }
|
||||
}
|
||||
}
|
||||
|
||||
void threadpool::submit(waiter *obj, std::function<void()> f) {
|
||||
entry e = {obj, f};
|
||||
void threadpool::submit(waiter *obj, std::function<void()> f, bool leaf) {
|
||||
CHECK_AND_ASSERT_THROW_MES(!is_leaf, "A leaf routine is using a thread pool");
|
||||
boost::unique_lock<boost::mutex> lock(mutex);
|
||||
if ((active == max && !queue.empty()) || depth > 0) {
|
||||
if (!leaf && ((active == max && !queue.empty()) || depth > 0)) {
|
||||
// if all available threads are already running
|
||||
// and there's work waiting, just run in current thread
|
||||
lock.unlock();
|
||||
++depth;
|
||||
is_leaf = leaf;
|
||||
f();
|
||||
--depth;
|
||||
is_leaf = false;
|
||||
} else {
|
||||
if (obj)
|
||||
obj->inc();
|
||||
queue.push_back(e);
|
||||
if (leaf)
|
||||
queue.push_front({obj, f, leaf});
|
||||
else
|
||||
queue.push_back({obj, f, leaf});
|
||||
has_work.notify_one();
|
||||
}
|
||||
}
|
||||
|
||||
int threadpool::get_max_concurrency() {
|
||||
unsigned int threadpool::get_max_concurrency() const {
|
||||
return max;
|
||||
}
|
||||
|
||||
@@ -91,7 +98,7 @@ threadpool::waiter::~waiter()
|
||||
}
|
||||
try
|
||||
{
|
||||
wait();
|
||||
wait(NULL);
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
@@ -99,9 +106,12 @@ threadpool::waiter::~waiter()
|
||||
}
|
||||
}
|
||||
|
||||
void threadpool::waiter::wait() {
|
||||
void threadpool::waiter::wait(threadpool *tpool) {
|
||||
if (tpool)
|
||||
tpool->run(true);
|
||||
boost::unique_lock<boost::mutex> lock(mt);
|
||||
while(num) cv.wait(lock);
|
||||
while(num)
|
||||
cv.wait(lock);
|
||||
}
|
||||
|
||||
void threadpool::waiter::inc() {
|
||||
@@ -113,15 +123,19 @@ void threadpool::waiter::dec() {
|
||||
const boost::unique_lock<boost::mutex> lock(mt);
|
||||
num--;
|
||||
if (!num)
|
||||
cv.notify_one();
|
||||
cv.notify_all();
|
||||
}
|
||||
|
||||
void threadpool::run() {
|
||||
void threadpool::run(bool flush) {
|
||||
boost::unique_lock<boost::mutex> lock(mutex);
|
||||
while (running) {
|
||||
entry e;
|
||||
while(queue.empty() && running)
|
||||
{
|
||||
if (flush)
|
||||
return;
|
||||
has_work.wait(lock);
|
||||
}
|
||||
if (!running) break;
|
||||
|
||||
active++;
|
||||
@@ -129,8 +143,10 @@ void threadpool::run() {
|
||||
queue.pop_front();
|
||||
lock.unlock();
|
||||
++depth;
|
||||
is_leaf = e.leaf;
|
||||
e.f();
|
||||
--depth;
|
||||
is_leaf = false;
|
||||
|
||||
if (e.wo)
|
||||
e.wo->dec();
|
||||
|
||||
@@ -46,6 +46,9 @@ public:
|
||||
static threadpool instance;
|
||||
return instance;
|
||||
}
|
||||
static threadpool *getNewForUnitTests(unsigned max_threads = 0) {
|
||||
return new threadpool(max_threads);
|
||||
}
|
||||
|
||||
// The waiter lets the caller know when all of its
|
||||
// tasks are completed.
|
||||
@@ -56,7 +59,7 @@ public:
|
||||
public:
|
||||
void inc();
|
||||
void dec();
|
||||
void wait(); //! Wait for a set of tasks to finish.
|
||||
void wait(threadpool *tpool); //! Wait for a set of tasks to finish.
|
||||
waiter() : num(0){}
|
||||
~waiter();
|
||||
};
|
||||
@@ -64,25 +67,27 @@ public:
|
||||
// Submit a task to the pool. The waiter pointer may be
|
||||
// NULL if the caller doesn't care to wait for the
|
||||
// task to finish.
|
||||
void submit(waiter *waiter, std::function<void()> f);
|
||||
void submit(waiter *waiter, std::function<void()> f, bool leaf = false);
|
||||
|
||||
int get_max_concurrency();
|
||||
unsigned int get_max_concurrency() const;
|
||||
|
||||
~threadpool();
|
||||
|
||||
private:
|
||||
threadpool();
|
||||
~threadpool();
|
||||
threadpool(unsigned int max_threads = 0);
|
||||
typedef struct entry {
|
||||
waiter *wo;
|
||||
std::function<void()> f;
|
||||
bool leaf;
|
||||
} entry;
|
||||
std::deque<entry> queue;
|
||||
boost::condition_variable has_work;
|
||||
boost::mutex mutex;
|
||||
std::vector<boost::thread> threads;
|
||||
int active;
|
||||
int max;
|
||||
unsigned int active;
|
||||
unsigned int max;
|
||||
bool running;
|
||||
void run();
|
||||
void run(bool flush = false);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ namespace tools
|
||||
|
||||
MDEBUG("Checking updates for " << buildtag << " " << software);
|
||||
|
||||
// All four Wownero domains have DNSSEC on and valid
|
||||
// All four MoneroPulse domains have DNSSEC on and valid
|
||||
static const std::vector<std::string> dns_urls = {
|
||||
};
|
||||
|
||||
@@ -65,12 +65,12 @@ namespace tools
|
||||
continue;
|
||||
|
||||
bool alnum = true;
|
||||
for (auto c: hash)
|
||||
for (auto c: fields[3])
|
||||
if (!isalnum(c))
|
||||
alnum = false;
|
||||
if (hash.size() != 64 && !alnum)
|
||||
if (fields[3].size() != 64 && !alnum)
|
||||
{
|
||||
MWARNING("Invalid hash: " << hash);
|
||||
MWARNING("Invalid hash: " << fields[3]);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -95,7 +95,7 @@ namespace tools
|
||||
|
||||
std::string get_update_url(const std::string &software, const std::string &subdir, const std::string &buildtag, const std::string &version, bool user)
|
||||
{
|
||||
const char *base = user ? "https://downloads.getmonero.org/" : "https://updates.getmonero.org/";
|
||||
const char *base = user ? "" : "";
|
||||
#ifdef _WIN32
|
||||
static const char *extension = strncmp(buildtag.c_str(), "install-", 8) ? ".zip" : ".exe";
|
||||
#else
|
||||
|
||||
@@ -28,12 +28,31 @@
|
||||
//
|
||||
// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
|
||||
|
||||
#include <unistd.h>
|
||||
#include <cstdio>
|
||||
|
||||
#ifdef __GLIBC__
|
||||
#include <gnu/libc-version.h>
|
||||
#endif
|
||||
|
||||
#ifdef __GLIBC__
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/resource.h>
|
||||
#include <unistd.h>
|
||||
#include <dirent.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <string>
|
||||
#endif
|
||||
|
||||
//tools::is_hdd
|
||||
#ifdef __GLIBC__
|
||||
#include <sstream>
|
||||
#include <sys/sysmacros.h>
|
||||
#include <fstream>
|
||||
#endif
|
||||
|
||||
#include "unbound.h"
|
||||
|
||||
#include "include_base_utils.h"
|
||||
@@ -184,6 +203,73 @@ namespace tools
|
||||
catch (...) {}
|
||||
}
|
||||
|
||||
file_locker::file_locker(const std::string &filename)
|
||||
{
|
||||
#ifdef WIN32
|
||||
m_fd = INVALID_HANDLE_VALUE;
|
||||
std::wstring filename_wide;
|
||||
try
|
||||
{
|
||||
filename_wide = string_tools::utf8_to_utf16(filename);
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
MERROR("Failed to convert path \"" << filename << "\" to UTF-16: " << e.what());
|
||||
return;
|
||||
}
|
||||
m_fd = CreateFileW(filename_wide.c_str(), GENERIC_READ, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (m_fd != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
OVERLAPPED ov;
|
||||
memset(&ov, 0, sizeof(ov));
|
||||
if (!LockFileEx(m_fd, LOCKFILE_FAIL_IMMEDIATELY | LOCKFILE_EXCLUSIVE_LOCK, 0, 1, 0, &ov))
|
||||
{
|
||||
MERROR("Failed to lock " << filename << ": " << std::error_code(GetLastError(), std::system_category()));
|
||||
CloseHandle(m_fd);
|
||||
m_fd = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
MERROR("Failed to open " << filename << ": " << std::error_code(GetLastError(), std::system_category()));
|
||||
}
|
||||
#else
|
||||
m_fd = open(filename.c_str(), O_RDONLY | O_CREAT | O_CLOEXEC, 0666);
|
||||
if (m_fd != -1)
|
||||
{
|
||||
if (flock(m_fd, LOCK_EX | LOCK_NB) == -1)
|
||||
{
|
||||
MERROR("Failed to lock " << filename << ": " << std::strerror(errno));
|
||||
close(m_fd);
|
||||
m_fd = -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
MERROR("Failed to open " << filename << ": " << std::strerror(errno));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
file_locker::~file_locker()
|
||||
{
|
||||
if (locked())
|
||||
{
|
||||
#ifdef WIN32
|
||||
CloseHandle(m_fd);
|
||||
#else
|
||||
close(m_fd);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
bool file_locker::locked() const
|
||||
{
|
||||
#ifdef WIN32
|
||||
return m_fd != INVALID_HANDLE_VALUE;
|
||||
#else
|
||||
return m_fd != -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
std::string get_windows_version_display_string()
|
||||
{
|
||||
@@ -604,6 +690,21 @@ std::string get_nix_version_display_string()
|
||||
static void setup_crash_dump() {}
|
||||
#endif
|
||||
|
||||
bool disable_core_dumps()
|
||||
{
|
||||
#ifdef __GLIBC__
|
||||
// disable core dumps in release mode
|
||||
struct rlimit rlimit;
|
||||
rlimit.rlim_cur = rlimit.rlim_max = 0;
|
||||
if (setrlimit(RLIMIT_CORE, &rlimit))
|
||||
{
|
||||
MWARNING("Failed to disable core dumps");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
bool on_startup()
|
||||
{
|
||||
mlog_configure("", true);
|
||||
@@ -639,6 +740,44 @@ std::string get_nix_version_display_string()
|
||||
#endif
|
||||
}
|
||||
|
||||
boost::optional<bool> is_hdd(const char *file_path)
|
||||
{
|
||||
#ifdef __GLIBC__
|
||||
struct stat st;
|
||||
std::string prefix;
|
||||
if(stat(file_path, &st) == 0)
|
||||
{
|
||||
std::ostringstream s;
|
||||
s << "/sys/dev/block/" << major(st.st_dev) << ":" << minor(st.st_dev);
|
||||
prefix = s.str();
|
||||
}
|
||||
else
|
||||
{
|
||||
return boost::none;
|
||||
}
|
||||
std::string attr_path = prefix + "/queue/rotational";
|
||||
std::ifstream f(attr_path, std::ios_base::in);
|
||||
if(not f.is_open())
|
||||
{
|
||||
attr_path = prefix + "/../queue/rotational";
|
||||
f.open(attr_path, std::ios_base::in);
|
||||
if(not f.is_open())
|
||||
{
|
||||
return boost::none;
|
||||
}
|
||||
}
|
||||
unsigned short val = 0xdead;
|
||||
f >> val;
|
||||
if(not f.fail())
|
||||
{
|
||||
return (val == 1);
|
||||
}
|
||||
return boost::none;
|
||||
#else
|
||||
return boost::none;
|
||||
#endif
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
boost::mutex max_concurrency_lock;
|
||||
@@ -782,4 +921,70 @@ std::string get_nix_version_display_string()
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
std::string glob_to_regex(const std::string &val)
|
||||
{
|
||||
std::string newval;
|
||||
|
||||
bool escape = false;
|
||||
for (char c: val)
|
||||
{
|
||||
if (c == '*')
|
||||
newval += escape ? "*" : ".*";
|
||||
else if (c == '?')
|
||||
newval += escape ? "?" : ".";
|
||||
else if (c == '\\')
|
||||
newval += '\\', escape = !escape;
|
||||
else
|
||||
newval += c;
|
||||
}
|
||||
return newval;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
std::string input_line_win()
|
||||
{
|
||||
HANDLE hConIn = CreateFileW(L"CONIN$", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, 0, nullptr);
|
||||
DWORD oldMode;
|
||||
|
||||
FlushConsoleInputBuffer(hConIn);
|
||||
GetConsoleMode(hConIn, &oldMode);
|
||||
SetConsoleMode(hConIn, ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT | ENABLE_PROCESSED_INPUT);
|
||||
|
||||
wchar_t buffer[1024];
|
||||
DWORD read;
|
||||
|
||||
ReadConsoleW(hConIn, buffer, sizeof(buffer)/sizeof(wchar_t)-1, &read, nullptr);
|
||||
buffer[read] = 0;
|
||||
|
||||
SetConsoleMode(hConIn, oldMode);
|
||||
CloseHandle(hConIn);
|
||||
|
||||
int size_needed = WideCharToMultiByte(CP_UTF8, 0, buffer, -1, NULL, 0, NULL, NULL);
|
||||
std::string buf(size_needed, '\0');
|
||||
WideCharToMultiByte(CP_UTF8, 0, buffer, -1, &buf[0], size_needed, NULL, NULL);
|
||||
buf.pop_back(); //size_needed includes null that we needed to have space for
|
||||
return buf;
|
||||
}
|
||||
#endif
|
||||
|
||||
void closefrom(int fd)
|
||||
{
|
||||
#if defined __FreeBSD__ || defined __OpenBSD__ || defined __NetBSD__ || defined __DragonFly__
|
||||
::closefrom(fd);
|
||||
#else
|
||||
#if defined __GLIBC__
|
||||
const int sc_open_max = sysconf(_SC_OPEN_MAX);
|
||||
const int MAX_FDS = std::min(65536, sc_open_max);
|
||||
#else
|
||||
const int MAX_FDS = 65536;
|
||||
#endif
|
||||
while (fd < MAX_FDS)
|
||||
{
|
||||
close(fd);
|
||||
++fd;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -91,6 +91,20 @@ namespace tools
|
||||
const std::string& filename() const noexcept { return m_filename; }
|
||||
};
|
||||
|
||||
class file_locker
|
||||
{
|
||||
public:
|
||||
file_locker(const std::string &filename);
|
||||
~file_locker();
|
||||
bool locked() const;
|
||||
private:
|
||||
#ifdef WIN32
|
||||
HANDLE m_fd;
|
||||
#else
|
||||
int m_fd;
|
||||
#endif
|
||||
};
|
||||
|
||||
/*! \brief Returns the default data directory.
|
||||
*
|
||||
* \details Windows < Vista: C:\\Documents and Settings\\Username\\Application Data\\CRYPTONOTE_NAME
|
||||
@@ -135,6 +149,8 @@ namespace tools
|
||||
|
||||
bool sanitize_locale();
|
||||
|
||||
bool disable_core_dumps();
|
||||
|
||||
bool on_startup();
|
||||
|
||||
/*! \brief Defines a signal handler for win32 and *nix
|
||||
@@ -214,5 +230,14 @@ namespace tools
|
||||
bool sha256sum(const uint8_t *data, size_t len, crypto::hash &hash);
|
||||
bool sha256sum(const std::string &filename, crypto::hash &hash);
|
||||
|
||||
boost::optional<bool> is_hdd(const char *path);
|
||||
|
||||
boost::optional<std::pair<uint32_t, uint32_t>> parse_subaddress_lookahead(const std::string& str);
|
||||
|
||||
std::string glob_to_regex(const std::string &val);
|
||||
#ifdef _WIN32
|
||||
std::string input_line_win();
|
||||
#endif
|
||||
|
||||
void closefrom(int fd);
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
* The blake256_* and blake224_* functions are largely copied from
|
||||
* blake256_light.c and blake224_light.c from the BLAKE website:
|
||||
*
|
||||
* http://131002.net/blake/
|
||||
* https://131002.net/blake/
|
||||
*
|
||||
* The hmac_* functions implement HMAC-BLAKE-256 and HMAC-BLAKE-224.
|
||||
* HMAC is specified by RFC 2104.
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user