Compare commits
631 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3b9b1a8f14 | ||
|
|
a6c4b17303 | ||
|
|
678138f097 | ||
|
|
b4e4038fb5 | ||
|
|
7a8e5976bc | ||
|
|
938c8d8bcd | ||
|
|
3aefa2b960 | ||
|
|
10657d96c4 | ||
|
|
4d66e8d06d | ||
|
|
010cfb7d67 | ||
|
|
f9a8aac036 | ||
|
|
3d28823be7 | ||
|
|
492317abd7 | ||
|
|
ab22d5e278 | ||
|
|
ce5f704dd5 | ||
|
|
696dc05dda | ||
|
|
589083ad7a | ||
|
|
1fda997370 | ||
|
|
7c335e8764 | ||
|
|
5b1d33d5fa | ||
|
|
e435407080 | ||
|
|
b180be7526 | ||
|
|
90fb473d87 | ||
|
|
3650f2d51c | ||
|
|
3090324366 | ||
|
|
130901e820 | ||
|
|
801b8191ef | ||
|
|
469f9c26e7 | ||
|
|
b5f510ead7 | ||
|
|
b4f8bba843 | ||
|
|
2bb79614f6 | ||
|
|
c077dc652d | ||
|
|
1b6f2a3e92 | ||
|
|
9136c81f05 | ||
|
|
912e5599d9 | ||
|
|
ff0095ac5e | ||
|
|
bf9fedc4ee | ||
|
|
78ba54da6b | ||
|
|
c90e279ab5 | ||
|
|
215602de08 | ||
|
|
13b832f959 | ||
|
|
789bb9c852 | ||
|
|
aada1f547b | ||
|
|
60718225ac | ||
|
|
1a2fc03083 | ||
|
|
61e8baee0c | ||
|
|
dbc5f55da9 | ||
|
|
81b7698428 | ||
|
|
4ce4bad383 | ||
|
|
23d25a079b | ||
|
|
d19bdb642e | ||
|
|
2e0246a6c2 | ||
|
|
349098e7b2 | ||
|
|
dc3b1ecdd0 | ||
|
|
7fb33796b1 | ||
|
|
ec886ddefb | ||
|
|
4ded4181a6 | ||
|
|
60691d03e0 | ||
|
|
869fa399b1 | ||
|
|
7af953fd62 | ||
|
|
5acbcb0d57 | ||
|
|
7000c394b2 | ||
|
|
7c0d894ccf | ||
|
|
f092c10de5 | ||
|
|
7f5e6b3a0a | ||
|
|
5e9dc185a5 | ||
|
|
0e94ac0111 | ||
|
|
0b5bbf6048 | ||
|
|
14c9cbd40e | ||
|
|
c4466878cf | ||
|
|
c584221fa2 | ||
|
|
70ba050c06 | ||
|
|
f2281dc38a | ||
|
|
18a2e6265d | ||
|
|
0d593199d0 | ||
|
|
832c4a7565 | ||
|
|
34d22a35dd | ||
|
|
c880716f16 | ||
|
|
f20f4c74d2 | ||
|
|
1fdfa1e6c6 | ||
|
|
4ee49f03df | ||
|
|
52d5278a62 | ||
|
|
35a2b87174 | ||
|
|
664bb2becd | ||
|
|
8865b95818 | ||
|
|
03600dce97 | ||
|
|
8b607efc40 | ||
|
|
9f1af6b3e8 | ||
|
|
c0952ba44b | ||
|
|
9475a2e474 | ||
|
|
5baed0c158 | ||
|
|
97c259858c | ||
|
|
0f90696528 | ||
|
|
ac974a180d | ||
|
|
052380b8de | ||
|
|
23a29439c0 | ||
|
|
a8617e2862 | ||
|
|
6945a6b320 | ||
|
|
b375c9adbf | ||
|
|
88a727739b | ||
|
|
5f3ae4dee3 | ||
|
|
5cbe834024 | ||
|
|
eea5b86cc4 | ||
|
|
09c512abaa | ||
|
|
d42d816e7f | ||
|
|
17effd15ab | ||
|
|
9982eba188 | ||
|
|
aafe527d4a | ||
|
|
e4c53a460e | ||
|
|
ca01596a65 | ||
|
|
4f2415b483 | ||
|
|
f680eacdf2 | ||
|
|
f6dcca3ebb | ||
|
|
1a642fc624 | ||
|
|
c4469514db | ||
|
|
59daf95859 | ||
|
|
3a6e04ba15 | ||
|
|
b26f86d6ff | ||
|
|
570215acae | ||
|
|
a511264433 | ||
|
|
06f25d2b27 | ||
|
|
a3bd355b16 | ||
|
|
1c1cd8b164 | ||
|
|
a898109522 | ||
|
|
3694b10e22 | ||
|
|
39f25d20a8 | ||
|
|
61c1646b43 | ||
|
|
1b9396dcbb | ||
|
|
05be4b5b0e | ||
|
|
f8f8bf0fea | ||
|
|
6643b6a306 | ||
|
|
7036ab26d7 | ||
|
|
9b55169251 | ||
|
|
ff13c9c186 | ||
|
|
879e7305ca | ||
|
|
1ff827b2ea | ||
|
|
e7f1204fa4 | ||
|
|
9a2c4a34ee | ||
|
|
f4c421f77a | ||
|
|
fe84718b55 | ||
|
|
15d71a01d5 | ||
|
|
abe30f2578 | ||
|
|
fdae48547b | ||
|
|
68ca8df22f | ||
|
|
b8da38f4e4 | ||
|
|
1f103ab7f1 | ||
|
|
da6cf33aac | ||
|
|
73f08b376f | ||
|
|
ed34d1fee7 | ||
|
|
e9f4f1d13c | ||
|
|
e5bb330be5 | ||
|
|
e23e22cb81 | ||
|
|
7434026f5f | ||
|
|
5319d33bc6 | ||
|
|
702311b6b2 | ||
|
|
2511bc20e0 | ||
|
|
ce5a6eabae | ||
|
|
581cd97ba1 | ||
|
|
fa2f99641f | ||
|
|
c40f7db1ab | ||
|
|
be1363e943 | ||
|
|
c313039526 | ||
|
|
73db5dda8c | ||
|
|
5a8fb77fb2 | ||
|
|
4b6ebcbb61 | ||
|
|
bc056c41bc | ||
|
|
5b54442a48 | ||
|
|
dc14cce7a9 | ||
|
|
4f278ba715 | ||
|
|
1036fcca36 | ||
|
|
6b286a5dee | ||
|
|
c8ae675b95 | ||
|
|
4186467129 | ||
|
|
726884afcb | ||
|
|
5a2f3e700b | ||
|
|
911fc74346 | ||
|
|
1388f4d27e | ||
|
|
5b87327a43 | ||
|
|
2fc1679886 | ||
|
|
7ba5652bea | ||
|
|
1e9aebbc86 | ||
|
|
61ec361182 | ||
|
|
7781cbbc57 | ||
|
|
f3b806b471 | ||
|
|
6496405f30 | ||
|
|
85a6dc5e8c | ||
|
|
856bbfc9c8 | ||
|
|
ebaa43fa4c | ||
|
|
2d44b3ebea | ||
|
|
984493db30 | ||
|
|
47848769ff | ||
|
|
a8f6f5b974 | ||
|
|
1e13f474cb | ||
|
|
c69c3a9a46 | ||
|
|
3216b143c2 | ||
|
|
cc963d42a0 | ||
|
|
3f95a62e4f | ||
|
|
7f9a9e2e82 | ||
|
|
375ecd4ada | ||
|
|
8875dccd11 | ||
|
|
4c2301fdf6 | ||
|
|
346594c406 | ||
|
|
2609e2db5c | ||
|
|
692d5b4e08 | ||
|
|
c4af7464e5 | ||
|
|
5a1dc3eb8a | ||
|
|
adcbfcf8d6 | ||
|
|
b57607e7d3 | ||
|
|
2f159d4f45 | ||
|
|
93e1040d07 | ||
|
|
403c07c305 | ||
|
|
6253308e2e | ||
|
|
33a014013a | ||
|
|
4637215ab2 | ||
|
|
ceaedbbd7f | ||
|
|
52f8b1a1d7 | ||
|
|
e6d1250185 | ||
|
|
d04e5e49d0 | ||
|
|
a72436f330 | ||
|
|
467403f437 | ||
|
|
bbaac0c6a9 | ||
|
|
753fd4bda3 | ||
|
|
57d2c8c94a | ||
|
|
870ec89e9a | ||
|
|
0c3b70f2fb | ||
|
|
7a367698fe | ||
|
|
c77e99814b | ||
|
|
4ddd69cc55 | ||
|
|
ef4a61c769 | ||
|
|
7dfb5ff5bd | ||
|
|
6b391312ab | ||
|
|
6e62d77e4d | ||
|
|
0281cca9af | ||
|
|
018e2403b1 | ||
|
|
61f4534e2a | ||
|
|
69667317c1 | ||
|
|
530aac0682 | ||
|
|
6e7d8f90b5 | ||
|
|
65bf1086a2 | ||
|
|
98220442b4 | ||
|
|
3c3d2ef2b9 | ||
|
|
67066eb32a | ||
|
|
631df0fe56 | ||
|
|
485870296d | ||
|
|
6e5a1c00dc | ||
|
|
ba487eaaca | ||
|
|
eb0986c3f9 | ||
|
|
baf5be09dc | ||
|
|
f3aed42dd6 | ||
|
|
44531e3009 | ||
|
|
2177a0179e | ||
|
|
e1f333021f | ||
|
|
4040d73c60 | ||
|
|
61bd47ccc1 | ||
|
|
915c366056 | ||
|
|
6888a968f9 | ||
|
|
4e8e5bbb86 | ||
|
|
5752869824 | ||
|
|
39a12622ae | ||
|
|
dca88ff85c | ||
|
|
ab9843cb00 | ||
|
|
72fd1fa58d | ||
|
|
51eac1926f | ||
|
|
c1aed4af45 | ||
|
|
c12447c7c5 | ||
|
|
502bacea82 | ||
|
|
da5ba4ccc8 | ||
|
|
1f2426226b | ||
|
|
c0eb30b604 | ||
|
|
caca3a8048 | ||
|
|
f929419676 | ||
|
|
bc53e78a04 | ||
|
|
3dbea1a7a1 | ||
|
|
644d1db5ef | ||
|
|
07d97d5b26 | ||
|
|
c658b46fe1 | ||
|
|
8a5c9a8c70 | ||
|
|
3e4a525520 | ||
|
|
74ce0f738e | ||
|
|
1073d56245 | ||
|
|
7aa4484a03 | ||
|
|
6c96b60a63 | ||
|
|
ac1900a0fc | ||
|
|
bd3bc5c168 | ||
|
|
9ed43230ca | ||
|
|
7abe9ec4cc | ||
|
|
5ed2527663 | ||
|
|
b87c7cac54 | ||
|
|
0b34579b04 | ||
|
|
31291ebd35 | ||
|
|
e8e0b08f17 | ||
|
|
491ce61a76 | ||
|
|
e12a26dac5 | ||
|
|
7bf1889af1 | ||
|
|
139a2b7b0d | ||
|
|
f230c719d8 | ||
|
|
8703449dfe | ||
|
|
108590d924 | ||
|
|
b2cf5d2958 | ||
|
|
ee5ed44761 | ||
|
|
346913b7f6 | ||
|
|
18a8d2f67f | ||
|
|
3ae10915e4 | ||
|
|
949b9c85ca | ||
|
|
c21c19bd6c | ||
|
|
29125e830b | ||
|
|
1ac4676f4b | ||
|
|
fe5301cebf | ||
|
|
7262601123 | ||
|
|
fcb6cc1e76 | ||
|
|
ff716e7799 | ||
|
|
9c595aff95 | ||
|
|
98dbd1fdc7 | ||
|
|
a6df452841 | ||
|
|
4eab8672b8 | ||
|
|
6e2821b4db | ||
|
|
1564fae011 | ||
|
|
30e40079ca | ||
|
|
65a1d88907 | ||
|
|
e590874a81 | ||
|
|
b28e742683 | ||
|
|
62fdfb937a | ||
|
|
8814195122 | ||
|
|
e2095d4a5d | ||
|
|
78a38e9825 | ||
|
|
712101b63d | ||
|
|
1f18dbb17c | ||
|
|
0d8001adea | ||
|
|
1e44a62494 | ||
|
|
e8b13cb77e | ||
|
|
3f2fd610d9 | ||
|
|
25604dc577 | ||
|
|
0cfc6bf2a6 | ||
|
|
90d7823acb | ||
|
|
b4ae1b6528 | ||
|
|
f442665c46 | ||
|
|
c22498066b | ||
|
|
637883f52b | ||
|
|
f0c0da8551 | ||
|
|
10f42a2b39 | ||
|
|
29baccd857 | ||
|
|
f9814381a7 | ||
|
|
771ea47d37 | ||
|
|
c54beba932 | ||
|
|
a809621f63 | ||
|
|
7ad556346e | ||
|
|
5737c21340 | ||
|
|
77a5ce6bf3 | ||
|
|
fb503f523b | ||
|
|
bf7677ce69 | ||
|
|
1ce8c1cf82 | ||
|
|
4ddccfa5e5 | ||
|
|
5795d332c8 | ||
|
|
823054dc34 | ||
|
|
2ce15f429b | ||
|
|
143411aaf0 | ||
|
|
7d9548400d | ||
|
|
1b1941a896 | ||
|
|
4848c384cd | ||
|
|
d4f38d3894 | ||
|
|
e6acbc5a58 | ||
|
|
8dd4db5d85 | ||
|
|
d436eddc6a | ||
|
|
faf8e9ec6a | ||
|
|
7e6a571cba | ||
|
|
6bee9cd1e4 | ||
|
|
fb2b77e991 | ||
|
|
b914912c06 | ||
|
|
0ce04845de | ||
|
|
073365d5d9 | ||
|
|
3c27587d83 | ||
|
|
dbccc700f1 | ||
|
|
9f90ff2e59 | ||
|
|
4d9c8926b1 | ||
|
|
070695b348 | ||
|
|
c6e97d4dc5 | ||
|
|
a24e78fa92 | ||
|
|
21e0cd7781 | ||
|
|
ed45760425 | ||
|
|
0ca4250bd4 | ||
|
|
5059619947 | ||
|
|
edb228839e | ||
|
|
a9c93c797d | ||
|
|
f826ac35e3 | ||
|
|
9dc512349a | ||
|
|
3ecf16a492 | ||
|
|
584a76ab70 | ||
|
|
e339cde790 | ||
|
|
82a6a0848a | ||
|
|
441cb7980b | ||
|
|
5f523f6966 | ||
|
|
993650f3d6 | ||
|
|
ab330301eb | ||
|
|
bab85dd789 | ||
|
|
acae643a4a | ||
|
|
01f825b0e1 | ||
|
|
796637b31a | ||
|
|
484ecfaf47 | ||
|
|
c082af6f74 | ||
|
|
494eb4ab6b | ||
|
|
fe678dcd2f | ||
|
|
da5de4a6ff | ||
|
|
526c61e2c0 | ||
|
|
c7f608ec74 | ||
|
|
6816f8b489 | ||
|
|
cd58b5ff1f | ||
|
|
bca100cdb0 | ||
|
|
c63452e25d | ||
|
|
7e779327eb | ||
|
|
9f1e08663d | ||
|
|
91122d9193 | ||
|
|
c7d21841a4 | ||
|
|
701692b7d3 | ||
|
|
787a30cd8e | ||
|
|
ca6edcaf71 | ||
|
|
8d171a37f8 | ||
|
|
e9bd41b3f1 | ||
|
|
aa67bd5d00 | ||
|
|
802d684994 | ||
|
|
434e018584 | ||
|
|
4839294c86 | ||
|
|
71bbcd54ff | ||
|
|
3db353f356 | ||
|
|
f4c5ea8378 | ||
|
|
6a97a4a11e | ||
|
|
79f754e6ac | ||
|
|
e3e2fcc285 | ||
|
|
00e61a9100 | ||
|
|
f3107214f4 | ||
|
|
78e001284f | ||
|
|
9caa868603 | ||
|
|
202c54d423 | ||
|
|
1051004aee | ||
|
|
a1a002f4da | ||
|
|
5ef41ed53e | ||
|
|
67721f3413 | ||
|
|
34bf2452c3 | ||
|
|
8fbb98fb3f | ||
|
|
1792725651 | ||
|
|
47ff3a9bee | ||
|
|
ac3a706f0d | ||
|
|
9b5483a71b | ||
|
|
38c31c880f | ||
|
|
0bed5976e3 | ||
|
|
19a6725430 | ||
|
|
48a54efcb2 | ||
|
|
c0b0dc5219 | ||
|
|
683a26c830 | ||
|
|
1a16f335fa | ||
|
|
4145be863b | ||
|
|
e9f1b38984 | ||
|
|
edd90f153c | ||
|
|
dec390a89f | ||
|
|
41348dead4 | ||
|
|
c473ab97c7 | ||
|
|
0cd1de769b | ||
|
|
5ae8e8a9ca | ||
|
|
796d72f48e | ||
|
|
86a8584252 | ||
|
|
6509e90c36 | ||
|
|
09ecd0c583 | ||
|
|
a6d6adc57f | ||
|
|
6be5744be4 | ||
|
|
31b4437b93 | ||
|
|
458afcd230 | ||
|
|
cf5ae81ced | ||
|
|
08e46432c5 | ||
|
|
6f11621734 | ||
|
|
6004c394d6 | ||
|
|
609d83f92c | ||
|
|
4ef71f8a82 | ||
|
|
b47218521f | ||
|
|
c9cee8fd52 | ||
|
|
75e779029f | ||
|
|
3016d54f13 | ||
|
|
05e7c133fb | ||
|
|
fd57100190 | ||
|
|
fc86b1799a | ||
|
|
9546e0c8c2 | ||
|
|
4fe6c148ef | ||
|
|
9e872788c7 | ||
|
|
da95f77996 | ||
|
|
6f758bc7b1 | ||
|
|
b37b3cd1fc | ||
|
|
e81069ab3d | ||
|
|
bf25f17880 | ||
|
|
6201532c64 | ||
|
|
3094ae9df9 | ||
|
|
59f6931e06 | ||
|
|
95a601d053 | ||
|
|
5d7ef54d02 | ||
|
|
b34d46cbc8 | ||
|
|
0bb78814a6 | ||
|
|
4938d5dde5 | ||
|
|
4817b94d0b | ||
|
|
2a470deeaf | ||
|
|
861d829420 | ||
|
|
09ee6e1477 | ||
|
|
10fc74eb81 | ||
|
|
986f485b3e | ||
|
|
af1088ef61 | ||
|
|
13bc922e54 | ||
|
|
1f39a1bd76 | ||
|
|
13efb6586d | ||
|
|
a48ed02433 | ||
|
|
24c43513a6 | ||
|
|
a6d267abc0 | ||
|
|
c8877d4098 | ||
|
|
1318f536c9 | ||
|
|
bc2f86e806 | ||
|
|
107f0fa4c6 | ||
|
|
a5190449da | ||
|
|
114d4433a9 | ||
|
|
bd4498cffc | ||
|
|
6771539a90 | ||
|
|
123b6ae62e | ||
|
|
5d6a0d4dae | ||
|
|
6ecc63002b | ||
|
|
b3ea766bd5 | ||
|
|
e2a90ce159 | ||
|
|
8057e8df43 | ||
|
|
98b7c07171 | ||
|
|
3d76417353 | ||
|
|
2060ea5de3 | ||
|
|
79eb8f7ace | ||
|
|
0ebcc200c3 | ||
|
|
27f3f42ce2 | ||
|
|
dab967ace8 | ||
|
|
485d4aa8f3 | ||
|
|
799ae29ac4 | ||
|
|
00b209a29e | ||
|
|
581e510c2d | ||
|
|
9053c0dfd9 | ||
|
|
d32ce37484 | ||
|
|
1020560af6 | ||
|
|
118588ef6c | ||
|
|
6b9314eaa9 | ||
|
|
686bf443e6 | ||
|
|
93054ef24b | ||
|
|
1620eabd9d | ||
|
|
7fcb082cad | ||
|
|
68d16b723a | ||
|
|
ec9c6e9783 | ||
|
|
3b083d545d | ||
|
|
5400447395 | ||
|
|
ed8425b8b9 | ||
|
|
7d7d4822a5 | ||
|
|
80528c5344 | ||
|
|
6c24d9897a | ||
|
|
e346f3058e | ||
|
|
dc8da3743d | ||
|
|
6563576ae9 | ||
|
|
db9397890e | ||
|
|
bd1e3fc606 | ||
|
|
fe5f5b28d9 | ||
|
|
ee41fa6f30 | ||
|
|
84ecab0eaf | ||
|
|
3fde07b2e1 | ||
|
|
3c2f13f88b | ||
|
|
52f10242e2 | ||
|
|
9e719f088f | ||
|
|
6552256981 | ||
|
|
d1934363e7 | ||
|
|
cdbcfaa7de | ||
|
|
6ecc855c34 | ||
|
|
30ecd045fa | ||
|
|
f9e64e0965 | ||
|
|
0ecbb3ec02 | ||
|
|
3bb5ad7204 | ||
|
|
8e078b1d83 | ||
|
|
0c4d2fbc70 | ||
|
|
e4614e49ae | ||
|
|
8f56606cac | ||
|
|
af90fbfb33 | ||
|
|
938c3707fc | ||
|
|
1b95af18ff | ||
|
|
272ebc1ef7 | ||
|
|
cfd50538bb | ||
|
|
08abf67a51 | ||
|
|
981554cf74 | ||
|
|
979af3d314 | ||
|
|
57d1f2b4d3 | ||
|
|
1fa95ac236 | ||
|
|
25dc1c2155 | ||
|
|
61ec02248a | ||
|
|
ecd7caa93d | ||
|
|
aea26dcc64 | ||
|
|
1b8f299df2 | ||
|
|
6e2e08628a | ||
|
|
fb0e6cf0d0 | ||
|
|
a57c45bb1c | ||
|
|
b2cc1c54f8 | ||
|
|
21dad1d41e | ||
|
|
1d42b7f0d1 | ||
|
|
cddc33bb24 | ||
|
|
cb7ad2366d | ||
|
|
25536c5ffb | ||
|
|
842b75c0e6 | ||
|
|
8b0ba97cf2 | ||
|
|
b84682168d | ||
|
|
f20f9f376e | ||
|
|
24838bbcd3 | ||
|
|
7a00d97977 | ||
|
|
ac3de4c5fc | ||
|
|
28c731881f | ||
|
|
a7a46f4253 | ||
|
|
528497b86a | ||
|
|
32c32ecfda | ||
|
|
e30839e85f | ||
|
|
a4c7843a07 | ||
|
|
f0c6d17ad8 | ||
|
|
66c0638f3b | ||
|
|
eec7364760 | ||
|
|
b10094508f | ||
|
|
8e8679807d | ||
|
|
629da8f8bf | ||
|
|
10a346476a | ||
|
|
d1f5284fe6 | ||
|
|
849f5d9a44 | ||
|
|
7a76916143 | ||
|
|
2a829b1f1a | ||
|
|
44c68221a8 | ||
|
|
e36c4ecc98 | ||
|
|
01d399ad66 | ||
|
|
9376796bdb | ||
|
|
f135c09b36 | ||
|
|
4e85015836 | ||
|
|
f56c065f57 | ||
|
|
adc3457a89 | ||
|
|
fa261ebd02 | ||
|
|
7fdb87ad38 |
@@ -1,3 +1,3 @@
|
|||||||
[target.x86_64-pc-windows-msvc]
|
[target.x86_64-pc-windows-msvc]
|
||||||
# Link the C runtime statically ; https://github.com/paritytech/parity/issues/6643
|
# Link the C runtime statically ; https://github.com/paritytech/parity-ethereum/issues/6643
|
||||||
rustflags = ["-Ctarget-feature=+crt-static"]
|
rustflags = ["-Ctarget-feature=+crt-static"]
|
||||||
|
|||||||
14
.github/CONTRIBUTING.md
vendored
14
.github/CONTRIBUTING.md
vendored
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
## Do you have a question?
|
## Do you have a question?
|
||||||
|
|
||||||
Check out our [Basic Usage](https://github.com/paritytech/parity/wiki/Basic-Usage), [Configuration](https://github.com/paritytech/parity/wiki/Configuring-Parity), and [FAQ](https://github.com/paritytech/parity/wiki/FAQ) articles on our [wiki](https://github.com/paritytech/parity/wiki)!
|
Check out our [Basic Usage](https://wiki.parity.io/Basic-Usage), [Configuration](https://wiki.parity.io/Configuring-Parity-Ethereum), and [FAQ](https://wiki.parity.io/FAQ) articles on our [wiki](https://wiki.parity.io/)!
|
||||||
|
|
||||||
See also frequently asked questions [tagged with `parity`](https://ethereum.stackexchange.com/questions/tagged/parity?sort=votes&pageSize=50) on Stack Exchange.
|
See also frequently asked questions [tagged with `parity`](https://ethereum.stackexchange.com/questions/tagged/parity?sort=votes&pageSize=50) on Stack Exchange.
|
||||||
|
|
||||||
@@ -10,11 +10,11 @@ See also frequently asked questions [tagged with `parity`](https://ethereum.stac
|
|||||||
|
|
||||||
Do **not** open an issue on Github if you think your discovered bug could be a **security-relevant vulnerability**. Please, read our [security policy](../SECURITY.md) instead.
|
Do **not** open an issue on Github if you think your discovered bug could be a **security-relevant vulnerability**. Please, read our [security policy](../SECURITY.md) instead.
|
||||||
|
|
||||||
Otherwise, just create a [new issue](https://github.com/paritytech/parity/issues/new) in our repository and state:
|
Otherwise, just create a [new issue](https://github.com/paritytech/parity-ethereum/issues/new) in our repository and state:
|
||||||
|
|
||||||
- What's your Parity version?
|
- What's your Parity Ethereum version?
|
||||||
- What's your operating system and version?
|
- What's your operating system and version?
|
||||||
- How did you install parity?
|
- How did you install Parity Ethereum?
|
||||||
- Is your node fully synchronized?
|
- Is your node fully synchronized?
|
||||||
- Did you try turning it off and on again?
|
- Did you try turning it off and on again?
|
||||||
|
|
||||||
@@ -22,12 +22,12 @@ Also, try to include **steps to reproduce** the issue and expand on the **actual
|
|||||||
|
|
||||||
## Contribute!
|
## Contribute!
|
||||||
|
|
||||||
If you would like to contribute to Parity, please **fork it**, fix bugs or implement features, and [propose a pull request](https://github.com/paritytech/parity/compare).
|
If you would like to contribute to Parity Ethereum, please **fork it**, fix bugs or implement features, and [propose a pull request](https://github.com/paritytech/parity-ethereum/compare).
|
||||||
|
|
||||||
Please, refer to the [Coding Guide](https://github.com/paritytech/parity/wiki/Coding-guide) in our wiki for more details about hacking on Parity.
|
Please, refer to the [Coding Guide](https://wiki.parity.io/Coding-guide) in our wiki for more details about hacking on Parity.
|
||||||
|
|
||||||
## License.
|
## License.
|
||||||
|
|
||||||
By contributing to Parity, you agree that your contributions will be licensed under the [GPLv3 License](../LICENSE).
|
By contributing to Parity Ethereum, you agree that your contributions will be licensed under the [GPLv3 License](../LICENSE).
|
||||||
|
|
||||||
Each contributor has to sign our Contributor License Agreement. The purpose of the CLA is to ensure that the guardian of a project's outputs has the necessary ownership or grants of rights over all contributions to allow them to distribute under the chosen license. You can read and sign our full Contributor License Agreement at [cla.parity.io](https://cla.parity.io) before submitting a pull request.
|
Each contributor has to sign our Contributor License Agreement. The purpose of the CLA is to ensure that the guardian of a project's outputs has the necessary ownership or grants of rights over all contributions to allow them to distribute under the chosen license. You can read and sign our full Contributor License Agreement at [cla.parity.io](https://cla.parity.io) before submitting a pull request.
|
||||||
|
|||||||
14
.github/ISSUE_TEMPLATE.md
vendored
14
.github/ISSUE_TEMPLATE.md
vendored
@@ -1,13 +1,11 @@
|
|||||||
_Before filing a new issue, please **provide the following information**._
|
_Before filing a new issue, please **provide the following information**._
|
||||||
|
|
||||||
> I'm running:
|
- **Parity Ethereum version**: 0.0.0
|
||||||
>
|
- **Operating system**: Windows / MacOS / Linux
|
||||||
> - **Which Parity version?**: 0.0.0
|
- **Installation**: homebrew / one-line installer / built from source
|
||||||
> - **Which operating system?**: Windows / MacOS / Linux
|
- **Fully synchronized**: no / yes
|
||||||
> - **How installed?**: via installer / homebrew / binaries / from source
|
- **Network**: ethereum / ropsten / kovan / ...
|
||||||
> - **Are you fully synchronized?**: no / yes
|
- **Restarted**: no / yes
|
||||||
> - **Which network are you connected to?**: ethereum / ropsten / kovan / ...
|
|
||||||
> - **Did you try to restart the node?**: no / yes
|
|
||||||
|
|
||||||
_Your issue description goes here below. Try to include **actual** vs. **expected behavior** and **steps to reproduce** the issue._
|
_Your issue description goes here below. Try to include **actual** vs. **expected behavior** and **steps to reproduce** the issue._
|
||||||
|
|
||||||
|
|||||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -38,7 +38,8 @@ node_modules
|
|||||||
|
|
||||||
# Build artifacts
|
# Build artifacts
|
||||||
out/
|
out/
|
||||||
|
parity-clib-examples/cpp/build/
|
||||||
|
|
||||||
.vscode
|
.vscode
|
||||||
|
rls/
|
||||||
/parity.*
|
/parity.*
|
||||||
|
|||||||
411
.gitlab-ci.yml
411
.gitlab-ci.yml
@@ -1,265 +1,206 @@
|
|||||||
stages:
|
stages:
|
||||||
- test
|
- test
|
||||||
- push-release
|
|
||||||
- build
|
- build
|
||||||
|
- publish
|
||||||
|
- publish-onchain
|
||||||
|
- optional
|
||||||
|
|
||||||
|
image: parity/rust:gitlab-ci
|
||||||
|
|
||||||
variables:
|
variables:
|
||||||
RUST_BACKTRACE: "1"
|
GIT_STRATEGY: fetch
|
||||||
RUSTFLAGS: ""
|
GIT_SUBMODULE_STRATEGY: recursive
|
||||||
CARGOFLAGS: ""
|
CI_SERVER_NAME: "GitLab CI"
|
||||||
CI_SERVER_NAME: "GitLab CI"
|
CARGO_HOME: "${CI_PROJECT_DIR}/.cargo"
|
||||||
LIBSSL: "libssl1.0.0 (>=1.0.0)"
|
CARGO_TARGET: x86_64-unknown-linux-gnu
|
||||||
cache:
|
|
||||||
key: "$CI_BUILD_STAGE-$CI_BUILD_REF_NAME"
|
.releaseable_branches: # list of git refs for building GitLab artifacts (think "pre-release binaries")
|
||||||
paths:
|
only: &releaseable_branches
|
||||||
- target/
|
- stable
|
||||||
untracked: true
|
|
||||||
linux-ubuntu:
|
|
||||||
stage: build
|
|
||||||
image: parity/rust:gitlab-ci
|
|
||||||
only:
|
|
||||||
- beta
|
- beta
|
||||||
- tags
|
- tags
|
||||||
- stable
|
- schedules
|
||||||
- triggers
|
|
||||||
script:
|
|
||||||
- rustup default stable
|
.collect_artifacts: &collect_artifacts
|
||||||
# ARGUMENTS: 1. BUILD_PLATFORM (target for binaries) 2. PLATFORM (target for cargo) 3. ARC (architecture) 4. & 5. CC & CXX flags 6. binary identifier
|
|
||||||
- scripts/gitlab-build.sh x86_64-unknown-linux-gnu x86_64-unknown-linux-gnu amd64 gcc g++ ubuntu
|
|
||||||
tags:
|
|
||||||
- rust-stable
|
|
||||||
artifacts:
|
artifacts:
|
||||||
|
name: "${CI_JOB_NAME}_${SCHEDULE_TAG:-${CI_COMMIT_REF_NAME}}"
|
||||||
|
when: on_success
|
||||||
|
expire_in: 1 mos
|
||||||
paths:
|
paths:
|
||||||
- parity.zip
|
- artifacts/
|
||||||
name: "stable-x86_64-unknown-linux-gnu_parity"
|
|
||||||
linux-debian:
|
.determine_version: &determine_version
|
||||||
stage: build
|
- VERSION="$(sed -r -n '1,/^version/s/^version = "([^"]+)".*$/\1/p' Cargo.toml)"
|
||||||
image: parity/rust-debian:gitlab-ci
|
- DATE_STR="$(date +%Y%m%d)"
|
||||||
only:
|
- ID_SHORT="$(echo ${CI_COMMIT_SHA} | cut -c 1-7)"
|
||||||
- beta
|
- test "${SCHEDULE_TAG:-${CI_COMMIT_REF_NAME}}" = "nightly" && VERSION="${VERSION}-${ID_SHORT}-${DATE_STR}"
|
||||||
- tags
|
- export VERSION
|
||||||
- stable
|
- echo "Version = ${VERSION}"
|
||||||
- triggers
|
|
||||||
|
test-linux:
|
||||||
|
stage: test
|
||||||
|
variables:
|
||||||
|
RUN_TESTS: all
|
||||||
script:
|
script:
|
||||||
- export LIBSSL="libssl1.1 (>=1.1.0)"
|
- scripts/gitlab/test-all.sh
|
||||||
- scripts/gitlab-build.sh x86_64-unknown-debian-gnu x86_64-unknown-linux-gnu amd64 gcc g++ debian
|
- sccache -s
|
||||||
tags:
|
tags:
|
||||||
- rust-debian
|
- linux-docker
|
||||||
artifacts:
|
|
||||||
paths:
|
test-audit:
|
||||||
- parity.zip
|
stage: test
|
||||||
name: "stable-x86_64-unknown-debian-gnu_parity"
|
|
||||||
linux-centos:
|
|
||||||
stage: build
|
|
||||||
image: parity/rust-centos:gitlab-ci
|
|
||||||
only:
|
|
||||||
- beta
|
|
||||||
- tags
|
|
||||||
- stable
|
|
||||||
- triggers
|
|
||||||
script:
|
script:
|
||||||
- scripts/gitlab-build.sh x86_64-unknown-centos-gnu x86_64-unknown-linux-gnu x86_64 gcc g++ centos
|
- set -e
|
||||||
|
- set -u
|
||||||
|
- cargo audit
|
||||||
tags:
|
tags:
|
||||||
- rust-centos
|
- linux-docker
|
||||||
artifacts:
|
|
||||||
paths:
|
build-linux:
|
||||||
- parity.zip
|
stage: build
|
||||||
name: "x86_64-unknown-centos-gnu_parity"
|
only: *releaseable_branches
|
||||||
linux-i686:
|
|
||||||
stage: build
|
|
||||||
image: parity/rust-i686:gitlab-ci
|
|
||||||
only:
|
|
||||||
- beta
|
|
||||||
- tags
|
|
||||||
- stable
|
|
||||||
- triggers
|
|
||||||
script:
|
script:
|
||||||
- scripts/gitlab-build.sh i686-unknown-linux-gnu i686-unknown-linux-gnu i386 gcc g++ ubuntu
|
- scripts/gitlab/build-unix.sh
|
||||||
|
- sccache -s
|
||||||
|
<<: *collect_artifacts
|
||||||
tags:
|
tags:
|
||||||
- rust-i686
|
- linux-docker
|
||||||
artifacts:
|
|
||||||
paths:
|
build-darwin:
|
||||||
- parity.zip
|
stage: build
|
||||||
name: "i686-unknown-linux-gnu"
|
only: *releaseable_branches
|
||||||
allow_failure: true
|
variables:
|
||||||
linux-armv7:
|
CARGO_TARGET: x86_64-apple-darwin
|
||||||
stage: build
|
CC: gcc
|
||||||
image: parity/rust-armv7:gitlab-ci
|
CXX: g++
|
||||||
only:
|
|
||||||
- beta
|
|
||||||
- tags
|
|
||||||
- stable
|
|
||||||
- triggers
|
|
||||||
script:
|
script:
|
||||||
- scripts/gitlab-build.sh armv7-unknown-linux-gnueabihf armv7-unknown-linux-gnueabihf armhf arm-linux-gnueabihf-gcc arm-linux-gnueabihf-g++ ubuntu
|
- scripts/gitlab/build-unix.sh
|
||||||
tags:
|
tags:
|
||||||
- rust-arm
|
- rust-osx
|
||||||
artifacts:
|
<<: *collect_artifacts
|
||||||
paths:
|
|
||||||
- parity.zip
|
build-windows:
|
||||||
name: "armv7_unknown_linux_gnueabihf_parity"
|
stage: build
|
||||||
allow_failure: true
|
only: *releaseable_branches
|
||||||
linux-arm:
|
variables:
|
||||||
stage: build
|
CARGO_TARGET: x86_64-pc-windows-msvc
|
||||||
image: parity/rust-arm:gitlab-ci
|
|
||||||
only:
|
|
||||||
- beta
|
|
||||||
- tags
|
|
||||||
- stable
|
|
||||||
- triggers
|
|
||||||
script:
|
script:
|
||||||
- scripts/gitlab-build.sh arm-unknown-linux-gnueabihf arm-unknown-linux-gnueabihf armhf arm-linux-gnueabihf-gcc arm-linux-gnueabihf-g++ ubuntu
|
- sh scripts/gitlab/build-windows.sh
|
||||||
tags:
|
|
||||||
- rust-arm
|
|
||||||
artifacts:
|
|
||||||
paths:
|
|
||||||
- parity.zip
|
|
||||||
name: "arm-unknown-linux-gnueabihf_parity"
|
|
||||||
allow_failure: true
|
|
||||||
linux-aarch64:
|
|
||||||
stage: build
|
|
||||||
image: parity/rust-arm64:gitlab-ci
|
|
||||||
only:
|
|
||||||
- beta
|
|
||||||
- tags
|
|
||||||
- stable
|
|
||||||
- triggers
|
|
||||||
script:
|
|
||||||
- scripts/gitlab-build.sh aarch64-unknown-linux-gnu aarch64-unknown-linux-gnu arm64 aarch64-linux-gnu-gcc aarch64-linux-gnu-g++ ubuntu
|
|
||||||
tags:
|
|
||||||
- rust-arm
|
|
||||||
artifacts:
|
|
||||||
paths:
|
|
||||||
- parity.zip
|
|
||||||
name: "aarch64-unknown-linux-gnu_parity"
|
|
||||||
linux-snap:
|
|
||||||
stage: build
|
|
||||||
image: parity/snapcraft:gitlab-ci
|
|
||||||
only:
|
|
||||||
- stable
|
|
||||||
- beta
|
|
||||||
- tags
|
|
||||||
- triggers
|
|
||||||
script:
|
|
||||||
- scripts/gitlab-build.sh x86_64-unknown-snap-gnu x86_64-unknown-linux-gnu amd64 gcc g++ snap
|
|
||||||
tags:
|
|
||||||
- rust-stable
|
|
||||||
artifacts:
|
|
||||||
paths:
|
|
||||||
- parity.zip
|
|
||||||
name: "stable-x86_64-unknown-snap-gnu_parity"
|
|
||||||
darwin:
|
|
||||||
stage: build
|
|
||||||
only:
|
|
||||||
- beta
|
|
||||||
- tags
|
|
||||||
- stable
|
|
||||||
- triggers
|
|
||||||
script:
|
|
||||||
- scripts/gitlab-build.sh x86_64-apple-darwin x86_64-apple-darwin macos gcc g++ macos
|
|
||||||
tags:
|
|
||||||
- osx
|
|
||||||
artifacts:
|
|
||||||
paths:
|
|
||||||
- parity.zip
|
|
||||||
name: "x86_64-apple-darwin_parity"
|
|
||||||
windows:
|
|
||||||
cache:
|
|
||||||
key: "%CI_BUILD_STAGE%-%CI_BUILD_REF_NAME%"
|
|
||||||
untracked: true
|
|
||||||
stage: build
|
|
||||||
only:
|
|
||||||
- beta
|
|
||||||
- tags
|
|
||||||
- stable
|
|
||||||
- triggers
|
|
||||||
script:
|
|
||||||
- sh scripts/gitlab-build.sh x86_64-pc-windows-msvc x86_64-pc-windows-msvc installer "" "" windows
|
|
||||||
tags:
|
tags:
|
||||||
- rust-windows
|
- rust-windows
|
||||||
artifacts:
|
<<: *collect_artifacts
|
||||||
paths:
|
|
||||||
- parity.zip
|
publish-docker:
|
||||||
name: "x86_64-pc-windows-msvc_parity"
|
stage: publish
|
||||||
android-armv7:
|
only: *releaseable_branches
|
||||||
stage: build
|
cache: {}
|
||||||
image: parity/parity-android:latest
|
dependencies:
|
||||||
only:
|
- build-linux
|
||||||
- beta
|
|
||||||
- tags
|
|
||||||
- stable
|
|
||||||
- triggers
|
|
||||||
script:
|
|
||||||
- cargo build --target=armv7-linux-androideabi
|
|
||||||
tags:
|
tags:
|
||||||
- rust-arm
|
- shell
|
||||||
allow_failure: true
|
|
||||||
artifacts:
|
|
||||||
paths:
|
|
||||||
- parity.zip
|
|
||||||
name: "armv7-linux-androideabi_parity"
|
|
||||||
docker-build:
|
|
||||||
stage: build
|
|
||||||
only:
|
|
||||||
- tags
|
|
||||||
- beta
|
|
||||||
- stable
|
|
||||||
- triggers
|
|
||||||
before_script:
|
|
||||||
- docker info
|
|
||||||
script:
|
script:
|
||||||
- if [ "$CI_BUILD_REF_NAME" == "master" ]; then DOCKER_TAG="latest"; else DOCKER_TAG=$CI_BUILD_REF_NAME; fi
|
- scripts/gitlab/publish-docker.sh parity
|
||||||
- echo "Tag:" $DOCKER_TAG
|
|
||||||
- docker login -u $Docker_Hub_User_Parity -p $Docker_Hub_Pass_Parity
|
publish-snap:
|
||||||
- scripts/docker-build.sh $DOCKER_TAG
|
stage: optional #publish
|
||||||
- docker logout
|
only: *releaseable_branches
|
||||||
tags:
|
image: snapcore/snapcraft
|
||||||
- docker
|
variables:
|
||||||
test-coverage:
|
BUILD_ARCH: amd64
|
||||||
stage: test
|
cache: {}
|
||||||
only:
|
before_script: *determine_version
|
||||||
- master
|
dependencies:
|
||||||
script:
|
- build-linux
|
||||||
- scripts/gitlab-test.sh test-coverage
|
|
||||||
tags:
|
|
||||||
- kcov
|
|
||||||
allow_failure: true
|
|
||||||
test-rust-stable:
|
|
||||||
stage: test
|
|
||||||
image: parity/rust:gitlab-ci
|
|
||||||
script:
|
|
||||||
- scripts/gitlab-test.sh stable
|
|
||||||
tags:
|
tags:
|
||||||
- rust-stable
|
- rust-stable
|
||||||
test-rust-beta:
|
|
||||||
stage: test
|
|
||||||
only:
|
|
||||||
- triggers
|
|
||||||
- master
|
|
||||||
image: parity/rust:gitlab-ci
|
|
||||||
script:
|
script:
|
||||||
- scripts/gitlab-test.sh beta
|
- scripts/gitlab/publish-snap.sh
|
||||||
tags:
|
allow_failure: true
|
||||||
- rust-beta
|
<<: *collect_artifacts
|
||||||
allow_failure: true
|
|
||||||
test-rust-nightly:
|
publish-onnet-update:
|
||||||
stage: test
|
stage: publish-onchain
|
||||||
only:
|
only: *releaseable_branches
|
||||||
- triggers
|
cache: {}
|
||||||
- master
|
dependencies:
|
||||||
image: parity/rust:gitlab-ci
|
- build-linux
|
||||||
|
- build-darwin
|
||||||
|
- build-windows
|
||||||
|
- publish-awss3-release
|
||||||
|
before_script: *determine_version
|
||||||
script:
|
script:
|
||||||
- scripts/gitlab-test.sh nightly
|
- scripts/gitlab/publish-onnet-update.sh
|
||||||
tags:
|
tags:
|
||||||
- rust
|
- linux-docker
|
||||||
- rust-nightly
|
|
||||||
allow_failure: true
|
# configures aws for fast uploads/syncs
|
||||||
push-release:
|
.s3-before-script: &s3-before-script
|
||||||
stage: push-release
|
before_script:
|
||||||
|
- mkdir -p ${HOME}/.aws
|
||||||
|
- |
|
||||||
|
cat > ${HOME}/.aws/config <<EOC
|
||||||
|
[default]
|
||||||
|
s3 =
|
||||||
|
max_concurrent_requests = 20
|
||||||
|
max_queue_size = 10000
|
||||||
|
multipart_threshold = 64MB
|
||||||
|
multipart_chunksize = 16MB
|
||||||
|
max_bandwidth = 50MB/s
|
||||||
|
use_accelerate_endpoint = false
|
||||||
|
addressing_style = path
|
||||||
|
EOC
|
||||||
|
|
||||||
|
publish-awss3-release:
|
||||||
|
image: parity/awscli:latest
|
||||||
|
stage: publish
|
||||||
|
only: *releaseable_branches
|
||||||
|
cache: {}
|
||||||
|
dependencies:
|
||||||
|
- build-linux
|
||||||
|
- build-darwin
|
||||||
|
- build-windows
|
||||||
|
variables:
|
||||||
|
GIT_STRATEGY: none
|
||||||
|
<<: *s3-before-script
|
||||||
|
script:
|
||||||
|
- echo "__________Push binaries to AWS S3____________"
|
||||||
|
- case "${SCHEDULE_TAG:-${CI_COMMIT_REF_NAME}}" in
|
||||||
|
(beta|stable|nightly)
|
||||||
|
export BUCKET=releases.parity.io/ethereum;
|
||||||
|
;;
|
||||||
|
(*)
|
||||||
|
export BUCKET=builds-parity;
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
- aws s3 sync ./artifacts s3://${BUCKET}/${SCHEDULE_TAG:-${CI_COMMIT_REF_NAME}}/
|
||||||
|
after_script:
|
||||||
|
- aws s3 ls s3://${BUCKET}/${SCHEDULE_TAG:-${CI_COMMIT_REF_NAME}}/
|
||||||
|
--recursive --human-readable --summarize
|
||||||
|
tags:
|
||||||
|
- linux-docker
|
||||||
|
|
||||||
|
publish-docs:
|
||||||
|
stage: publish
|
||||||
only:
|
only:
|
||||||
- tags
|
- tags
|
||||||
- triggers
|
except:
|
||||||
image: parity/rust:gitlab-ci
|
- nightly
|
||||||
|
cache: {}
|
||||||
script:
|
script:
|
||||||
- scripts/gitlab-push-release.sh
|
- scripts/gitlab/publish-docs.sh
|
||||||
tags:
|
tags:
|
||||||
- curl
|
- linux-docker
|
||||||
|
|
||||||
|
build-android:
|
||||||
|
stage: optional
|
||||||
|
image: parity/rust-android:gitlab-ci
|
||||||
|
variables:
|
||||||
|
CARGO_TARGET: armv7-linux-androideabi
|
||||||
|
script:
|
||||||
|
- scripts/gitlab/build-unix.sh
|
||||||
|
tags:
|
||||||
|
- linux-docker
|
||||||
|
allow_failure: true
|
||||||
|
<<: *collect_artifacts
|
||||||
|
|
||||||
|
|||||||
518
CHANGELOG.md
518
CHANGELOG.md
@@ -1,272 +1,280 @@
|
|||||||
## Parity [v1.10.2](https://github.com/paritytech/parity/releases/tag/v1.10.2) (2018-04-24)
|
## Parity-Ethereum [v2.2.5](https://github.com/paritytech/parity-ethereum/releases/tag/v2.2.5) (2018-12-14)
|
||||||
|
Parity-Ethereum 2.2.5-beta is an important release that introduces Constantinople fork at block 7080000 on Mainnet.
|
||||||
|
This release also contains a fix for chains using AuRa + EmptySteps. Read carefully if this applies to you.
|
||||||
|
If you have a chain with`empty_steps` already running, some blocks most likely contain non-strict entries (unordered or duplicated empty steps). In this release`strict_empty_steps_transition` **is enabled by default at block 0** for any chain with `empty_steps`.
|
||||||
|
If your network uses `empty_steps` you **must**:
|
||||||
|
- plan a hard fork and change `strict_empty_steps_transition` to the desire fork block
|
||||||
|
- update the clients of the whole network to 2.2.5-beta / 2.1.10-stable.
|
||||||
|
If for some reason you don't want to do this please set`strict_empty_steps_transition` to `0xfffffffff` to disable it.
|
||||||
|
|
||||||
Parity 1.10.2 is a bug-fix release to improve performance and stability.
|
The full list of included changes:
|
||||||
|
- Backports for beta 2.2.5 ([#10047](https://github.com/paritytech/parity-ethereum/pull/10047))
|
||||||
|
- Bump beta to 2.2.5 ([#10047](https://github.com/paritytech/parity-ethereum/pull/10047))
|
||||||
|
- Fix empty steps ([#9939](https://github.com/paritytech/parity-ethereum/pull/9939))
|
||||||
|
- Prevent sending empty step message twice
|
||||||
|
- Prevent sending empty step and then block in the same step
|
||||||
|
- Don't accept double empty steps
|
||||||
|
- Do basic validation of self-sealed blocks
|
||||||
|
- Strict empty steps validation ([#10041](https://github.com/paritytech/parity-ethereum/pull/10041))
|
||||||
|
- Enables strict verification of empty steps - there can be no duplicates and empty steps should be ordered inside the seal.
|
||||||
|
- Note that authorities won't produce invalid seals after [#9939](https://github.com/paritytech/parity-ethereum/pull/9939), this PR just adds verification to the seal to prevent forging incorrect blocks and potentially causing consensus issues.
|
||||||
|
- This features is enabled by default so any AuRa + EmptySteps chain should set strict_empty_steps_transition fork block number in their spec and upgrade to v2.2.5-beta or v2.1.10-stable.
|
||||||
|
- ethcore: enable constantinople on ethereum ([#10031](https://github.com/paritytech/parity-ethereum/pull/10031))
|
||||||
|
- ethcore: change blockreward to 2e18 for foundation after constantinople
|
||||||
|
- ethcore: delay diff bomb by 2e6 blocks for foundation after constantinople
|
||||||
|
- ethcore: enable eip-{145,1014,1052,1283} for foundation after constantinople
|
||||||
|
- Change test miner max memory to malloc reports. ([#10024](https://github.com/paritytech/parity-ethereum/pull/10024))
|
||||||
|
- Fix: test corpus_inaccessible panic ([#10019](https://github.com/paritytech/parity-ethereum/pull/10019))
|
||||||
|
|
||||||
|
## Parity-Ethereum [v2.2.2](https://github.com/paritytech/parity-ethereum/releases/tag/v2.2.2) (2018-11-29)
|
||||||
|
|
||||||
|
Parity-Ethereum 2.2.2-beta is an exciting release. Among others, it improves sync performance, peering stability, block propagation, and transaction propagation times. Also, a warp-sync no longer removes existing blocks from the database, but rather reuses locally available information to decrease sync times and reduces required bandwidth.
|
||||||
|
|
||||||
|
Before upgrading to 2.2.2, please also verify the validity of your chain specs. Parity Ethereum now denies unknown fields in the specification. To do this, use the chainspec tool:
|
||||||
|
|
||||||
|
```
|
||||||
|
cargo build --release -p chainspec
|
||||||
|
./target/release/chainspec /path/to/spec.json
|
||||||
|
```
|
||||||
|
|
||||||
|
Last but not least, JSONRPC APIs which are not yet accepted as an EIP in the `eth`, `personal`, or `web3` namespace, are now considere experimental as their final specification might change in future. These APIs have to be manually enabled by explicitly running `--jsonrpc-experimental`.
|
||||||
|
|
||||||
The full list of included changes:
|
The full list of included changes:
|
||||||
|
|
||||||
- Update Parity beta to 1.10.2 + Backports ([#8455](https://github.com/paritytech/parity/pull/8455))
|
- Backports For beta 2.2.2 ([#9976](https://github.com/paritytech/parity-ethereum/pull/9976))
|
||||||
- Update Parity beta to 1.10.2
|
- Version: bump beta to 2.2.2
|
||||||
- Allow 32-bit pipelines to fail ([#8454](https://github.com/paritytech/parity/pull/8454))
|
- Add experimental RPCs flag ([#9928](https://github.com/paritytech/parity-ethereum/pull/9928))
|
||||||
- Disable 32-bit targets for Gitlab
|
- Keep existing blocks when restoring a Snapshot ([#8643](https://github.com/paritytech/parity-ethereum/pull/8643))
|
||||||
- Rename Linux pipelines
|
- Rename db_restore => client
|
||||||
- Update wasmi ([#8452](https://github.com/paritytech/parity/pull/8452))
|
- First step: make it compile!
|
||||||
- Fix Cargo.lock
|
- Second step: working implementation!
|
||||||
- Backports ([#8450](https://github.com/paritytech/parity/pull/8450))
|
- Refactoring
|
||||||
- Use forked app_dirs crate for reverted Windows dir behavior ([#8438](https://github.com/paritytech/parity/pull/8438))
|
- Fix tests
|
||||||
- Remove unused app_dirs dependency in CLI
|
- Migrate ancient blocks interacting backward
|
||||||
- Use forked app_dirs crate for reverted Windows dir behavior
|
- Early return in block migration if snapshot is aborted
|
||||||
- Remove Tendermint extra_info due to seal inconsistencies ([#8367](https://github.com/paritytech/parity/pull/8367))
|
- Remove RwLock getter (PR Grumble I)
|
||||||
- Handle queue import errors a bit more gracefully ([#8385](https://github.com/paritytech/parity/pull/8385))
|
- Remove dependency on `Client`: only used Traits
|
||||||
- Improve VM executor stack size estimation rules ([#8439](https://github.com/paritytech/parity/pull/8439))
|
- Add test for recovering aborted snapshot recovery
|
||||||
- Improve VM executor stack size estimation rules
|
- Add test for migrating old blocks
|
||||||
- Typo: docs add "(Debug build)" comment
|
- Release RwLock earlier
|
||||||
- Fix an off by one typo and set minimal stack size
|
- Revert Cargo.lock
|
||||||
- Use saturating_sub to avoid potential overflow
|
- Update _update ancient block_ logic: set local in `commit`
|
||||||
|
- Update typo in ethcore/src/snapshot/service.rs
|
||||||
## Parity [v1.10.1](https://github.com/paritytech/parity/releases/tag/v1.10.1) (2018-04-17)
|
- Adjust requests costs for light client ([#9925](https://github.com/paritytech/parity-ethereum/pull/9925))
|
||||||
|
- Pip Table Cost relative to average peers instead of max peers
|
||||||
Parity 1.10.1 is a bug-fix release to improve performance and stability. Among other changes, you can now use `--warp-barrier [BLOCK]` to specify a minimum block number to `--warp` to. This is useful in cases where clients restore to outdated snapshots far behind the latest chain head.
|
- Add tracing in PIP new_cost_table
|
||||||
|
- Update stat peer_count
|
||||||
The full list of included changes:
|
- Use number of leeching peers for Light serve costs
|
||||||
|
- Fix test::light_params_load_share_depends_on_max_peers (wrong type)
|
||||||
- Bump beta to 1.10.1 ([#8350](https://github.com/paritytech/parity/pull/8350))
|
- Remove (now) useless test
|
||||||
- Bump beta to 1.10.1
|
- Remove `load_share` from LightParams.Config
|
||||||
- Unflag critical release
|
- Add LEECHER_COUNT_FACTOR
|
||||||
- Backports ([#8346](https://github.com/paritytech/parity/pull/8346))
|
- Pr Grumble: u64 to u32 for f64 casting
|
||||||
- Warp-only sync with warp-barrier [blocknumber] flag. ([#8228](https://github.com/paritytech/parity/pull/8228))
|
- Prevent u32 overflow for avg_peer_count
|
||||||
- Warp-only sync with warp-after [blocknumber] flag.
|
- Add tests for LightSync::Statistics
|
||||||
|
- Fix empty steps ([#9939](https://github.com/paritytech/parity-ethereum/pull/9939))
|
||||||
|
- Don't send empty step twice or empty step then block.
|
||||||
|
- Perform basic validation of locally sealed blocks.
|
||||||
|
- Don't include empty step twice.
|
||||||
|
- Prevent silent errors in daemon mode, closes [#9367](https://github.com/paritytech/parity-ethereum/issues/9367) ([#9946](https://github.com/paritytech/parity-ethereum/pull/9946))
|
||||||
|
- Fix a deadlock ([#9952](https://github.com/paritytech/parity-ethereum/pull/9952))
|
||||||
|
- Update informant:
|
||||||
|
- Decimal in Mgas/s
|
||||||
|
- Print every 5s (not randomly between 5s and 10s)
|
||||||
|
- Fix dead-lock in `blockchain.rs`
|
||||||
|
- Update locks ordering
|
||||||
|
- Fix light client informant while syncing ([#9932](https://github.com/paritytech/parity-ethereum/pull/9932))
|
||||||
|
- Add `is_idle` to LightSync to check importing status
|
||||||
|
- Use SyncStateWrapper to make sure is_idle gets updates
|
||||||
|
- Update is_major_import to use verified queue size as well
|
||||||
|
- Add comment for `is_idle`
|
||||||
|
- Add Debug to `SyncStateWrapper`
|
||||||
|
- `fn get` -> `fn into_inner`
|
||||||
|
- Ci: rearrange pipeline by logic ([#9970](https://github.com/paritytech/parity-ethereum/pull/9970))
|
||||||
|
- Ci: rearrange pipeline by logic
|
||||||
|
- Ci: rename docs script
|
||||||
|
- Fix docker build ([#9971](https://github.com/paritytech/parity-ethereum/pull/9971))
|
||||||
|
- Deny unknown fields for chainspec ([#9972](https://github.com/paritytech/parity-ethereum/pull/9972))
|
||||||
|
- Add deny_unknown_fields to chainspec
|
||||||
|
- Add tests and fix existing one
|
||||||
|
- Remove serde_ignored dependency for chainspec
|
||||||
|
- Fix rpc test eth chain spec
|
||||||
|
- Fix starting_nonce_test spec
|
||||||
|
- Improve block and transaction propagation ([#9954](https://github.com/paritytech/parity-ethereum/pull/9954))
|
||||||
|
- Refactor sync to add priority tasks.
|
||||||
|
- Send priority tasks notifications.
|
||||||
|
- Propagate blocks, optimize transactions.
|
||||||
|
- Implement transaction propagation. Use sync_channel.
|
||||||
|
- Tone down info.
|
||||||
|
- Prevent deadlock by not waiting forever for sync lock.
|
||||||
|
- Fix lock order.
|
||||||
|
- Don't use sync_channel to prevent deadlocks.
|
||||||
- Fix tests.
|
- Fix tests.
|
||||||
- Fix configuration tests.
|
- Fix unstable peers and slowness in sync ([#9967](https://github.com/paritytech/parity-ethereum/pull/9967))
|
||||||
- Rename to warp barrier.
|
- Don't sync all peers after each response
|
||||||
- Allow unsafe js eval on Parity Wallet. ([#8204](https://github.com/paritytech/parity/pull/8204))
|
- Update formating
|
||||||
- Update musicoin spec in line with gmc v2.6.2 ([#8242](https://github.com/paritytech/parity/pull/8242))
|
- Fix tests: add `continue_sync` to `Sync_step`
|
||||||
- Supress TemporaryInvalid verification failures. ([#8256](https://github.com/paritytech/parity/pull/8256))
|
- Update ethcore/sync/src/chain/mod.rs
|
||||||
- Include suicided accounts in state diff ([#8297](https://github.com/paritytech/parity/pull/8297))
|
- Fix rpc middlewares
|
||||||
- Include suicided accounts in state diff
|
- Fix Cargo.lock
|
||||||
- Shorten form match -> if let
|
- Json: resolve merge in spec
|
||||||
- Test suicide trace diff in State
|
- Rpc: fix starting_nonce_test
|
||||||
- Replace_home for password_files, reserved_peers and log_file ([#8324](https://github.com/paritytech/parity/pull/8324))
|
- Ci: allow nightl job to fail
|
||||||
- Replace_home for password_files, reserved_peers and log_file
|
|
||||||
- Typo: arg_log_file is Option
|
|
||||||
- Enable UI by default, but only display info page.
|
|
||||||
- Fix test.
|
|
||||||
- Fix naming and remove old todo.
|
|
||||||
- Change "wallet" with "browser UI"
|
|
||||||
- Change name Wallet -> UI ([#8164](https://github.com/paritytech/parity/pull/8164)) ([#8205](https://github.com/paritytech/parity/pull/8205))
|
|
||||||
- Change name Wallet -> UI
|
|
||||||
- Make warning bold
|
|
||||||
- Backport [#8099](https://github.com/paritytech/parity/pull/8099) ([#8132](https://github.com/paritytech/parity/pull/8132))
|
|
||||||
- WASM libs ([#8220](https://github.com/paritytech/parity/pull/8220))
|
|
||||||
- Bump wasm libs ([#8171](https://github.com/paritytech/parity/pull/8171))
|
|
||||||
- Bump wasmi version ([#8209](https://github.com/paritytech/parity/pull/8209))
|
|
||||||
- Update hyper to 0.11.24 ([#8203](https://github.com/paritytech/parity/pull/8203))
|
|
||||||
- Updated jsonrpc to include latest backports (beta) ([#8181](https://github.com/paritytech/parity/pull/8181))
|
|
||||||
- Updated jsonrpc to include latest backports
|
|
||||||
- Update dependencies.
|
|
||||||
|
|
||||||
## Parity [v1.10.0](https://github.com/paritytech/parity/releases/tag/v1.10.0) (2018-03-22)
|
## Parity-Ethereum [v2.2.1](https://github.com/paritytech/parity-ethereum/releases/tag/v2.2.1) (2018-11-15)
|
||||||
|
|
||||||
This is the Parity 1.10.0-beta release! Cool!
|
Parity-Ethereum 2.2.1-beta is the first v2.2 release, and might introduce features that break previous work flows, among others:
|
||||||
|
|
||||||
### Disabling the Parity Wallet
|
- Prevent zero network ID ([#9763](https://github.com/paritytech/parity-ethereum/pull/9763)) and drop support for Olympic testnet ([#9801](https://github.com/paritytech/parity-ethereum/pull/9801)): The Olympic test net is dead for years and never used a chain ID but network ID zero. Parity Ethereum is now preventing the network ID to be zero, thus Olympic support is dropped. Make sure to chose positive non-zero network IDs in future.
|
||||||
|
- Multithreaded snapshot creation ([#9239](https://github.com/paritytech/parity-ethereum/pull/9239)): adds a CLI argument `--snapshot-threads` which specifies the number of threads. This helps improving the performance of full nodes that wish to provide warp-snapshots for the network. The gain in performance comes with a slight drawback in increased snapshot size.
|
||||||
The **Parity Wallet (a.k.a. "UI") is now disabled by default**. We are preparing to split the wallet from the core client.
|
- Expose config max-round-blocks-to-import ([#9439](https://github.com/paritytech/parity-ethereum/pull/9439)): Parity Ethereum imports blocks in rounds. If at the end of any round, the queue is not empty, we consider it to be _importing_ and won't notify pubsub. On large re-orgs (10+ blocks), this is possible. The default `max_round_blocks_to_import` is increased to 12 and configurable via the `--max-round-blocks-to-import` CLI flag. With unstable network conditions, it is advised to increase the number. This shouldn't have any noticeable performance impact unless the number is set to really large.
|
||||||
|
- Increase Gas-floor-target and Gas Cap ([#9564](https://github.com/paritytech/parity-ethereum/pull/9564)): the default values for gas floor target are `8_000_000` and gas cap `10_000_000`, similar to Geth 1.8.15+.
|
||||||
To reactivate the parity wallet, you have to run Parity either with `parity --force-ui` (not recommended) or `parity ui` (deprecated) from the command line. Or, if you feel super fancy and want to test our pre-releases of the stand-alone electron wallet, head over to the [Parity-JS repositories and check the releases](https://github.com/Parity-JS/shell/releases).
|
- Produce portable binaries ([#9725](https://github.com/paritytech/parity-ethereum/pull/9725)): we now produce portable binaries, but it may incur some performance degradation. For ultimate performance it's now better to compile Parity Ethereum from source with `PORTABLE=OFF` environment variable.
|
||||||
|
- RPC: `parity_allTransactionHashes` ([#9745](https://github.com/paritytech/parity-ethereum/pull/9745)): Get all pending transactions from the queue with the high performant `parity_allTransactionHashes` RPC method.
|
||||||
Further reading:
|
- Support `eth_chainId` RPC method ([#9783](https://github.com/paritytech/parity-ethereum/pull/9783)): implements EIP-695 to get the chainID via RPC.
|
||||||
|
- AuRa: finalize blocks ([#9692](https://github.com/paritytech/parity-ethereum/pull/9692)): The AuRa engine was updated to emit ancestry actions to finalize blocks. The full client stores block finality in the database, the engine builds finality from an ancestry of `ExtendedHeader`; `is_epoch_end` was updated to take a vec of recently finalized headers; `is_epoch_end_light` was added which maintains the previous interface and is used by the light client since the client itself doesn't track finality.
|
||||||
- [Docs: Parity Wallet](https://wiki.parity.io/Parity-Wallet)
|
|
||||||
- [Docs: How to customize Parity UI?](https://wiki.parity.io/FAQ-Customize-Parity-UI.html)
|
|
||||||
- [Github: Parity-JS](https://github.com/parity-js)
|
|
||||||
|
|
||||||
### Introducing the Wasm VM
|
|
||||||
|
|
||||||
We are excited to announce support for **Wasm Smart Contracts on Kovan network**. The hard-fork to activate the Wasm-VM will take place on block `6_600_000`.
|
|
||||||
|
|
||||||
To enable Wasm contracts on your custom network, just schedule a `wasmActivationTransition` at your favorite block number (e.g., `42`, `666`, or `0xbada55`). To hack your first Wasm smart contracts in Rust, have a look at the [Parity Wasm Tutorials](https://github.com/paritytech/pwasm-tutorial).
|
|
||||||
|
|
||||||
Further reading:
|
|
||||||
|
|
||||||
- [Docs: WebAssembly (wasm)](https://wiki.parity.io/WebAssembly-Home)
|
|
||||||
- [Docs: Wasm VM Design](https://wiki.parity.io/WebAssembly-Design)
|
|
||||||
- [Docs: Wasm tutorials and examples](https://wiki.parity.io/WebAssembly-Links)
|
|
||||||
|
|
||||||
### Empty step messages in PoA
|
|
||||||
|
|
||||||
To **reduce blockchain bloat, proof-of-authority networks can now enable _empty step messages_ which replace empty blocks**. Each step message will be signed and broadcasted by the issuing authorities, and included and rewarded in the next non-empty block.
|
|
||||||
|
|
||||||
To enable empty step messages, set the `emptyStepsTransition` to your favorite block number. You can also specify a maximum number of empty steps with `maximumEmptySteps` in your chain spec.
|
|
||||||
|
|
||||||
### Other noteworthy changes
|
|
||||||
|
|
||||||
We removed the old database migrations from 2016. In case you upgrade Parity from a really, really old version, you will have to reset your database manually first with `parity <options> db kill`.
|
|
||||||
|
|
||||||
We fixed DELEGATECALL `from` and `to` fields, see [#7166](https://github.com/paritytech/parity/issues/7166).
|
|
||||||
|
|
||||||
We reduced the default USD per transaction value to 0.0001. Thanks, @MysticRyuujin!
|
|
||||||
|
|
||||||
The Musicoin chain is now enabled with Byzantium features starting at block `2_222_222`.
|
|
||||||
|
|
||||||
### Overview of all changes included
|
|
||||||
|
|
||||||
The full list of included changes:
|
The full list of included changes:
|
||||||
|
|
||||||
- Re-enable signer, even with no UI. ([#8167](https://github.com/paritytech/parity/pull/8167)) ([#8168](https://github.com/paritytech/parity/pull/8168))
|
- Backport to parity 2.2.1 beta ([#9905](https://github.com/paritytech/parity-ethereum/pull/9905))
|
||||||
- Re-enable signer, even with no UI.
|
- Bump version to 2.2.1
|
||||||
- Fix message.
|
- Fix: Intermittent failing CI due to addr in use ([#9885](https://github.com/paritytech/parity-ethereum/pull/9885))
|
||||||
- Beta Backports ([#8136](https://github.com/paritytech/parity/pull/8136))
|
- Fix Parity not closing on Ctrl-C ([#9886](https://github.com/paritytech/parity-ethereum/pull/9886))
|
||||||
- Support parity protocol. ([#8035](https://github.com/paritytech/parity/pull/8035))
|
- Fix json tracer overflow ([#9873](https://github.com/paritytech/parity-ethereum/pull/9873))
|
||||||
- updater: apply exponential backoff after download failure ([#8059](https://github.com/paritytech/parity/pull/8059))
|
- Fix docker script ([#9854](https://github.com/paritytech/parity-ethereum/pull/9854))
|
||||||
- updater: apply exponential backoff after download failure
|
- Add hardcoded headers for light client ([#9907](https://github.com/paritytech/parity-ethereum/pull/9907))
|
||||||
- updater: reset backoff on new release
|
- Gitlab-ci: make android release build succeed ([#9743](https://github.com/paritytech/parity-ethereum/pull/9743))
|
||||||
- Max code size on Kovan ([#8067](https://github.com/paritytech/parity/pull/8067))
|
- Allow to seal work on latest block ([#9876](https://github.com/paritytech/parity-ethereum/pull/9876))
|
||||||
- Enable code size limit on kovan
|
- Remove rust-toolchain file ([#9906](https://github.com/paritytech/parity-ethereum/pull/9906))
|
||||||
- Fix formatting.
|
- Light-fetch: Differentiate between out-of-gas/manual throw and use required gas from response on failure ([#9824](https://github.com/paritytech/parity-ethereum/pull/9824))
|
||||||
- Limit incoming connections. ([#8060](https://github.com/paritytech/parity/pull/8060))
|
- Eip-712 implementation ([#9631](https://github.com/paritytech/parity-ethereum/pull/9631))
|
||||||
- Limit ingress connections
|
- Eip-191 implementation ([#9701](https://github.com/paritytech/parity-ethereum/pull/9701))
|
||||||
- Optimized handshakes logging
|
- Simplify cargo audit ([#9918](https://github.com/paritytech/parity-ethereum/pull/9918))
|
||||||
- WASM libraries bump ([#7970](https://github.com/paritytech/parity/pull/7970))
|
- Fix performance issue importing Kovan blocks ([#9914](https://github.com/paritytech/parity-ethereum/pull/9914))
|
||||||
- update wasmi, parity-wasm, wasm-utils to latest version
|
- Ci: nuke the gitlab caches ([#9855](https://github.com/paritytech/parity-ethereum/pull/9855))
|
||||||
- Update to new wasmi & error handling
|
- Backports to parity beta 2.2.0 ([#9820](https://github.com/paritytech/parity-ethereum/pull/9820))
|
||||||
- also utilize new stack limiter
|
- Ci: remove failing tests for android, windows, and macos ([#9788](https://github.com/paritytech/parity-ethereum/pull/9788))
|
||||||
- fix typo
|
- Implement NoProof for json tests and update tests reference ([#9814](https://github.com/paritytech/parity-ethereum/pull/9814))
|
||||||
- replace dependency url
|
- Move state root verification before gas used ([#9841](https://github.com/paritytech/parity-ethereum/pull/9841))
|
||||||
- Cargo.lock update
|
- Classic.json Bootnode Update ([#9828](https://github.com/paritytech/parity-ethereum/pull/9828))
|
||||||
- add some dos protection ([#8084](https://github.com/paritytech/parity/pull/8084))
|
- Rpc: parity_allTransactionHashes ([#9745](https://github.com/paritytech/parity-ethereum/pull/9745))
|
||||||
- revert removing blooms ([#8066](https://github.com/paritytech/parity/pull/8066))
|
- Revert "prevent zero networkID ([#9763](https://github.com/paritytech/parity-ethereum/pull/9763))" ([#9815](https://github.com/paritytech/parity-ethereum/pull/9815))
|
||||||
- Revert "fix traces, removed bloomchain crate, closes [#7228](https://github.com/paritytech/parity/issues/7228), closes [#7167](https://github.com/paritytech/parity/issues/7167)"
|
- Allow zero chain id in EIP155 signing process ([#9792](https://github.com/paritytech/parity-ethereum/pull/9792))
|
||||||
- Revert "fixed broken logs ([#7934](https://github.com/paritytech/parity/pull/7934))"
|
- Add readiness check for docker container ([#9804](https://github.com/paritytech/parity-ethereum/pull/9804))
|
||||||
- fixed broken logs
|
- Insert dev account before unlocking ([#9813](https://github.com/paritytech/parity-ethereum/pull/9813))
|
||||||
- bring back old lock order
|
- Removed "rustup" & added new runner tag ([#9731](https://github.com/paritytech/parity-ethereum/pull/9731))
|
||||||
- remove migration v13
|
- Expose config max-round-blocks-to-import ([#9439](https://github.com/paritytech/parity-ethereum/pull/9439))
|
||||||
- revert CURRENT_VERSION to 12 in migration.rs
|
- Aura: finalize blocks ([#9692](https://github.com/paritytech/parity-ethereum/pull/9692))
|
||||||
- more dos protection ([#8104](https://github.com/paritytech/parity/pull/8104))
|
- Sync: retry different peer after empty subchain heads response ([#9753](https://github.com/paritytech/parity-ethereum/pull/9753))
|
||||||
- Const time comparison ([#8113](https://github.com/paritytech/parity/pull/8113))
|
- Fix(light-rpc/parity) : Remove unused client ([#9802](https://github.com/paritytech/parity-ethereum/pull/9802))
|
||||||
- Use `subtle::slices_equal` for constant time comparison.
|
- Drops support for olympic testnet, closes [#9800](https://github.com/paritytech/parity-ethereum/issues/9800) ([#9801](https://github.com/paritytech/parity-ethereum/pull/9801))
|
||||||
- Also update the existing version of subtle in `ethcrypto` from 0.1 to 0.5
|
- Replace `tokio_core` with `tokio` (`ring` -> 0.13) ([#9657](https://github.com/paritytech/parity-ethereum/pull/9657))
|
||||||
- Test specifically for InvalidPassword error.
|
- Support eth_chainId RPC method ([#9783](https://github.com/paritytech/parity-ethereum/pull/9783))
|
||||||
- fix trace filter returning returning unrelated reward calls, closes #8070 ([#8098](https://github.com/paritytech/parity/pull/8098))
|
- Ethcore: bump ropsten forkblock checkpoint ([#9775](https://github.com/paritytech/parity-ethereum/pull/9775))
|
||||||
- network: init discovery using healthy nodes ([#8061](https://github.com/paritytech/parity/pull/8061))
|
- Docs: changelogs for 2.0.8 and 2.1.3 ([#9758](https://github.com/paritytech/parity-ethereum/pull/9758))
|
||||||
- network: init discovery using healthy nodes
|
- Prevent zero networkID ([#9763](https://github.com/paritytech/parity-ethereum/pull/9763))
|
||||||
- network: fix style grumble
|
- Skip seal fields count check when --no-seal-check is used ([#9757](https://github.com/paritytech/parity-ethereum/pull/9757))
|
||||||
- network: fix typo
|
- Aura: fix panic on extra_info with unsealed block ([#9755](https://github.com/paritytech/parity-ethereum/pull/9755))
|
||||||
- Postpone Kovan hard fork ([#8137](https://github.com/paritytech/parity/pull/8137))
|
- Docs: update changelogs ([#9742](https://github.com/paritytech/parity-ethereum/pull/9742))
|
||||||
- ethcore: postpone Kovan hard fork
|
- Removed extra assert in generation_session_is_removed_when_succeeded ([#9738](https://github.com/paritytech/parity-ethereum/pull/9738))
|
||||||
- util: update version fork metadata
|
- Make checkpoint_storage_at use plain loop instead of recursion ([#9734](https://github.com/paritytech/parity-ethereum/pull/9734))
|
||||||
- Disable UI by default. ([#8105](https://github.com/paritytech/parity/pull/8105))
|
- Use signed 256-bit integer for sstore gas refund substate ([#9746](https://github.com/paritytech/parity-ethereum/pull/9746))
|
||||||
- dapps: update parity-ui dependencies ([#8160](https://github.com/paritytech/parity/pull/8160))
|
- Heads ref not present for branches beta and stable ([#9741](https://github.com/paritytech/parity-ethereum/pull/9741))
|
||||||
- Probe changes one step deeper ([#8134](https://github.com/paritytech/parity/pull/8134)) ([#8135](https://github.com/paritytech/parity/pull/8135))
|
- Add Callisto support ([#9534](https://github.com/paritytech/parity-ethereum/pull/9534))
|
||||||
- Beta backports ([#8053](https://github.com/paritytech/parity/pull/8053))
|
- Add --force to cargo audit install script ([#9735](https://github.com/paritytech/parity-ethereum/pull/9735))
|
||||||
- CI: Fix cargo cache ([#7968](https://github.com/paritytech/parity/pull/7968))
|
- Remove unused expired value from Handshake ([#9732](https://github.com/paritytech/parity-ethereum/pull/9732))
|
||||||
- Fix cache
|
- Add hardcoded headers ([#9730](https://github.com/paritytech/parity-ethereum/pull/9730))
|
||||||
- Only clean locked cargo cache on windows
|
- Produce portable binaries ([#9725](https://github.com/paritytech/parity-ethereum/pull/9725))
|
||||||
- fixed ethstore sign ([#8026](https://github.com/paritytech/parity/pull/8026))
|
- Gitlab ci: releasable_branches: change variables condition to schedule ([#9729](https://github.com/paritytech/parity-ethereum/pull/9729))
|
||||||
- fixed parsing ethash seals and verify_block_undordered ([#8031](https://github.com/paritytech/parity/pull/8031))
|
- Update a few parity-common dependencies ([#9663](https://github.com/paritytech/parity-ethereum/pull/9663))
|
||||||
- fix for verify_block_basic crashing on invalid transaction rlp ([#8032](https://github.com/paritytech/parity/pull/8032))
|
- Hf in POA Core (2018-10-22) ([#9724](https://github.com/paritytech/parity-ethereum/pull/9724))
|
||||||
- fix cache & snapcraft CI build ([#8052](https://github.com/paritytech/parity/pull/8052))
|
- Schedule nightly builds ([#9717](https://github.com/paritytech/parity-ethereum/pull/9717))
|
||||||
- Add MCIP-6 Byzyantium transition to Musicoin spec ([#7841](https://github.com/paritytech/parity/pull/7841))
|
- Fix ancient blocks sync ([#9531](https://github.com/paritytech/parity-ethereum/pull/9531))
|
||||||
- Add test chain spec for musicoin byzantium testnet
|
- Ci: Skip docs job for nightly ([#9693](https://github.com/paritytech/parity-ethereum/pull/9693))
|
||||||
- Add MCIP-6 Byzyantium transition to Musicoin spec
|
- Fix (light/provider) : Make `read_only executions` read-only ([#9591](https://github.com/paritytech/parity-ethereum/pull/9591))
|
||||||
- Update mcip6_byz.json
|
- Ethcore: fix detection of major import ([#9552](https://github.com/paritytech/parity-ethereum/pull/9552))
|
||||||
- ethcore: update musicoin byzantium block number
|
- Return 0 on error ([#9705](https://github.com/paritytech/parity-ethereum/pull/9705))
|
||||||
- ethcore: update musicoin bootnodes
|
- Ethcore: delay ropsten hardfork ([#9704](https://github.com/paritytech/parity-ethereum/pull/9704))
|
||||||
- Update musicoin.json
|
- Make instantSeal engine backwards compatible, closes [#9696](https://github.com/paritytech/parity-ethereum/issues/9696) ([#9700](https://github.com/paritytech/parity-ethereum/pull/9700))
|
||||||
- More bootnodes.
|
- Implement CREATE2 gas changes and fix some potential overflowing ([#9694](https://github.com/paritytech/parity-ethereum/pull/9694))
|
||||||
- Make 1.10 beta ([#8022](https://github.com/paritytech/parity/pull/8022))
|
- Don't hash the init_code of CREATE. ([#9688](https://github.com/paritytech/parity-ethereum/pull/9688))
|
||||||
- Make 1.10 beta
|
- Ethcore: minor optimization of modexp by using LR exponentiation ([#9697](https://github.com/paritytech/parity-ethereum/pull/9697))
|
||||||
- Fix gitlab builds
|
- Removed redundant clone before each block import ([#9683](https://github.com/paritytech/parity-ethereum/pull/9683))
|
||||||
- SecretStore: secretstore_generateDocumentKey RPC ([#7864](https://github.com/paritytech/parity/pull/7864))
|
- Add Foundation Bootnodes ([#9666](https://github.com/paritytech/parity-ethereum/pull/9666))
|
||||||
- SecretStore: ECDSA session for cases when 2*t < N ([#7739](https://github.com/paritytech/parity/pull/7739))
|
- Docker: run as parity user ([#9689](https://github.com/paritytech/parity-ethereum/pull/9689))
|
||||||
- bump tiny-keccak ([#8019](https://github.com/paritytech/parity/pull/8019))
|
- Ethcore: mcip3 block reward contract ([#9605](https://github.com/paritytech/parity-ethereum/pull/9605))
|
||||||
- Remove un-necessary comment ([#8014](https://github.com/paritytech/parity/pull/8014))
|
- Verify block syncing responses against requests ([#9670](https://github.com/paritytech/parity-ethereum/pull/9670))
|
||||||
- clean up account fmt::Debug ([#7983](https://github.com/paritytech/parity/pull/7983))
|
- Add a new RPC `parity_submitWorkDetail` similar `eth_submitWork` but return block hash ([#9404](https://github.com/paritytech/parity-ethereum/pull/9404))
|
||||||
- improve quality of vote_collector module ([#7984](https://github.com/paritytech/parity/pull/7984))
|
- Resumable EVM and heap-allocated callstack ([#9360](https://github.com/paritytech/parity-ethereum/pull/9360))
|
||||||
- ExecutedBlock cleanup ([#7991](https://github.com/paritytech/parity/pull/7991))
|
- Update parity-wordlist library ([#9682](https://github.com/paritytech/parity-ethereum/pull/9682))
|
||||||
- Hardware-wallet/usb-subscribe-refactor ([#7860](https://github.com/paritytech/parity/pull/7860))
|
- Ci: Remove unnecessary pipes ([#9681](https://github.com/paritytech/parity-ethereum/pull/9681))
|
||||||
- remove wildcard imports from views, make tests more idiomatic ([#7986](https://github.com/paritytech/parity/pull/7986))
|
- Test.sh: use cargo --target for platforms other than linux, win or mac ([#9650](https://github.com/paritytech/parity-ethereum/pull/9650))
|
||||||
- moved PerfTimer to a separate crate - "trace-time" ([#7985](https://github.com/paritytech/parity/pull/7985))
|
- Ci: fix push script ([#9679](https://github.com/paritytech/parity-ethereum/pull/9679))
|
||||||
- clean up ethcore::spec module imports ([#7990](https://github.com/paritytech/parity/pull/7990))
|
- Hardfork the testnets ([#9562](https://github.com/paritytech/parity-ethereum/pull/9562))
|
||||||
- rpc: don't include current block in new_block_filter ([#7982](https://github.com/paritytech/parity/pull/7982))
|
- Calculate sha3 instead of sha256 for push-release. ([#9673](https://github.com/paritytech/parity-ethereum/pull/9673))
|
||||||
- fix traces, removed bloomchain crate ([#7979](https://github.com/paritytech/parity/pull/7979))
|
- Ethcore-io retries failed work steal ([#9651](https://github.com/paritytech/parity-ethereum/pull/9651))
|
||||||
- simplify compression and move it out of rlp crate ([#7957](https://github.com/paritytech/parity/pull/7957))
|
- Fix(light_fetch): avoid race with BlockNumber::Latest ([#9665](https://github.com/paritytech/parity-ethereum/pull/9665))
|
||||||
- removed old migrations ([#7974](https://github.com/paritytech/parity/pull/7974))
|
- Test fix for windows cache name... ([#9658](https://github.com/paritytech/parity-ethereum/pull/9658))
|
||||||
- Reject too large packets in snapshot sync. ([#7977](https://github.com/paritytech/parity/pull/7977))
|
- Refactor(fetch) : light use only one `DNS` thread ([#9647](https://github.com/paritytech/parity-ethereum/pull/9647))
|
||||||
- fixed broken logs ([#7934](https://github.com/paritytech/parity/pull/7934))
|
- Ethereum libfuzzer integration small change ([#9547](https://github.com/paritytech/parity-ethereum/pull/9547))
|
||||||
- Increase max download limit to 128MB ([#7965](https://github.com/paritytech/parity/pull/7965))
|
- Cli: remove reference to --no-ui in --unlock flag help ([#9616](https://github.com/paritytech/parity-ethereum/pull/9616))
|
||||||
- Calculate proper keccak256/sha3 using parity. ([#7953](https://github.com/paritytech/parity/pull/7953))
|
- Remove master from releasable branches ([#9655](https://github.com/paritytech/parity-ethereum/pull/9655))
|
||||||
- Add changelog for 1.8.10 stable and 1.9.3 beta ([#7947](https://github.com/paritytech/parity/pull/7947))
|
- Ethcore/VerificationQueue don't spawn up extra `worker-threads` when explictly specified not to ([#9620](https://github.com/paritytech/parity-ethereum/pull/9620))
|
||||||
- kvdb-rocksdb: remove buffered operations when committing transaction ([#7950](https://github.com/paritytech/parity/pull/7950))
|
- Rpc: parity_getBlockReceipts ([#9527](https://github.com/paritytech/parity-ethereum/pull/9527))
|
||||||
- Bump WebSockets ([#7952](https://github.com/paritytech/parity/pull/7952))
|
- Remove unused dependencies ([#9589](https://github.com/paritytech/parity-ethereum/pull/9589))
|
||||||
- removed redundant Bloom conversions ([#7932](https://github.com/paritytech/parity/pull/7932))
|
- Ignore key_server_cluster randomly failing tests ([#9639](https://github.com/paritytech/parity-ethereum/pull/9639))
|
||||||
- simplify RefInfo fmt ([#7929](https://github.com/paritytech/parity/pull/7929))
|
- Ethcore: handle vm exception when estimating gas ([#9615](https://github.com/paritytech/parity-ethereum/pull/9615))
|
||||||
- Kovan WASM fork code ([#7849](https://github.com/paritytech/parity/pull/7849))
|
- Fix bad-block reporting no reason ([#9638](https://github.com/paritytech/parity-ethereum/pull/9638))
|
||||||
- bring back trie and triehash benches ([#7926](https://github.com/paritytech/parity/pull/7926))
|
- Use static call and apparent value transfer for block reward contract code ([#9603](https://github.com/paritytech/parity-ethereum/pull/9603))
|
||||||
- removed redundant PodAccount::new method ([#7928](https://github.com/paritytech/parity/pull/7928))
|
- Hf in POA Sokol (2018-09-19) ([#9607](https://github.com/paritytech/parity-ethereum/pull/9607))
|
||||||
- removed dummy wrapper structure - LogGroupPosition ([#7922](https://github.com/paritytech/parity/pull/7922))
|
- Bump smallvec to 0.6 in ethcore-light, ethstore and whisper ([#9588](https://github.com/paritytech/parity-ethereum/pull/9588))
|
||||||
- spec: Validate required divisor fields are not 0 ([#7933](https://github.com/paritytech/parity/pull/7933))
|
- Add constantinople conf to EvmTestClient. ([#9570](https://github.com/paritytech/parity-ethereum/pull/9570))
|
||||||
- simplify Client::filter_traces method ([#7936](https://github.com/paritytech/parity/pull/7936))
|
- Fix(network): don't disconnect reserved peers ([#9608](https://github.com/paritytech/parity-ethereum/pull/9608))
|
||||||
- gitlab cache ([#7921](https://github.com/paritytech/parity/pull/7921))
|
- Fix failing node-table tests on mac os, closes [#9632](https://github.com/paritytech/parity-ethereum/issues/9632) ([#9633](https://github.com/paritytech/parity-ethereum/pull/9633))
|
||||||
- Fix a division by zero in light client RPC handler ([#7917](https://github.com/paritytech/parity/pull/7917))
|
- Update ropsten.json ([#9602](https://github.com/paritytech/parity-ethereum/pull/9602))
|
||||||
- triehash optimisations ([#7920](https://github.com/paritytech/parity/pull/7920))
|
- Simplify ethcore errors by removing BlockImportError ([#9593](https://github.com/paritytech/parity-ethereum/pull/9593))
|
||||||
- removed redundant Blockchain::db method ([#7919](https://github.com/paritytech/parity/pull/7919))
|
- Fix windows compilation, replaces [#9561](https://github.com/paritytech/parity-ethereum/issues/9561) ([#9621](https://github.com/paritytech/parity-ethereum/pull/9621))
|
||||||
- removed redundant Blockchain::rewind method ([#7918](https://github.com/paritytech/parity/pull/7918))
|
- Master: rpc-docs set github token ([#9610](https://github.com/paritytech/parity-ethereum/pull/9610))
|
||||||
- Pending transactions subscription ([#7906](https://github.com/paritytech/parity/pull/7906))
|
- Docs: add changelogs for 1.11.10, 1.11.11, 2.0.3, 2.0.4, 2.0.5, 2.0.6, 2.1.0, and 2.1.1 ([#9554](https://github.com/paritytech/parity-ethereum/pull/9554))
|
||||||
- removed redundant otry! macro from ethcore ([#7916](https://github.com/paritytech/parity/pull/7916))
|
- Docs(rpc): annotate tag with the provided message ([#9601](https://github.com/paritytech/parity-ethereum/pull/9601))
|
||||||
- Make block generator easier to use ([#7888](https://github.com/paritytech/parity/pull/7888))
|
- Ci: fix regex roll_eyes ([#9597](https://github.com/paritytech/parity-ethereum/pull/9597))
|
||||||
- ECIP 1041 - Remove Difficulty Bomb ([#7905](https://github.com/paritytech/parity/pull/7905))
|
- Remove snapcraft clean ([#9585](https://github.com/paritytech/parity-ethereum/pull/9585))
|
||||||
- Fix CSP for dapps that require eval. ([#7867](https://github.com/paritytech/parity/pull/7867))
|
- Add snapcraft package image (master) ([#9584](https://github.com/paritytech/parity-ethereum/pull/9584))
|
||||||
- Fix gitlab ([#7901](https://github.com/paritytech/parity/pull/7901))
|
- Docs(rpc): push the branch along with tags ([#9578](https://github.com/paritytech/parity-ethereum/pull/9578))
|
||||||
- Gitlb snap master patch ([#7900](https://github.com/paritytech/parity/pull/7900))
|
- Fix typo for jsonrpc-threads flag ([#9574](https://github.com/paritytech/parity-ethereum/pull/9574))
|
||||||
- fix snap build master ([#7896](https://github.com/paritytech/parity/pull/7896))
|
- Fix informant compile ([#9571](https://github.com/paritytech/parity-ethereum/pull/9571))
|
||||||
- Fix wallet import ([#7873](https://github.com/paritytech/parity/pull/7873))
|
- Added ropsten bootnodes ([#9569](https://github.com/paritytech/parity-ethereum/pull/9569))
|
||||||
- Fix snapcraft nightly ([#7884](https://github.com/paritytech/parity/pull/7884))
|
- Increase Gas-floor-target and Gas Cap ([#9564](https://github.com/paritytech/parity-ethereum/pull/9564))
|
||||||
- Add a timeout for light client sync requests ([#7848](https://github.com/paritytech/parity/pull/7848))
|
- While working on the platform tests make them non-breaking ([#9563](https://github.com/paritytech/parity-ethereum/pull/9563))
|
||||||
- SecretStore: fixed test ([#7878](https://github.com/paritytech/parity/pull/7878))
|
- Improve P2P discovery ([#9526](https://github.com/paritytech/parity-ethereum/pull/9526))
|
||||||
- Fix checksums and auto-update push ([#7846](https://github.com/paritytech/parity/pull/7846))
|
- Move dockerfile for android build container to scripts repo ([#9560](https://github.com/paritytech/parity-ethereum/pull/9560))
|
||||||
- Forward-port snap fixes ([#7831](https://github.com/paritytech/parity/pull/7831))
|
- Simultaneous platform tests WIP ([#9557](https://github.com/paritytech/parity-ethereum/pull/9557))
|
||||||
- Update gitlab-test.sh ([#7883](https://github.com/paritytech/parity/pull/7883))
|
- Update ethabi-derive, serde, serde_json, serde_derive, syn && quote ([#9553](https://github.com/paritytech/parity-ethereum/pull/9553))
|
||||||
- Fix installer binary names for macos and windows ([#7881](https://github.com/paritytech/parity/pull/7881))
|
- Ci: fix rpc docs generation 2 ([#9550](https://github.com/paritytech/parity-ethereum/pull/9550))
|
||||||
- Fix string typo: "develoopment" -> "development" ([#7874](https://github.com/paritytech/parity/pull/7874))
|
- Ci: always run build pipelines for win, mac, linux, and android ([#9537](https://github.com/paritytech/parity-ethereum/pull/9537))
|
||||||
- Update the instructions to install the stable snap ([#7876](https://github.com/paritytech/parity/pull/7876))
|
- Multithreaded snapshot creation ([#9239](https://github.com/paritytech/parity-ethereum/pull/9239))
|
||||||
- SecretStore: 'broadcast' decryption session ([#7843](https://github.com/paritytech/parity/pull/7843))
|
- New ethabi ([#9511](https://github.com/paritytech/parity-ethereum/pull/9511))
|
||||||
- Flush keyfiles. Resolves #7632 ([#7868](https://github.com/paritytech/parity/pull/7868))
|
- Remove initial token for WS. ([#9545](https://github.com/paritytech/parity-ethereum/pull/9545))
|
||||||
- Read registry_address from given block ([#7866](https://github.com/paritytech/parity/pull/7866))
|
- Net_version caches network_id to avoid redundant aquire of sync readlock ([#9544](https://github.com/paritytech/parity-ethereum/pull/9544))
|
||||||
- Clean up docs formatting for Wasm runtime ([#7869](https://github.com/paritytech/parity/pull/7869))
|
- Correct before_script for nightly build versions ([#9543](https://github.com/paritytech/parity-ethereum/pull/9543))
|
||||||
- WASM: Disable internal memory ([#7842](https://github.com/paritytech/parity/pull/7842))
|
- Deps: bump kvdb-rocksdb to 0.1.4 ([#9539](https://github.com/paritytech/parity-ethereum/pull/9539))
|
||||||
- Update gitlab-build.sh ([#7855](https://github.com/paritytech/parity/pull/7855))
|
- State: test when contract creation fails, old storage values should re-appear ([#9532](https://github.com/paritytech/parity-ethereum/pull/9532))
|
||||||
- ethabi version 5 ([#7723](https://github.com/paritytech/parity/pull/7723))
|
- Allow dropping light client RPC query with no results ([#9318](https://github.com/paritytech/parity-ethereum/pull/9318))
|
||||||
- Light client: randomize the peer we dispatch requests to ([#7844](https://github.com/paritytech/parity/pull/7844))
|
- Bump master to 2.2.0 ([#9517](https://github.com/paritytech/parity-ethereum/pull/9517))
|
||||||
- Store updater metadata in a single place ([#7832](https://github.com/paritytech/parity/pull/7832))
|
- Enable all Constantinople hard fork changes in constantinople_test.json ([#9505](https://github.com/paritytech/parity-ethereum/pull/9505))
|
||||||
- Add new EF ropstens nodes. ([#7824](https://github.com/paritytech/parity/pull/7824))
|
- [Light] Validate `account balance` before importing transactions ([#9417](https://github.com/paritytech/parity-ethereum/pull/9417))
|
||||||
- refactor stratum to remove retain cycle ([#7827](https://github.com/paritytech/parity/pull/7827))
|
- In create memory calculation is the same for create2 because the additional parameter was popped before. ([#9522](https://github.com/paritytech/parity-ethereum/pull/9522))
|
||||||
- Bump jsonrpc. ([#7828](https://github.com/paritytech/parity/pull/7828))
|
- Update patricia trie to 0.2.2 ([#9525](https://github.com/paritytech/parity-ethereum/pull/9525))
|
||||||
- Add binary identifiers and sha256sum to builds ([#7830](https://github.com/paritytech/parity/pull/7830))
|
- Replace hardcoded JSON with serde json! macro ([#9489](https://github.com/paritytech/parity-ethereum/pull/9489))
|
||||||
- Update references to UI shell & wallet ([#7808](https://github.com/paritytech/parity/pull/7808))
|
- Fix typo in version string ([#9516](https://github.com/paritytech/parity-ethereum/pull/9516))
|
||||||
- Adjust storage update evm-style ([#7812](https://github.com/paritytech/parity/pull/7812))
|
|
||||||
- Updated WASM Runtime & new interpreter (wasmi) ([#7796](https://github.com/paritytech/parity/pull/7796))
|
|
||||||
- SecretStore: ignore removed authorities when running auto-migration ([#7674](https://github.com/paritytech/parity/pull/7674))
|
|
||||||
- Fix build ([#7807](https://github.com/paritytech/parity/pull/7807))
|
|
||||||
- Move js & js-old code to github.com/parity-js ([#7685](https://github.com/paritytech/parity/pull/7685))
|
|
||||||
- More changelogs :) ([#7782](https://github.com/paritytech/parity/pull/7782))
|
|
||||||
- Actualized API set in help ([#7790](https://github.com/paritytech/parity/pull/7790))
|
|
||||||
- Removed obsolete file ([#7788](https://github.com/paritytech/parity/pull/7788))
|
|
||||||
- Update ropsten bootnodes ([#7776](https://github.com/paritytech/parity/pull/7776))
|
|
||||||
- CHANGELOG for 1.9.1 and 1.8.8 ([#7775](https://github.com/paritytech/parity/pull/7775))
|
|
||||||
- Enable byzantium features on non-ethash chains ([#7753](https://github.com/paritytech/parity/pull/7753))
|
|
||||||
- Fix client not being dropped on shutdown ([#7695](https://github.com/paritytech/parity/pull/7695))
|
|
||||||
- Filter-out nodes.json ([#7716](https://github.com/paritytech/parity/pull/7716))
|
|
||||||
- Removes redundant parentheses ([#7721](https://github.com/paritytech/parity/pull/7721))
|
|
||||||
- Transaction-pool fixes ([#7741](https://github.com/paritytech/parity/pull/7741))
|
|
||||||
- More visible download link in README.md ([#7707](https://github.com/paritytech/parity/pull/7707))
|
|
||||||
- Changelog for 1.9.0 ([#7664](https://github.com/paritytech/parity/pull/7664))
|
|
||||||
- Add scroll when too many accounts ([#7677](https://github.com/paritytech/parity/pull/7677))
|
|
||||||
- SecretStore: return HTTP 403 (access denied) if consensus is unreachable ([#7656](https://github.com/paritytech/parity/pull/7656))
|
|
||||||
- Moved StopGaurd to it's own crate ([#7635](https://github.com/paritytech/parity/pull/7635))
|
|
||||||
|
|
||||||
## Previous releases
|
## Previous releases
|
||||||
|
|
||||||
- [CHANGELOG-1.9](docs/CHANGELOG-1.9.md) (_stable_)
|
- [CHANGELOG-2.1](docs/CHANGELOG-2.1.md) (_stable_)
|
||||||
|
- [CHANGELOG-2.0](docs/CHANGELOG-2.0.md) (EOL: 2018-11-15)
|
||||||
|
- [CHANGELOG-1.11](docs/CHANGELOG-1.11.md) (EOL: 2018-09-19)
|
||||||
|
- [CHANGELOG-1.10](docs/CHANGELOG-1.10.md) (EOL: 2018-07-18)
|
||||||
|
- [CHANGELOG-1.9](docs/CHANGELOG-1.9.md) (EOL: 2018-05-09)
|
||||||
- [CHANGELOG-1.8](docs/CHANGELOG-1.8.md) (EOL: 2018-03-22)
|
- [CHANGELOG-1.8](docs/CHANGELOG-1.8.md) (EOL: 2018-03-22)
|
||||||
- [CHANGELOG-1.7](docs/CHANGELOG-1.7.md) (EOL: 2018-01-25)
|
- [CHANGELOG-1.7](docs/CHANGELOG-1.7.md) (EOL: 2018-01-25)
|
||||||
- [CHANGELOG-1.6](docs/CHANGELOG-1.6.md) (EOL: 2017-10-15)
|
- [CHANGELOG-1.6](docs/CHANGELOG-1.6.md) (EOL: 2017-10-15)
|
||||||
|
|||||||
4458
Cargo.lock
generated
4458
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
120
Cargo.toml
120
Cargo.toml
@@ -1,16 +1,16 @@
|
|||||||
[package]
|
[package]
|
||||||
description = "Parity Ethereum client"
|
description = "Parity Ethereum client"
|
||||||
name = "parity"
|
name = "parity-ethereum"
|
||||||
# NOTE Make sure to update util/version/Cargo.toml as well
|
# NOTE Make sure to update util/version/Cargo.toml as well
|
||||||
version = "1.11.4"
|
version = "2.3.3"
|
||||||
license = "GPL-3.0"
|
license = "GPL-3.0"
|
||||||
authors = ["Parity Technologies <admin@parity.io>"]
|
authors = ["Parity Technologies <admin@parity.io>"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
log = "0.3"
|
blooms-db = { path = "util/blooms-db" }
|
||||||
env_logger = "0.4"
|
log = "0.4"
|
||||||
rustc-hex = "1.0"
|
rustc-hex = "1.0"
|
||||||
docopt = "0.8"
|
docopt = "1.0"
|
||||||
clap = "2"
|
clap = "2"
|
||||||
term_size = "0.3"
|
term_size = "0.3"
|
||||||
textwrap = "0.9"
|
textwrap = "0.9"
|
||||||
@@ -19,59 +19,57 @@ number_prefix = "0.2"
|
|||||||
rpassword = "1.0"
|
rpassword = "1.0"
|
||||||
semver = "0.9"
|
semver = "0.9"
|
||||||
ansi_term = "0.10"
|
ansi_term = "0.10"
|
||||||
parking_lot = "0.5"
|
parking_lot = "0.7"
|
||||||
regex = "0.2"
|
regex = "1.0"
|
||||||
atty = "0.2.8"
|
atty = "0.2.8"
|
||||||
toml = "0.4"
|
toml = "0.4"
|
||||||
serde = "1.0"
|
serde = "1.0"
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
serde_derive = "1.0"
|
serde_derive = "1.0"
|
||||||
futures = "0.1"
|
futures = "0.1"
|
||||||
futures-cpupool = "0.1"
|
|
||||||
fdlimit = "0.1"
|
fdlimit = "0.1"
|
||||||
ctrlc = { git = "https://github.com/paritytech/rust-ctrlc.git" }
|
ctrlc = { git = "https://github.com/paritytech/rust-ctrlc.git" }
|
||||||
jsonrpc-core = { git = "https://github.com/paritytech/jsonrpc.git", branch = "parity-1.11" }
|
jsonrpc-core = { git = "https://github.com/paritytech/jsonrpc.git", branch = "parity-2.2" }
|
||||||
ethcore = { path = "ethcore" }
|
ethcore = { path = "ethcore", features = ["parity"] }
|
||||||
ethcore-bytes = { path = "util/bytes" }
|
parity-bytes = "0.1"
|
||||||
|
common-types = { path = "ethcore/types" }
|
||||||
|
ethcore-blockchain = { path = "ethcore/blockchain" }
|
||||||
|
ethcore-call-contract = { path = "ethcore/call-contract"}
|
||||||
|
ethcore-db = { path = "ethcore/db" }
|
||||||
ethcore-io = { path = "util/io" }
|
ethcore-io = { path = "util/io" }
|
||||||
ethcore-light = { path = "ethcore/light" }
|
ethcore-light = { path = "ethcore/light" }
|
||||||
ethcore-logger = { path = "logger" }
|
ethcore-logger = { path = "parity/logger" }
|
||||||
ethcore-miner = { path = "miner" }
|
ethcore-miner = { path = "miner" }
|
||||||
ethcore-network = { path = "util/network" }
|
ethcore-network = { path = "util/network" }
|
||||||
ethcore-private-tx = { path = "ethcore/private-tx" }
|
ethcore-private-tx = { path = "ethcore/private-tx" }
|
||||||
ethcore-service = { path = "ethcore/service" }
|
ethcore-service = { path = "ethcore/service" }
|
||||||
ethcore-stratum = { path = "ethcore/stratum" }
|
|
||||||
ethcore-sync = { path = "ethcore/sync" }
|
ethcore-sync = { path = "ethcore/sync" }
|
||||||
ethcore-transaction = { path = "ethcore/transaction" }
|
ethstore = { path = "accounts/ethstore" }
|
||||||
ethereum-types = "0.3"
|
ethereum-types = "0.4"
|
||||||
node-filter = { path = "ethcore/node_filter" }
|
node-filter = { path = "ethcore/node-filter" }
|
||||||
ethkey = { path = "ethkey" }
|
ethkey = { path = "accounts/ethkey" }
|
||||||
node-health = { path = "dapps/node-health" }
|
rlp = { version = "0.3.0", features = ["ethereum"] }
|
||||||
rlp = { path = "util/rlp" }
|
cli-signer= { path = "cli-signer" }
|
||||||
rpc-cli = { path = "rpc_cli" }
|
parity-hash-fetch = { path = "updater/hash-fetch" }
|
||||||
parity-hash-fetch = { path = "hash-fetch" }
|
|
||||||
parity-ipfs-api = { path = "ipfs" }
|
parity-ipfs-api = { path = "ipfs" }
|
||||||
parity-local-store = { path = "local-store" }
|
parity-local-store = { path = "miner/local-store" }
|
||||||
parity-reactor = { path = "util/reactor" }
|
parity-runtime = { path = "util/runtime" }
|
||||||
parity-rpc = { path = "rpc" }
|
parity-rpc = { path = "rpc" }
|
||||||
parity-rpc-client = { path = "rpc_client" }
|
|
||||||
parity-updater = { path = "updater" }
|
parity-updater = { path = "updater" }
|
||||||
parity-version = { path = "util/version" }
|
parity-version = { path = "util/version" }
|
||||||
parity-whisper = { path = "whisper" }
|
parity-whisper = { path = "whisper" }
|
||||||
path = { path = "util/path" }
|
parity-path = "0.1"
|
||||||
dir = { path = "util/dir" }
|
dir = { path = "util/dir" }
|
||||||
panic_hook = { path = "util/panic_hook" }
|
panic_hook = { path = "util/panic-hook" }
|
||||||
keccak-hash = { path = "util/hash" }
|
keccak-hash = "0.1"
|
||||||
migration-rocksdb = { path = "util/migration-rocksdb" }
|
migration-rocksdb = { path = "util/migration-rocksdb" }
|
||||||
kvdb = { path = "util/kvdb" }
|
kvdb = "0.1"
|
||||||
kvdb-rocksdb = { path = "util/kvdb-rocksdb" }
|
kvdb-rocksdb = "0.1.3"
|
||||||
journaldb = { path = "util/journaldb" }
|
journaldb = { path = "util/journaldb" }
|
||||||
mem = { path = "util/mem" }
|
|
||||||
|
|
||||||
parity-dapps = { path = "dapps", optional = true }
|
ethcore-secretstore = { path = "secret-store", optional = true }
|
||||||
ethcore-secretstore = { path = "secret_store", optional = true }
|
|
||||||
|
|
||||||
registrar = { path = "registrar" }
|
registrar = { path = "util/registrar" }
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
rustc_version = "0.2"
|
rustc_version = "0.2"
|
||||||
@@ -82,58 +80,64 @@ ipnetwork = "0.12.6"
|
|||||||
tempdir = "0.3"
|
tempdir = "0.3"
|
||||||
fake-fetch = { path = "util/fake-fetch" }
|
fake-fetch = { path = "util/fake-fetch" }
|
||||||
|
|
||||||
|
[target.'cfg(not(windows))'.dependencies]
|
||||||
|
daemonize = "0.3"
|
||||||
|
|
||||||
[target.'cfg(windows)'.dependencies]
|
[target.'cfg(windows)'.dependencies]
|
||||||
winapi = { version = "0.3.4", features = ["winsock2", "winuser", "shellapi"] }
|
winapi = { version = "0.3.4", features = ["winsock2", "winuser", "shellapi"] }
|
||||||
|
|
||||||
[target.'cfg(not(windows))'.dependencies]
|
|
||||||
daemonize = { git = "https://github.com/paritytech/daemonize" }
|
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["ui-precompiled"]
|
miner-debug = ["ethcore/miner-debug"]
|
||||||
ui = [
|
|
||||||
"ui-enabled",
|
|
||||||
"parity-dapps/ui",
|
|
||||||
]
|
|
||||||
ui-precompiled = [
|
|
||||||
"ui-enabled",
|
|
||||||
"parity-dapps/ui-precompiled",
|
|
||||||
]
|
|
||||||
ui-enabled = ["dapps"]
|
|
||||||
dapps = ["parity-dapps"]
|
|
||||||
json-tests = ["ethcore/json-tests"]
|
json-tests = ["ethcore/json-tests"]
|
||||||
|
ci-skip-issue = ["ethcore/ci-skip-issue"]
|
||||||
test-heavy = ["ethcore/test-heavy"]
|
test-heavy = ["ethcore/test-heavy"]
|
||||||
evm-debug = ["ethcore/evm-debug"]
|
evm-debug = ["ethcore/evm-debug"]
|
||||||
evm-debug-tests = ["ethcore/evm-debug-tests"]
|
evm-debug-tests = ["ethcore/evm-debug-tests"]
|
||||||
slow-blocks = ["ethcore/slow-blocks"]
|
slow-blocks = ["ethcore/slow-blocks"]
|
||||||
secretstore = ["ethcore-secretstore"]
|
secretstore = ["ethcore-secretstore"]
|
||||||
final = ["parity-version/final"]
|
final = ["parity-version/final"]
|
||||||
|
deadlock_detection = ["parking_lot/deadlock_detection"]
|
||||||
|
# to create a memory profile (requires nightly rust), use e.g.
|
||||||
|
# `heaptrack /path/to/parity <parity params>`,
|
||||||
|
# to visualize a memory profile, use `heaptrack_gui`
|
||||||
|
# or
|
||||||
|
# `valgrind --tool=massif /path/to/parity <parity params>`
|
||||||
|
# and `massif-visualizer` for visualization
|
||||||
|
memory_profiling = []
|
||||||
|
# hardcode version number 1.3.7 of parity to force an update
|
||||||
|
# in order to manually test that parity fall-over to the local version
|
||||||
|
# in case of invalid or deprecated command line arguments are entered
|
||||||
|
test-updater = ["parity-updater/test-updater"]
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
path = "parity/lib.rs"
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
path = "parity/main.rs"
|
path = "parity/main.rs"
|
||||||
name = "parity"
|
name = "parity"
|
||||||
|
|
||||||
[profile.dev]
|
[profile.dev]
|
||||||
panic = "abort"
|
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
debug = false
|
debug = false
|
||||||
lto = false
|
|
||||||
panic = "abort"
|
|
||||||
|
|
||||||
[workspace]
|
[workspace]
|
||||||
|
# This should only list projects that are not
|
||||||
|
# in the dependency tree in any other way
|
||||||
|
# (i.e. pretty much only standalone CLI tools)
|
||||||
members = [
|
members = [
|
||||||
|
"accounts/ethkey/cli",
|
||||||
|
"accounts/ethstore/cli",
|
||||||
"chainspec",
|
"chainspec",
|
||||||
"dapps/js-glue",
|
|
||||||
"ethcore/wasm/run",
|
"ethcore/wasm/run",
|
||||||
"ethcore/types",
|
|
||||||
"ethkey/cli",
|
|
||||||
"ethstore/cli",
|
|
||||||
"evmbin",
|
"evmbin",
|
||||||
"miner",
|
"parity-clib",
|
||||||
"transaction-pool",
|
|
||||||
"whisper",
|
|
||||||
"whisper/cli",
|
"whisper/cli",
|
||||||
|
"util/triehash-ethereum",
|
||||||
|
"util/keccak-hasher",
|
||||||
|
"util/patricia-trie-ethereum",
|
||||||
|
"util/fastmap"
|
||||||
]
|
]
|
||||||
|
|
||||||
[patch.crates-io]
|
[patch.crates-io]
|
||||||
ring = { git = "https://github.com/paritytech/ring" }
|
heapsize = { git = "https://github.com/cheme/heapsize.git", branch = "ec-macfix" }
|
||||||
|
|||||||
198
README.md
198
README.md
@@ -1,122 +1,75 @@
|
|||||||
# Parity - fast, light, and robust Ethereum client
|

|
||||||
|
|
||||||
## [» Download the latest release «](https://github.com/paritytech/parity/releases/latest)
|
<h2 align="center">The Fastest and most Advanced Ethereum Client.</h2>
|
||||||
|
|
||||||
[](https://gitlab.parity.io/parity/parity/commits/master)
|
<p align="center"><strong><a href="https://github.com/paritytech/parity-ethereum/releases/latest">» Download the latest release «</a></strong></p>
|
||||||
[](https://codecov.io/gh/paritytech/parity)
|
|
||||||
[](https://build.snapcraft.io/user/paritytech/parity)
|
|
||||||
[](https://www.gnu.org/licenses/gpl-3.0.en.html)
|
|
||||||
|
|
||||||
|
<p align="center"><a href="https://gitlab.parity.io/parity/parity-ethereum/commits/master" target="_blank"><img src="https://gitlab.parity.io/parity/parity-ethereum/badges/master/build.svg" /></a>
|
||||||
|
<a href="https://www.gnu.org/licenses/gpl-3.0.en.html" target="_blank"><img src="https://img.shields.io/badge/license-GPL%20v3-green.svg" /></a></p>
|
||||||
|
|
||||||
### Join the chat!
|
**Built for mission-critical use**: Miners, service providers, and exchanges need fast synchronisation and maximum uptime. Parity Ethereum provides the core infrastructure essential for speedy and reliable services.
|
||||||
|
|
||||||
Get in touch with us on Gitter:
|
- Clean, modular codebase for easy customisation
|
||||||
[](https://gitter.im/paritytech/parity)
|
- Advanced CLI-based client
|
||||||
[](https://gitter.im/paritytech/parity.js)
|
- Minimal memory and storage footprint
|
||||||
[](https://gitter.im/paritytech/parity/miners)
|
- Synchronise in hours, not days with Warp Sync
|
||||||
[](https://gitter.im/paritytech/parity-poa)
|
- Modular for light integration into your service or product
|
||||||
|
|
||||||
Or join our community on Matrix:
|
## Technical Overview
|
||||||
[](https://riot.im/app/#/group/+parity:matrix.parity.io)
|
|
||||||
|
|
||||||
Official website: https://parity.io
|
Parity Ethereum's goal is to be the fastest, lightest, and most secure Ethereum client. We are developing Parity Ethereum using the sophisticated and cutting-edge **Rust programming language**. Parity Ethereum is licensed under the GPLv3 and can be used for all your Ethereum needs.
|
||||||
|
|
||||||
Be sure to check out [our wiki](https://wiki.parity.io) for more information.
|
By default, Parity Ethereum runs a JSON-RPC HTTP server on port `:8545` and a Web-Sockets server on port `:8546`. This is fully configurable and supports a number of APIs.
|
||||||
|
|
||||||
----
|
If you run into problems while using Parity Ethereum, check out the [wiki for documentation](https://wiki.parity.io/), feel free to [file an issue in this repository](https://github.com/paritytech/parity-ethereum/issues/new), or hop on our [Gitter](https://gitter.im/paritytech/parity) or [Riot](https://riot.im/app/#/group/+parity:matrix.parity.io) chat room to ask a question. We are glad to help! **For security-critical issues**, please refer to the security policy outlined in [SECURITY.md](SECURITY.md).
|
||||||
|
|
||||||
## About Parity
|
Parity Ethereum's current beta-release is 2.1. You can download it at [the releases page](https://github.com/paritytech/parity-ethereum/releases) or follow the instructions below to build from source. Please, mind the [CHANGELOG.md](CHANGELOG.md) for a list of all changes between different versions.
|
||||||
|
|
||||||
Parity's goal is to be the fastest, lightest, and most secure Ethereum client. We are developing Parity using the sophisticated and cutting-edge Rust programming language. Parity is licensed under the GPLv3, and can be used for all your Ethereum needs.
|
## Build Dependencies
|
||||||
|
|
||||||
Parity comes with a built-in wallet, to install it please follow [these instructions](https://wiki.parity.io/Parity-Wallet). It includes various functionality allowing you to:
|
Parity Ethereum requires **latest stable Rust version** to build.
|
||||||
|
|
||||||
- create and manage your Ethereum accounts;
|
We recommend installing Rust through [rustup](https://www.rustup.rs/). If you don't already have `rustup`, you can install it like this:
|
||||||
- manage your Ether and any Ethereum tokens;
|
|
||||||
- create and register your own tokens;
|
|
||||||
- and much more.
|
|
||||||
|
|
||||||
From Parity Ethereum client version >=1.10, the User Interface (UI) is accessible in a separate application called Parity UI. To keep using the UI in the browser (deprecated), [follow these steps](https://wiki.parity.io/FAQ-Basic-Operations,-Configuration,-and-Synchronization.md#the-parity-ui-application-isnt-working-the-way-i-want).
|
|
||||||
|
|
||||||
By default, Parity will also run a JSONRPC server on `127.0.0.1:8545` and a websockets server on `127.0.0.1:8546`. This is fully configurable and supports a number of APIs.
|
|
||||||
|
|
||||||
If you run into an issue while using Parity, feel free to file one in this repository or hop on our [Gitter](https://gitter.im/paritytech/parity) or [Riot](https://riot.im/app/#/group/+parity:matrix.parity.io) chat room to ask a question. We are glad to help!
|
|
||||||
|
|
||||||
**For security-critical issues**, please refer to the security policy outlined in [SECURITY.MD](SECURITY.md).
|
|
||||||
|
|
||||||
Parity's current release is 1.9. You can download it at https://github.com/paritytech/parity/releases or follow the instructions below to build from source.
|
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
## Build dependencies
|
|
||||||
|
|
||||||
**Parity requires Rust version 1.23.0 to build**
|
|
||||||
|
|
||||||
We recommend installing Rust through [rustup](https://www.rustup.rs/). If you don't already have rustup, you can install it like this:
|
|
||||||
|
|
||||||
- Linux:
|
- Linux:
|
||||||
```bash
|
|
||||||
$ curl https://sh.rustup.rs -sSf | sh
|
|
||||||
```
|
|
||||||
|
|
||||||
Parity also requires `gcc`, `g++`, `libssl-dev`/`openssl`, `libudev-dev` and `pkg-config` packages to be installed.
|
|
||||||
|
|
||||||
- OSX:
|
|
||||||
```bash
|
|
||||||
$ curl https://sh.rustup.rs -sSf | sh
|
|
||||||
```
|
|
||||||
|
|
||||||
`clang` is required. It comes with Xcode command line tools or can be installed with homebrew.
|
|
||||||
|
|
||||||
- Windows
|
|
||||||
Make sure you have Visual Studio 2015 with C++ support installed. Next, download and run the rustup installer from
|
|
||||||
https://static.rust-lang.org/rustup/dist/x86_64-pc-windows-msvc/rustup-init.exe, start "VS2015 x64 Native Tools Command Prompt", and use the following command to install and set up the msvc toolchain:
|
|
||||||
```bash
|
```bash
|
||||||
$ rustup default stable-x86_64-pc-windows-msvc
|
$ curl https://sh.rustup.rs -sSf | sh
|
||||||
```
|
```
|
||||||
|
|
||||||
Once you have rustup installed, then you need to install:
|
Parity Ethereum also requires `gcc`, `g++`, `libudev-dev`, `pkg-config`, `file`, `make`, and `cmake` packages to be installed.
|
||||||
|
|
||||||
|
- OSX:
|
||||||
|
```bash
|
||||||
|
$ curl https://sh.rustup.rs -sSf | sh
|
||||||
|
```
|
||||||
|
|
||||||
|
`clang` is required. It comes with Xcode command line tools or can be installed with homebrew.
|
||||||
|
|
||||||
|
- Windows
|
||||||
|
Make sure you have Visual Studio 2015 with C++ support installed. Next, download and run the `rustup` installer from
|
||||||
|
https://static.rust-lang.org/rustup/dist/x86_64-pc-windows-msvc/rustup-init.exe, start "VS2015 x64 Native Tools Command Prompt", and use the following command to install and set up the `msvc` toolchain:
|
||||||
|
```bash
|
||||||
|
$ rustup default stable-x86_64-pc-windows-msvc
|
||||||
|
```
|
||||||
|
|
||||||
|
Once you have `rustup` installed, then you need to install:
|
||||||
* [Perl](https://www.perl.org)
|
* [Perl](https://www.perl.org)
|
||||||
* [Yasm](http://yasm.tortall.net)
|
* [Yasm](https://yasm.tortall.net)
|
||||||
|
|
||||||
Make sure that these binaries are in your `PATH`. After that you should be able to build parity from source.
|
Make sure that these binaries are in your `PATH`. After that, you should be able to build Parity Ethereum from source.
|
||||||
|
|
||||||
----
|
## Build from Source Code
|
||||||
|
|
||||||
## Install from the snap store
|
|
||||||
|
|
||||||
In any of the [supported Linux distros](https://snapcraft.io/docs/core/install):
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
sudo snap install parity
|
# download Parity Ethereum code
|
||||||
```
|
$ git clone https://github.com/paritytech/parity-ethereum
|
||||||
|
$ cd parity-ethereum
|
||||||
Or, if you want to contribute testing the upcoming release:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
sudo snap install parity --beta
|
|
||||||
```
|
|
||||||
|
|
||||||
And to test the latest code landed into the master branch:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
sudo snap install parity --edge
|
|
||||||
```
|
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
## Build from source
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# download Parity code
|
|
||||||
$ git clone https://github.com/paritytech/parity
|
|
||||||
$ cd parity
|
|
||||||
|
|
||||||
# build in release mode
|
# build in release mode
|
||||||
$ cargo build --release
|
$ cargo build --release --features final
|
||||||
```
|
```
|
||||||
|
|
||||||
This will produce an executable in the `./target/release` subdirectory.
|
This produces an executable in the `./target/release` subdirectory.
|
||||||
|
|
||||||
Note: if cargo fails to parse manifest try:
|
Note: if cargo fails to parse manifest try:
|
||||||
|
|
||||||
@@ -124,19 +77,13 @@ Note: if cargo fails to parse manifest try:
|
|||||||
$ ~/.cargo/bin/cargo build --release
|
$ ~/.cargo/bin/cargo build --release
|
||||||
```
|
```
|
||||||
|
|
||||||
Note: When compiling a crate and you receive the following error:
|
Note, when compiling a crate and you receive errors, it's in most cases your outdated version of Rust, or some of your crates have to be recompiled. Cleaning the repository will most likely solve the issue if you are on the latest stable version of Rust, try:
|
||||||
|
|
||||||
```
|
|
||||||
error: the crate is compiled with the panic strategy `abort` which is incompatible with this crate's strategy of `unwind`
|
|
||||||
```
|
|
||||||
|
|
||||||
Cleaning the repository will most likely solve the issue, try:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
$ cargo clean
|
$ cargo clean
|
||||||
```
|
```
|
||||||
|
|
||||||
This will always compile the latest nightly builds. If you want to build stable or beta, do a
|
This always compiles the latest nightly builds. If you want to build stable or beta, do a
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
$ git checkout stable
|
$ git checkout stable
|
||||||
@@ -148,38 +95,61 @@ or
|
|||||||
$ git checkout beta
|
$ git checkout beta
|
||||||
```
|
```
|
||||||
|
|
||||||
first.
|
## Simple One-Line Installer for Mac and Linux
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
## Simple one-line installer for Mac and Ubuntu
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
bash <(curl https://get.parity.io -Lk)
|
bash <(curl https://get.parity.io -L)
|
||||||
```
|
```
|
||||||
|
|
||||||
The one-line installer always defaults to the latest beta release. To install a stable release, run:
|
The one-line installer always defaults to the latest beta release. To install a stable release, run:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
bash <(curl https://get.parity.io -Lk) -r stable
|
bash <(curl https://get.parity.io -L) -r stable
|
||||||
```
|
```
|
||||||
|
|
||||||
## Start Parity
|
## Start Parity Ethereum
|
||||||
|
|
||||||
### Manually
|
### Manually
|
||||||
|
|
||||||
To start Parity manually, just run
|
To start Parity Ethereum manually, just run
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
$ ./target/release/parity
|
$ ./target/release/parity
|
||||||
```
|
```
|
||||||
|
|
||||||
and Parity will begin syncing the Ethereum blockchain.
|
so Parity Ethereum begins syncing the Ethereum blockchain.
|
||||||
|
|
||||||
### Using systemd service file
|
### Using `systemd` service file
|
||||||
|
|
||||||
To start Parity as a regular user using systemd init:
|
To start Parity Ethereum as a regular user using `systemd` init:
|
||||||
|
|
||||||
1. Copy `./scripts/parity.service` to your
|
1. Copy `./scripts/parity.service` to your
|
||||||
systemd user directory (usually `~/.config/systemd/user`).
|
`systemd` user directory (usually `~/.config/systemd/user`).
|
||||||
2. To configure Parity, write a `/etc/parity/config.toml` config file, see [Configuring Parity](https://paritytech.github.io/wiki/Configuring-Parity) for details.
|
2. To configure Parity Ethereum, write a `/etc/parity/config.toml` config file, see [Configuring Parity Ethereum](https://paritytech.github.io/wiki/Configuring-Parity) for details.
|
||||||
|
|
||||||
|
## Parity Ethereum toolchain
|
||||||
|
|
||||||
|
In addition to the Parity Ethereum client, there are additional tools in this repository available:
|
||||||
|
|
||||||
|
- [evmbin](https://github.com/paritytech/parity-ethereum/blob/master/evmbin/) - EVM implementation for Parity Ethereum.
|
||||||
|
- [ethabi](https://github.com/paritytech/ethabi) - Parity Ethereum function calls encoding.
|
||||||
|
- [ethstore](https://github.com/paritytech/parity-ethereum/blob/master/accounts/ethstore) - Parity Ethereum key management.
|
||||||
|
- [ethkey](https://github.com/paritytech/parity-ethereum/blob/master/accounts/ethkey) - Parity Ethereum keys generator.
|
||||||
|
- [whisper](https://github.com/paritytech/parity-ethereum/blob/master/whisper/) - Implementation of Whisper-v2 PoC.
|
||||||
|
|
||||||
|
## Join the chat!
|
||||||
|
|
||||||
|
Questions? Get in touch with us on Gitter:
|
||||||
|
[](https://gitter.im/paritytech/parity)
|
||||||
|
[](https://gitter.im/paritytech/parity.js)
|
||||||
|
[](https://gitter.im/paritytech/parity/miners)
|
||||||
|
[](https://gitter.im/paritytech/parity-poa)
|
||||||
|
|
||||||
|
Alternatively, join our community on Matrix:
|
||||||
|
[](https://riot.im/app/#/group/+parity:matrix.parity.io)
|
||||||
|
|
||||||
|
## Documentation
|
||||||
|
|
||||||
|
Official website: https://parity.io
|
||||||
|
|
||||||
|
Be sure to [check out our wiki](https://wiki.parity.io) for more information.
|
||||||
|
|||||||
@@ -6,13 +6,16 @@ authors = ["Parity Technologies <admin@parity.io>"]
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
byteorder = "1.0"
|
byteorder = "1.0"
|
||||||
edit-distance = "2.0"
|
edit-distance = "2.0"
|
||||||
|
parity-crypto = "0.2"
|
||||||
eth-secp256k1 = { git = "https://github.com/paritytech/rust-secp256k1" }
|
eth-secp256k1 = { git = "https://github.com/paritytech/rust-secp256k1" }
|
||||||
ethereum-types = "0.3"
|
ethereum-types = "0.4"
|
||||||
lazy_static = "1.0"
|
lazy_static = "1.0"
|
||||||
log = "0.3"
|
log = "0.4"
|
||||||
mem = { path = "../util/mem" }
|
memzero = { path = "../../util/memzero" }
|
||||||
parity-wordlist = "1.2"
|
parity-wordlist = "1.2"
|
||||||
|
quick-error = "1.2.2"
|
||||||
rand = "0.4"
|
rand = "0.4"
|
||||||
rust-crypto = "0.2"
|
|
||||||
rustc-hex = "1.0"
|
rustc-hex = "1.0"
|
||||||
tiny-keccak = "1.3"
|
serde = "1.0"
|
||||||
|
serde_derive = "1.0"
|
||||||
|
tiny-keccak = "1.4"
|
||||||
@@ -1,19 +1,12 @@
|
|||||||
# ethkey
|
## ethkey-cli
|
||||||
|
|
||||||
[![Build Status][travis-image]][travis-url]
|
Parity Ethereum keys generator.
|
||||||
|
|
||||||
[travis-image]: https://travis-ci.org/paritytech/ethkey.svg?branch=master
|
|
||||||
[travis-url]: https://travis-ci.org/paritytech/ethkey
|
|
||||||
|
|
||||||
Ethereum keys generator.
|
|
||||||
|
|
||||||
[Documentation](http://paritytech.github.io/ethkey/ethkey/index.html)
|
|
||||||
|
|
||||||
### Usage
|
### Usage
|
||||||
|
|
||||||
```
|
```
|
||||||
Ethereum keys generator.
|
Parity Ethereum keys generator.
|
||||||
Copyright 2016, 2017 Parity Technologies (UK) Ltd
|
Copyright 2015-2018 Parity Technologies (UK) Ltd.
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
ethkey info <secret-or-phrase> [options]
|
ethkey info <secret-or-phrase> [options]
|
||||||
@@ -27,17 +20,17 @@ Usage:
|
|||||||
|
|
||||||
Options:
|
Options:
|
||||||
-h, --help Display this message and exit.
|
-h, --help Display this message and exit.
|
||||||
-s, --secret Display only the secret.
|
-s, --secret Display only the secret key.
|
||||||
-p, --public Display only the public.
|
-p, --public Display only the public key.
|
||||||
-a, --address Display only the address.
|
-a, --address Display only the address.
|
||||||
-b, --brain Use parity brain wallet algorithm.
|
-b, --brain Use parity brain wallet algorithm. Not recommended.
|
||||||
|
|
||||||
Commands:
|
Commands:
|
||||||
info Display public and address of the secret.
|
info Display public key and address of the secret.
|
||||||
generate random Generates new random ethereum key.
|
generate random Generates new random Ethereum key.
|
||||||
generate prefix Random generation, but address must start with a prefix.
|
generate prefix Random generation, but address must start with a prefix ("vanity address").
|
||||||
sign Sign message using secret.
|
sign Sign message using a secret key.
|
||||||
verify Verify signer of the signature.
|
verify Verify signer of the signature by public key or address.
|
||||||
recover Try to find brain phrase matching given address from partial phrase.
|
recover Try to find brain phrase matching given address from partial phrase.
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -218,10 +211,11 @@ public: 4e19a5fdae82596e1485c69b687c9cc52b5078e5b0668ef3ce8543cd90e712cb00df822
|
|||||||
address: 00cf3711cbd3a1512570639280758118ba0b2bcb
|
address: 00cf3711cbd3a1512570639280758118ba0b2bcb
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Parity Ethereum toolchain
|
||||||
|
_This project is a part of the Parity Ethereum toolchain._
|
||||||
|
|
||||||
# Parity toolchain
|
- [evmbin](https://github.com/paritytech/parity-ethereum/blob/master/evmbin/) - EVM implementation for Parity Ethereum.
|
||||||
*this project is a part of the parity toolchain*
|
- [ethabi](https://github.com/paritytech/ethabi) - Parity Ethereum function calls encoding.
|
||||||
|
- [ethstore](https://github.com/paritytech/parity-ethereum/blob/master/accounts/ethstore) - Parity Ethereum key management.
|
||||||
- [**ethkey**](https://github.com/paritytech/ethkey) - Ethereum keys generator and signer.
|
- [ethkey](https://github.com/paritytech/parity-ethereum/blob/master/accounts/ethkey) - Parity Ethereum keys generator.
|
||||||
- [**ethstore**](https://github.com/paritytech/ethstore) - Ethereum key management.
|
- [whisper](https://github.com/paritytech/parity-ethereum/blob/master/whisper/) - Implementation of Whisper-v2 PoC.
|
||||||
- [**ethabi**](https://github.com/paritytech/ethabi) - Ethereum function calls encoding.
|
|
||||||
@@ -4,10 +4,10 @@ version = "0.1.0"
|
|||||||
authors = ["Parity Technologies <admin@parity.io>"]
|
authors = ["Parity Technologies <admin@parity.io>"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
docopt = "0.8"
|
docopt = "1.0"
|
||||||
env_logger = "0.4"
|
env_logger = "0.5"
|
||||||
ethkey = { path = "../" }
|
ethkey = { path = "../" }
|
||||||
panic_hook = { path = "../../util/panic_hook" }
|
panic_hook = { path = "../../../util/panic-hook" }
|
||||||
parity-wordlist="1.2"
|
parity-wordlist="1.2"
|
||||||
rustc-hex = "1.0"
|
rustc-hex = "1.0"
|
||||||
serde = "1.0"
|
serde = "1.0"
|
||||||
@@ -1,18 +1,18 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
// Copyright 2015-2019 Parity Technologies (UK) Ltd.
|
||||||
// This file is part of Parity.
|
// This file is part of Parity Ethereum.
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
// Parity Ethereum is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
// Parity Ethereum is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
extern crate docopt;
|
extern crate docopt;
|
||||||
extern crate env_logger;
|
extern crate env_logger;
|
||||||
@@ -34,8 +34,8 @@ use ethkey::{KeyPair, Random, Brain, BrainPrefix, Prefix, Error as EthkeyError,
|
|||||||
use rustc_hex::{FromHex, FromHexError};
|
use rustc_hex::{FromHex, FromHexError};
|
||||||
|
|
||||||
const USAGE: &'static str = r#"
|
const USAGE: &'static str = r#"
|
||||||
Ethereum keys generator.
|
Parity Ethereum keys generator.
|
||||||
Copyright 2016, 2017 Parity Technologies (UK) Ltd
|
Copyright 2015-2018 Parity Technologies (UK) Ltd.
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
ethkey info <secret-or-phrase> [options]
|
ethkey info <secret-or-phrase> [options]
|
||||||
@@ -49,17 +49,17 @@ Usage:
|
|||||||
|
|
||||||
Options:
|
Options:
|
||||||
-h, --help Display this message and exit.
|
-h, --help Display this message and exit.
|
||||||
-s, --secret Display only the secret.
|
-s, --secret Display only the secret key.
|
||||||
-p, --public Display only the public.
|
-p, --public Display only the public key.
|
||||||
-a, --address Display only the address.
|
-a, --address Display only the address.
|
||||||
-b, --brain Use parity brain wallet algorithm.
|
-b, --brain Use parity brain wallet algorithm. Not recommended.
|
||||||
|
|
||||||
Commands:
|
Commands:
|
||||||
info Display public and address of the secret.
|
info Display public key and address of the secret.
|
||||||
generate random Generates new random ethereum key.
|
generate random Generates new random Ethereum key.
|
||||||
generate prefix Random generation, but address must start with a prefix.
|
generate prefix Random generation, but address must start with a prefix ("vanity address").
|
||||||
sign Sign message using secret.
|
sign Sign message using a secret key.
|
||||||
verify Verify signer of the signature.
|
verify Verify signer of the signature by public key or address.
|
||||||
recover Try to find brain phrase matching given address from partial phrase.
|
recover Try to find brain phrase matching given address from partial phrase.
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
@@ -161,15 +161,16 @@ impl DisplayMode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
panic_hook::set();
|
panic_hook::set_abort();
|
||||||
env_logger::init().expect("Logger initialized only once.");
|
env_logger::try_init().expect("Logger initialized only once.");
|
||||||
|
|
||||||
match execute(env::args()) {
|
match execute(env::args()) {
|
||||||
Ok(ok) => println!("{}", ok),
|
Ok(ok) => println!("{}", ok),
|
||||||
|
Err(Error::Docopt(ref e)) => e.exit(),
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
println!("{}", err);
|
eprintln!("{}", err);
|
||||||
process::exit(1);
|
process::exit(1);
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1,18 +1,18 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
// Copyright 2015-2019 Parity Technologies (UK) Ltd.
|
||||||
// This file is part of Parity.
|
// This file is part of Parity Ethereum.
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
// Parity Ethereum is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
// Parity Ethereum is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use keccak::Keccak256;
|
use keccak::Keccak256;
|
||||||
use super::{KeyPair, Generator, Secret};
|
use super::{KeyPair, Generator, Secret};
|
||||||
@@ -1,18 +1,18 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
// Copyright 2015-2019 Parity Technologies (UK) Ltd.
|
||||||
// This file is part of Parity.
|
// This file is part of Parity Ethereum.
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
// Parity Ethereum is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
// Parity Ethereum is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use super::{Generator, KeyPair, Error, Brain};
|
use super::{Generator, KeyPair, Error, Brain};
|
||||||
use parity_wordlist as wordlist;
|
use parity_wordlist as wordlist;
|
||||||
@@ -1,18 +1,18 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
// Copyright 2015-2019 Parity Technologies (UK) Ltd.
|
||||||
// This file is part of Parity.
|
// This file is part of Parity Ethereum.
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
// Parity Ethereum is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
// Parity Ethereum is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
|
||||||
@@ -21,7 +21,6 @@ use parity_wordlist;
|
|||||||
|
|
||||||
use super::{Address, Brain, Generator};
|
use super::{Address, Brain, Generator};
|
||||||
|
|
||||||
|
|
||||||
/// Tries to find a phrase for address, given the number
|
/// Tries to find a phrase for address, given the number
|
||||||
/// of expected words and a partial phrase.
|
/// of expected words and a partial phrase.
|
||||||
///
|
///
|
||||||
@@ -150,7 +149,6 @@ impl Iterator for PhrasesIterator {
|
|||||||
mod tests {
|
mod tests {
|
||||||
use super::PhrasesIterator;
|
use super::PhrasesIterator;
|
||||||
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn should_generate_possible_combinations() {
|
fn should_generate_possible_combinations() {
|
||||||
let mut it = PhrasesIterator::new(vec![
|
let mut it = PhrasesIterator::new(vec![
|
||||||
189
accounts/ethkey/src/crypto.rs
Normal file
189
accounts/ethkey/src/crypto.rs
Normal file
@@ -0,0 +1,189 @@
|
|||||||
|
// Copyright 2015-2019 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity Ethereum.
|
||||||
|
|
||||||
|
// Parity Ethereum is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity Ethereum is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
use secp256k1;
|
||||||
|
use std::io;
|
||||||
|
use parity_crypto::error::SymmError;
|
||||||
|
|
||||||
|
quick_error! {
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Error {
|
||||||
|
Secp(e: secp256k1::Error) {
|
||||||
|
display("secp256k1 error: {}", e)
|
||||||
|
cause(e)
|
||||||
|
from()
|
||||||
|
}
|
||||||
|
Io(e: io::Error) {
|
||||||
|
display("i/o error: {}", e)
|
||||||
|
cause(e)
|
||||||
|
from()
|
||||||
|
}
|
||||||
|
InvalidMessage {
|
||||||
|
display("invalid message")
|
||||||
|
}
|
||||||
|
Symm(e: SymmError) {
|
||||||
|
cause(e)
|
||||||
|
from()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ECDH functions
|
||||||
|
pub mod ecdh {
|
||||||
|
use secp256k1::{self, ecdh, key};
|
||||||
|
use super::Error;
|
||||||
|
use {Secret, Public, SECP256K1};
|
||||||
|
|
||||||
|
/// Agree on a shared secret
|
||||||
|
pub fn agree(secret: &Secret, public: &Public) -> Result<Secret, Error> {
|
||||||
|
let context = &SECP256K1;
|
||||||
|
let pdata = {
|
||||||
|
let mut temp = [4u8; 65];
|
||||||
|
(&mut temp[1..65]).copy_from_slice(&public[0..64]);
|
||||||
|
temp
|
||||||
|
};
|
||||||
|
|
||||||
|
let publ = key::PublicKey::from_slice(context, &pdata)?;
|
||||||
|
let sec = key::SecretKey::from_slice(context, &secret)?;
|
||||||
|
let shared = ecdh::SharedSecret::new_raw(context, &publ, &sec);
|
||||||
|
|
||||||
|
Secret::from_unsafe_slice(&shared[0..32])
|
||||||
|
.map_err(|_| Error::Secp(secp256k1::Error::InvalidSecretKey))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ECIES function
|
||||||
|
pub mod ecies {
|
||||||
|
use parity_crypto::{aes, digest, hmac, is_equal};
|
||||||
|
use ethereum_types::H128;
|
||||||
|
use super::{ecdh, Error};
|
||||||
|
use {Random, Generator, Public, Secret};
|
||||||
|
|
||||||
|
/// Encrypt a message with a public key, writing an HMAC covering both
|
||||||
|
/// the plaintext and authenticated data.
|
||||||
|
///
|
||||||
|
/// Authenticated data may be empty.
|
||||||
|
pub fn encrypt(public: &Public, auth_data: &[u8], plain: &[u8]) -> Result<Vec<u8>, Error> {
|
||||||
|
let r = Random.generate()?;
|
||||||
|
let z = ecdh::agree(r.secret(), public)?;
|
||||||
|
let mut key = [0u8; 32];
|
||||||
|
kdf(&z, &[0u8; 0], &mut key);
|
||||||
|
|
||||||
|
let ekey = &key[0..16];
|
||||||
|
let mkey = hmac::SigKey::sha256(&digest::sha256(&key[16..32]));
|
||||||
|
|
||||||
|
let mut msg = vec![0u8; 1 + 64 + 16 + plain.len() + 32];
|
||||||
|
msg[0] = 0x04u8;
|
||||||
|
{
|
||||||
|
let msgd = &mut msg[1..];
|
||||||
|
msgd[0..64].copy_from_slice(r.public());
|
||||||
|
let iv = H128::random();
|
||||||
|
msgd[64..80].copy_from_slice(&iv);
|
||||||
|
{
|
||||||
|
let cipher = &mut msgd[(64 + 16)..(64 + 16 + plain.len())];
|
||||||
|
aes::encrypt_128_ctr(ekey, &iv, plain, cipher)?;
|
||||||
|
}
|
||||||
|
let mut hmac = hmac::Signer::with(&mkey);
|
||||||
|
{
|
||||||
|
let cipher_iv = &msgd[64..(64 + 16 + plain.len())];
|
||||||
|
hmac.update(cipher_iv);
|
||||||
|
}
|
||||||
|
hmac.update(auth_data);
|
||||||
|
let sig = hmac.sign();
|
||||||
|
msgd[(64 + 16 + plain.len())..].copy_from_slice(&sig);
|
||||||
|
}
|
||||||
|
Ok(msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Decrypt a message with a secret key, checking HMAC for ciphertext
|
||||||
|
/// and authenticated data validity.
|
||||||
|
pub fn decrypt(secret: &Secret, auth_data: &[u8], encrypted: &[u8]) -> Result<Vec<u8>, Error> {
|
||||||
|
let meta_len = 1 + 64 + 16 + 32;
|
||||||
|
if encrypted.len() < meta_len || encrypted[0] < 2 || encrypted[0] > 4 {
|
||||||
|
return Err(Error::InvalidMessage); //invalid message: publickey
|
||||||
|
}
|
||||||
|
|
||||||
|
let e = &encrypted[1..];
|
||||||
|
let p = Public::from_slice(&e[0..64]);
|
||||||
|
let z = ecdh::agree(secret, &p)?;
|
||||||
|
let mut key = [0u8; 32];
|
||||||
|
kdf(&z, &[0u8; 0], &mut key);
|
||||||
|
|
||||||
|
let ekey = &key[0..16];
|
||||||
|
let mkey = hmac::SigKey::sha256(&digest::sha256(&key[16..32]));
|
||||||
|
|
||||||
|
let clen = encrypted.len() - meta_len;
|
||||||
|
let cipher_with_iv = &e[64..(64+16+clen)];
|
||||||
|
let cipher_iv = &cipher_with_iv[0..16];
|
||||||
|
let cipher_no_iv = &cipher_with_iv[16..];
|
||||||
|
let msg_mac = &e[(64+16+clen)..];
|
||||||
|
|
||||||
|
// Verify tag
|
||||||
|
let mut hmac = hmac::Signer::with(&mkey);
|
||||||
|
hmac.update(cipher_with_iv);
|
||||||
|
hmac.update(auth_data);
|
||||||
|
let mac = hmac.sign();
|
||||||
|
|
||||||
|
if !is_equal(&mac.as_ref()[..], msg_mac) {
|
||||||
|
return Err(Error::InvalidMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut msg = vec![0u8; clen];
|
||||||
|
aes::decrypt_128_ctr(ekey, cipher_iv, cipher_no_iv, &mut msg[..])?;
|
||||||
|
Ok(msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn kdf(secret: &Secret, s1: &[u8], dest: &mut [u8]) {
|
||||||
|
// SEC/ISO/Shoup specify counter size SHOULD be equivalent
|
||||||
|
// to size of hash output, however, it also notes that
|
||||||
|
// the 4 bytes is okay. NIST specifies 4 bytes.
|
||||||
|
let mut ctr = 1u32;
|
||||||
|
let mut written = 0usize;
|
||||||
|
while written < dest.len() {
|
||||||
|
let mut hasher = digest::Hasher::sha256();
|
||||||
|
let ctrs = [(ctr >> 24) as u8, (ctr >> 16) as u8, (ctr >> 8) as u8, ctr as u8];
|
||||||
|
hasher.update(&ctrs);
|
||||||
|
hasher.update(secret);
|
||||||
|
hasher.update(s1);
|
||||||
|
let d = hasher.finish();
|
||||||
|
&mut dest[written..(written + 32)].copy_from_slice(&d);
|
||||||
|
written += 32;
|
||||||
|
ctr += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::ecies;
|
||||||
|
use {Random, Generator};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn ecies_shared() {
|
||||||
|
let kp = Random.generate().unwrap();
|
||||||
|
let message = b"So many books, so little time";
|
||||||
|
|
||||||
|
let shared = b"shared";
|
||||||
|
let wrong_shared = b"incorrect";
|
||||||
|
let encrypted = ecies::encrypt(kp.public(), shared, message).unwrap();
|
||||||
|
assert!(encrypted[..] != message[..]);
|
||||||
|
assert_eq!(encrypted[0], 0x04);
|
||||||
|
|
||||||
|
assert!(ecies::decrypt(kp.secret(), wrong_shared, &encrypted).is_err());
|
||||||
|
let decrypted = ecies::decrypt(kp.secret(), shared, &encrypted).unwrap();
|
||||||
|
assert_eq!(decrypted[..message.len()], message[..]);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,18 +1,18 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
// Copyright 2015-2019 Parity Technologies (UK) Ltd.
|
||||||
// This file is part of Parity.
|
// This file is part of Parity Ethereum.
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
// Parity Ethereum is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
// Parity Ethereum is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use std::{fmt, error};
|
use std::{fmt, error};
|
||||||
|
|
||||||
@@ -1,18 +1,18 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
// Copyright 2015-2019 Parity Technologies (UK) Ltd.
|
||||||
// This file is part of Parity.
|
// This file is part of Parity Ethereum.
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
// Parity Ethereum is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
// Parity Ethereum is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
//! Extended keys
|
//! Extended keys
|
||||||
|
|
||||||
@@ -207,9 +207,7 @@ impl ExtendedKeyPair {
|
|||||||
// Work is based on BIP0032
|
// Work is based on BIP0032
|
||||||
// https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki
|
// https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki
|
||||||
mod derivation {
|
mod derivation {
|
||||||
use rcrypto::hmac::Hmac;
|
use parity_crypto::hmac;
|
||||||
use rcrypto::mac::Mac;
|
|
||||||
use rcrypto::sha2::Sha512;
|
|
||||||
use ethereum_types::{U256, U512, H512, H256};
|
use ethereum_types::{U256, U512, H512, H256};
|
||||||
use secp256k1::key::{SecretKey, PublicKey};
|
use secp256k1::key::{SecretKey, PublicKey};
|
||||||
use SECP256K1;
|
use SECP256K1;
|
||||||
@@ -242,10 +240,8 @@ mod derivation {
|
|||||||
let private: U256 = private_key.into();
|
let private: U256 = private_key.into();
|
||||||
|
|
||||||
// produces 512-bit derived hmac (I)
|
// produces 512-bit derived hmac (I)
|
||||||
let mut hmac = Hmac::new(Sha512::new(), &*chain_code);
|
let skey = hmac::SigKey::sha512(&*chain_code);
|
||||||
let mut i_512 = [0u8; 64];
|
let i_512 = hmac::sign(&skey, &data[..]);
|
||||||
hmac.input(&data[..]);
|
|
||||||
hmac.raw_result(&mut i_512);
|
|
||||||
|
|
||||||
// left most 256 bits are later added to original private key
|
// left most 256 bits are later added to original private key
|
||||||
let hmac_key: U256 = H256::from_slice(&i_512[0..32]).into();
|
let hmac_key: U256 = H256::from_slice(&i_512[0..32]).into();
|
||||||
@@ -321,10 +317,8 @@ mod derivation {
|
|||||||
index.store(&mut data[33..(33 + T::len())]);
|
index.store(&mut data[33..(33 + T::len())]);
|
||||||
|
|
||||||
// HMAC512SHA produces [derived private(256); new chain code(256)]
|
// HMAC512SHA produces [derived private(256); new chain code(256)]
|
||||||
let mut hmac = Hmac::new(Sha512::new(), &*chain_code);
|
let skey = hmac::SigKey::sha512(&*chain_code);
|
||||||
let mut i_512 = [0u8; 64];
|
let i_512 = hmac::sign(&skey, &data[..]);
|
||||||
hmac.input(&data[..]);
|
|
||||||
hmac.raw_result(&mut i_512);
|
|
||||||
|
|
||||||
let new_private = H256::from(&i_512[0..32]);
|
let new_private = H256::from(&i_512[0..32]);
|
||||||
let new_chain_code = H256::from(&i_512[32..64]);
|
let new_chain_code = H256::from(&i_512[32..64]);
|
||||||
@@ -369,10 +363,8 @@ mod derivation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn seed_pair(seed: &[u8]) -> (H256, H256) {
|
pub fn seed_pair(seed: &[u8]) -> (H256, H256) {
|
||||||
let mut hmac = Hmac::new(Sha512::new(), b"Bitcoin seed");
|
let skey = hmac::SigKey::sha512(b"Bitcoin seed");
|
||||||
let mut i_512 = [0u8; 64];
|
let i_512 = hmac::sign(&skey, seed);
|
||||||
hmac.input(seed);
|
|
||||||
hmac.raw_result(&mut i_512);
|
|
||||||
|
|
||||||
let master_key = H256::from_slice(&i_512[0..32]);
|
let master_key = H256::from_slice(&i_512[0..32]);
|
||||||
let chain_code = H256::from_slice(&i_512[32..64]);
|
let chain_code = H256::from_slice(&i_512[32..64]);
|
||||||
@@ -1,18 +1,18 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
// Copyright 2015-2019 Parity Technologies (UK) Ltd.
|
||||||
// This file is part of Parity.
|
// This file is part of Parity Ethereum.
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
// Parity Ethereum is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
// Parity Ethereum is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use tiny_keccak::Keccak;
|
use tiny_keccak::Keccak;
|
||||||
|
|
||||||
@@ -1,18 +1,18 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
// Copyright 2015-2019 Parity Technologies (UK) Ltd.
|
||||||
// This file is part of Parity.
|
// This file is part of Parity Ethereum.
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
// Parity Ethereum is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
// Parity Ethereum is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use secp256k1::key;
|
use secp256k1::key;
|
||||||
@@ -1,42 +1,48 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
// Copyright 2015-2019 Parity Technologies (UK) Ltd.
|
||||||
// This file is part of Parity.
|
// This file is part of Parity Ethereum.
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
// Parity Ethereum is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
// Parity Ethereum is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
// #![warn(missing_docs)]
|
// #![warn(missing_docs)]
|
||||||
|
|
||||||
extern crate byteorder;
|
extern crate byteorder;
|
||||||
extern crate crypto as rcrypto;
|
|
||||||
extern crate edit_distance;
|
extern crate edit_distance;
|
||||||
|
extern crate parity_crypto;
|
||||||
extern crate ethereum_types;
|
extern crate ethereum_types;
|
||||||
extern crate mem;
|
extern crate memzero;
|
||||||
extern crate parity_wordlist;
|
extern crate parity_wordlist;
|
||||||
|
#[macro_use]
|
||||||
|
extern crate quick_error;
|
||||||
extern crate rand;
|
extern crate rand;
|
||||||
extern crate rustc_hex;
|
extern crate rustc_hex;
|
||||||
extern crate secp256k1;
|
extern crate secp256k1;
|
||||||
|
extern crate serde;
|
||||||
extern crate tiny_keccak;
|
extern crate tiny_keccak;
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate lazy_static;
|
extern crate lazy_static;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate log;
|
extern crate log;
|
||||||
|
#[macro_use]
|
||||||
|
extern crate serde_derive;
|
||||||
|
|
||||||
mod brain;
|
mod brain;
|
||||||
mod brain_prefix;
|
mod brain_prefix;
|
||||||
mod error;
|
mod error;
|
||||||
mod keypair;
|
mod keypair;
|
||||||
mod keccak;
|
mod keccak;
|
||||||
|
mod password;
|
||||||
mod prefix;
|
mod prefix;
|
||||||
mod random;
|
mod random;
|
||||||
mod signature;
|
mod signature;
|
||||||
@@ -44,6 +50,7 @@ mod secret;
|
|||||||
mod extended;
|
mod extended;
|
||||||
|
|
||||||
pub mod brain_recover;
|
pub mod brain_recover;
|
||||||
|
pub mod crypto;
|
||||||
pub mod math;
|
pub mod math;
|
||||||
|
|
||||||
pub use self::parity_wordlist::Error as WordlistError;
|
pub use self::parity_wordlist::Error as WordlistError;
|
||||||
@@ -52,6 +59,7 @@ pub use self::brain_prefix::BrainPrefix;
|
|||||||
pub use self::error::Error;
|
pub use self::error::Error;
|
||||||
pub use self::keypair::{KeyPair, public_to_address};
|
pub use self::keypair::{KeyPair, public_to_address};
|
||||||
pub use self::math::public_is_valid;
|
pub use self::math::public_is_valid;
|
||||||
|
pub use self::password::Password;
|
||||||
pub use self::prefix::Prefix;
|
pub use self::prefix::Prefix;
|
||||||
pub use self::random::Random;
|
pub use self::random::Random;
|
||||||
pub use self::signature::{sign, verify_public, verify_address, recover, Signature};
|
pub use self::signature::{sign, verify_public, verify_address, recover, Signature};
|
||||||
@@ -1,18 +1,18 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
// Copyright 2015-2019 Parity Technologies (UK) Ltd.
|
||||||
// This file is part of Parity.
|
// This file is part of Parity Ethereum.
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
// Parity Ethereum is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
// Parity Ethereum is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use super::{SECP256K1, Public, Secret, Error};
|
use super::{SECP256K1, Public, Secret, Error};
|
||||||
use secp256k1::key;
|
use secp256k1::key;
|
||||||
59
accounts/ethkey/src/password.rs
Normal file
59
accounts/ethkey/src/password.rs
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
// Copyright 2015-2019 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity Ethereum.
|
||||||
|
|
||||||
|
// Parity Ethereum is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity Ethereum is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
use std::{fmt, ptr};
|
||||||
|
|
||||||
|
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
|
pub struct Password(String);
|
||||||
|
|
||||||
|
impl fmt::Debug for Password {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(f, "Password(******)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Password {
|
||||||
|
pub fn as_bytes(&self) -> &[u8] {
|
||||||
|
self.0.as_bytes()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_str(&self) -> &str {
|
||||||
|
self.0.as_str()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Custom drop impl to zero out memory.
|
||||||
|
impl Drop for Password {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
unsafe {
|
||||||
|
for byte_ref in self.0.as_mut_vec() {
|
||||||
|
ptr::write_volatile(byte_ref, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<String> for Password {
|
||||||
|
fn from(s: String) -> Password {
|
||||||
|
Password(s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<&'a str> for Password {
|
||||||
|
fn from(s: &'a str) -> Password {
|
||||||
|
Password::from(String::from(s))
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,18 +1,18 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
// Copyright 2015-2019 Parity Technologies (UK) Ltd.
|
||||||
// This file is part of Parity.
|
// This file is part of Parity Ethereum.
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
// Parity Ethereum is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
// Parity Ethereum is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use super::{Random, Generator, KeyPair, Error};
|
use super::{Random, Generator, KeyPair, Error};
|
||||||
|
|
||||||
@@ -1,18 +1,18 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
// Copyright 2015-2019 Parity Technologies (UK) Ltd.
|
||||||
// This file is part of Parity.
|
// This file is part of Parity Ethereum.
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
// Parity Ethereum is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
// Parity Ethereum is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use rand::os::OsRng;
|
use rand::os::OsRng;
|
||||||
use super::{Generator, KeyPair, SECP256K1};
|
use super::{Generator, KeyPair, SECP256K1};
|
||||||
@@ -1,18 +1,18 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
// Copyright 2015-2019 Parity Technologies (UK) Ltd.
|
||||||
// This file is part of Parity.
|
// This file is part of Parity Ethereum.
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
// Parity Ethereum is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
// Parity Ethereum is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
@@ -21,7 +21,7 @@ use rustc_hex::ToHex;
|
|||||||
use secp256k1::constants::{SECRET_KEY_SIZE as SECP256K1_SECRET_KEY_SIZE};
|
use secp256k1::constants::{SECRET_KEY_SIZE as SECP256K1_SECRET_KEY_SIZE};
|
||||||
use secp256k1::key;
|
use secp256k1::key;
|
||||||
use ethereum_types::H256;
|
use ethereum_types::H256;
|
||||||
use mem::Memzero;
|
use memzero::Memzero;
|
||||||
use {Error, SECP256K1};
|
use {Error, SECP256K1};
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq)]
|
#[derive(Clone, PartialEq, Eq)]
|
||||||
@@ -1,18 +1,18 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
// Copyright 2015-2019 Parity Technologies (UK) Ltd.
|
||||||
// This file is part of Parity.
|
// This file is part of Parity Ethereum.
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
// Parity Ethereum is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
// Parity Ethereum is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use std::ops::{Deref, DerefMut};
|
use std::ops::{Deref, DerefMut};
|
||||||
use std::cmp::PartialEq;
|
use std::cmp::PartialEq;
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "ethstore"
|
name = "ethstore"
|
||||||
version = "0.2.0"
|
version = "0.2.1"
|
||||||
authors = ["Parity Technologies <admin@parity.io>"]
|
authors = ["Parity Technologies <admin@parity.io>"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
log = "0.3"
|
log = "0.4"
|
||||||
libc = "0.2"
|
libc = "0.2"
|
||||||
rand = "0.4"
|
rand = "0.4"
|
||||||
ethkey = { path = "../ethkey" }
|
ethkey = { path = "../ethkey" }
|
||||||
@@ -12,17 +12,15 @@ serde = "1.0"
|
|||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
serde_derive = "1.0"
|
serde_derive = "1.0"
|
||||||
rustc-hex = "1.0"
|
rustc-hex = "1.0"
|
||||||
rust-crypto = "0.2.36"
|
tiny-keccak = "1.4"
|
||||||
tiny-keccak = "1.3"
|
|
||||||
time = "0.1.34"
|
time = "0.1.34"
|
||||||
itertools = "0.5"
|
itertools = "0.5"
|
||||||
parking_lot = "0.5"
|
parking_lot = "0.7"
|
||||||
ethcore-crypto = { path = "../ethcore/crypto" }
|
parity-crypto = "0.2"
|
||||||
ethereum-types = "0.3"
|
ethereum-types = "0.4"
|
||||||
dir = { path = "../util/dir" }
|
dir = { path = "../../util/dir" }
|
||||||
smallvec = "0.4"
|
smallvec = "0.6"
|
||||||
parity-wordlist = "1.0"
|
parity-wordlist = "1.0"
|
||||||
subtle = "0.5"
|
|
||||||
tempdir = "0.3"
|
tempdir = "0.3"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
@@ -1,19 +1,12 @@
|
|||||||
# ethstore
|
## ethstore-cli
|
||||||
|
|
||||||
[![Build Status][travis-image]][travis-url]
|
Parity Ethereum key management.
|
||||||
|
|
||||||
[travis-image]: https://travis-ci.org/paritytech/ethstore.svg?branch=master
|
|
||||||
[travis-url]: https://travis-ci.org/paritytech/ethstore
|
|
||||||
|
|
||||||
Ethereum key management.
|
|
||||||
|
|
||||||
[Documentation](http://paritytech.github.io/ethstore/ethstore/index.html)
|
|
||||||
|
|
||||||
### Usage
|
### Usage
|
||||||
|
|
||||||
```
|
```
|
||||||
Ethereum key management.
|
Parity Ethereum key management tool.
|
||||||
Copyright 2016, 2017 Parity Technologies (UK) Ltd
|
Copyright 2015-2018 Parity Technologies (UK) Ltd.
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
ethstore insert <secret> <password> [--dir DIR] [--vault VAULT] [--vault-pwd VAULTPWD]
|
ethstore insert <secret> <password> [--dir DIR] [--vault VAULT] [--vault-pwd VAULTPWD]
|
||||||
@@ -35,19 +28,19 @@ Usage:
|
|||||||
Options:
|
Options:
|
||||||
-h, --help Display this message and exit.
|
-h, --help Display this message and exit.
|
||||||
--dir DIR Specify the secret store directory. It may be either
|
--dir DIR Specify the secret store directory. It may be either
|
||||||
parity, parity-test, geth, geth-test
|
parity, parity-(chain), geth, geth-test
|
||||||
or a path [default: parity].
|
or a path [default: parity].
|
||||||
--vault VAULT Specify vault to use in this operation.
|
--vault VAULT Specify vault to use in this operation.
|
||||||
--vault-pwd VAULTPWD Specify vault password to use in this operation. Please note
|
--vault-pwd VAULTPWD Specify vault password to use in this operation. Please note
|
||||||
that this option is required when vault option is set.
|
that this option is required when vault option is set.
|
||||||
Otherwise it is ignored.
|
Otherwise it is ignored.
|
||||||
--src DIR Specify import source. It may be either
|
--src DIR Specify import source. It may be either
|
||||||
parity, parity-test, get, geth-test
|
parity, parity-(chain), geth, geth-test
|
||||||
or a path [default: geth].
|
or a path [default: geth].
|
||||||
|
|
||||||
Commands:
|
Commands:
|
||||||
insert Save account with password.
|
insert Save account with password.
|
||||||
change-pwd Change account password.
|
change-pwd Change password.
|
||||||
list List accounts.
|
list List accounts.
|
||||||
import Import accounts from src.
|
import Import accounts from src.
|
||||||
import-wallet Import presale wallet.
|
import-wallet Import presale wallet.
|
||||||
@@ -59,7 +52,7 @@ Commands:
|
|||||||
create-vault Create new vault.
|
create-vault Create new vault.
|
||||||
change-vault-pwd Change vault password.
|
change-vault-pwd Change vault password.
|
||||||
move-to-vault Move account to vault from another vault/root directory.
|
move-to-vault Move account to vault from another vault/root directory.
|
||||||
move-from-vault Move account to root directory from given vault or root.
|
move-from-vault Move account to root directory from given vault.
|
||||||
```
|
```
|
||||||
|
|
||||||
### Examples
|
### Examples
|
||||||
@@ -337,11 +330,11 @@ ethstore move-from-vault 00e63fdb87ceb815ec96ae185b8f7381a0b4a5ea vault1 vault1_
|
|||||||
OK
|
OK
|
||||||
```
|
```
|
||||||
|
|
||||||
--
|
## Parity Ethereum toolchain
|
||||||
|
_This project is a part of the Parity Ethereum toolchain._
|
||||||
|
|
||||||
# Parity toolchain
|
- [evmbin](https://github.com/paritytech/parity-ethereum/blob/master/evmbin/) - EVM implementation for Parity Ethereum.
|
||||||
*this project is a part of the parity toolchain*
|
- [ethabi](https://github.com/paritytech/ethabi) - Parity Ethereum function calls encoding.
|
||||||
|
- [ethstore](https://github.com/paritytech/parity-ethereum/blob/master/accounts/ethstore) - Parity Ethereum key management.
|
||||||
- [**ethkey**](https://github.com/paritytech/ethkey) - Ethereum keys generator and signer.
|
- [ethkey](https://github.com/paritytech/parity-ethereum/blob/master/accounts/ethkey) - Parity Ethereum keys generator.
|
||||||
- [**ethstore**](https://github.com/paritytech/ethstore) - Ethereum key management.
|
- [whisper](https://github.com/paritytech/parity-ethereum/blob/master/whisper/) - Implementation of Whisper-v2 PoC.
|
||||||
- [**ethabi**](https://github.com/paritytech/ethabi) - Ethereum function calls encoding.
|
|
||||||
@@ -1,18 +1,19 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "ethstore-cli"
|
name = "ethstore-cli"
|
||||||
version = "0.1.0"
|
version = "0.1.1"
|
||||||
authors = ["Parity Technologies <admin@parity.io>"]
|
authors = ["Parity Technologies <admin@parity.io>"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
docopt = "0.8"
|
docopt = "1.0"
|
||||||
|
env_logger = "0.5"
|
||||||
num_cpus = "1.6"
|
num_cpus = "1.6"
|
||||||
rustc-hex = "1.0"
|
rustc-hex = "1.0"
|
||||||
serde = "1.0"
|
serde = "1.0"
|
||||||
serde_derive = "1.0"
|
serde_derive = "1.0"
|
||||||
parking_lot = "0.5"
|
parking_lot = "0.7"
|
||||||
ethstore = { path = "../" }
|
ethstore = { path = "../" }
|
||||||
dir = { path = '../../util/dir' }
|
dir = { path = '../../../util/dir' }
|
||||||
panic_hook = { path = "../../util/panic_hook" }
|
panic_hook = { path = "../../../util/panic-hook" }
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "ethstore"
|
name = "ethstore"
|
||||||
66
accounts/ethstore/cli/src/crack.rs
Normal file
66
accounts/ethstore/cli/src/crack.rs
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
// Copyright 2015-2019 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity Ethereum.
|
||||||
|
|
||||||
|
// Parity Ethereum is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity Ethereum is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
use std::{cmp, thread};
|
||||||
|
use std::sync::Arc;
|
||||||
|
use std::collections::VecDeque;
|
||||||
|
use parking_lot::Mutex;
|
||||||
|
|
||||||
|
use ethstore::{ethkey::Password, PresaleWallet, Error};
|
||||||
|
use num_cpus;
|
||||||
|
|
||||||
|
pub fn run(passwords: VecDeque<Password>, wallet_path: &str) -> Result<(), Error> {
|
||||||
|
let passwords = Arc::new(Mutex::new(passwords));
|
||||||
|
|
||||||
|
let mut handles = Vec::new();
|
||||||
|
|
||||||
|
for _ in 0..num_cpus::get() {
|
||||||
|
let passwords = passwords.clone();
|
||||||
|
let wallet = PresaleWallet::open(&wallet_path)?;
|
||||||
|
handles.push(thread::spawn(move || {
|
||||||
|
look_for_password(passwords, wallet);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
for handle in handles {
|
||||||
|
handle.join().map_err(|err| Error::Custom(format!("Error finishing thread: {:?}", err)))?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn look_for_password(passwords: Arc<Mutex<VecDeque<Password>>>, wallet: PresaleWallet) {
|
||||||
|
let mut counter = 0;
|
||||||
|
while !passwords.lock().is_empty() {
|
||||||
|
let package = {
|
||||||
|
let mut passwords = passwords.lock();
|
||||||
|
let len = passwords.len();
|
||||||
|
passwords.split_off(cmp::min(len, 32))
|
||||||
|
};
|
||||||
|
for pass in package {
|
||||||
|
counter += 1;
|
||||||
|
match wallet.decrypt(&pass) {
|
||||||
|
Ok(_) => {
|
||||||
|
println!("Found password: {}", pass.as_str());
|
||||||
|
passwords.lock().clear();
|
||||||
|
return;
|
||||||
|
},
|
||||||
|
_ if counter % 100 == 0 => print!("."),
|
||||||
|
_ => {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,18 +1,18 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
// Copyright 2015-2019 Parity Technologies (UK) Ltd.
|
||||||
// This file is part of Parity.
|
// This file is part of Parity Ethereum.
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
// Parity Ethereum is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
// Parity Ethereum is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
extern crate dir;
|
extern crate dir;
|
||||||
extern crate docopt;
|
extern crate docopt;
|
||||||
@@ -23,6 +23,8 @@ extern crate parking_lot;
|
|||||||
extern crate rustc_hex;
|
extern crate rustc_hex;
|
||||||
extern crate serde;
|
extern crate serde;
|
||||||
|
|
||||||
|
extern crate env_logger;
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate serde_derive;
|
extern crate serde_derive;
|
||||||
|
|
||||||
@@ -32,20 +34,20 @@ use std::{env, process, fs, fmt};
|
|||||||
|
|
||||||
use docopt::Docopt;
|
use docopt::Docopt;
|
||||||
use ethstore::accounts_dir::{KeyDirectory, RootDiskDirectory};
|
use ethstore::accounts_dir::{KeyDirectory, RootDiskDirectory};
|
||||||
use ethstore::ethkey::Address;
|
use ethstore::ethkey::{Address, Password};
|
||||||
use ethstore::{EthStore, SimpleSecretStore, SecretStore, import_accounts, PresaleWallet, SecretVaultRef, StoreAccountRef};
|
use ethstore::{EthStore, SimpleSecretStore, SecretStore, import_accounts, PresaleWallet, SecretVaultRef, StoreAccountRef};
|
||||||
|
|
||||||
mod crack;
|
mod crack;
|
||||||
|
|
||||||
pub const USAGE: &'static str = r#"
|
pub const USAGE: &'static str = r#"
|
||||||
Ethereum key management.
|
Parity Ethereum key management tool.
|
||||||
Copyright 2016, 2017 Parity Technologies (UK) Ltd
|
Copyright 2015-2018 Parity Technologies (UK) Ltd.
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
ethstore insert <secret> <password> [--dir DIR] [--vault VAULT] [--vault-pwd VAULTPWD]
|
ethstore insert <secret> <password> [--dir DIR] [--vault VAULT] [--vault-pwd VAULTPWD]
|
||||||
ethstore change-pwd <address> <old-pwd> <new-pwd> [--dir DIR] [--vault VAULT] [--vault-pwd VAULTPWD]
|
ethstore change-pwd <address> <old-pwd> <new-pwd> [--dir DIR] [--vault VAULT] [--vault-pwd VAULTPWD]
|
||||||
ethstore list [--dir DIR] [--vault VAULT] [--vault-pwd VAULTPWD]
|
ethstore list [--dir DIR] [--vault VAULT] [--vault-pwd VAULTPWD]
|
||||||
ethstore import [--src DIR] [--dir DIR]
|
ethstore import [<password>] [--src DIR] [--dir DIR]
|
||||||
ethstore import-wallet <path> <password> [--dir DIR] [--vault VAULT] [--vault-pwd VAULTPWD]
|
ethstore import-wallet <path> <password> [--dir DIR] [--vault VAULT] [--vault-pwd VAULTPWD]
|
||||||
ethstore find-wallet-pass <path> <password>
|
ethstore find-wallet-pass <path> <password>
|
||||||
ethstore remove <address> <password> [--dir DIR] [--vault VAULT] [--vault-pwd VAULTPWD]
|
ethstore remove <address> <password> [--dir DIR] [--vault VAULT] [--vault-pwd VAULTPWD]
|
||||||
@@ -68,7 +70,7 @@ Options:
|
|||||||
that this option is required when vault option is set.
|
that this option is required when vault option is set.
|
||||||
Otherwise it is ignored.
|
Otherwise it is ignored.
|
||||||
--src DIR Specify import source. It may be either
|
--src DIR Specify import source. It may be either
|
||||||
parity, parity-(chain), get, geth-test
|
parity, parity-(chain), geth, geth-test
|
||||||
or a path [default: geth].
|
or a path [default: geth].
|
||||||
|
|
||||||
Commands:
|
Commands:
|
||||||
@@ -145,30 +147,35 @@ impl fmt::Display for Error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
panic_hook::set();
|
panic_hook::set_abort();
|
||||||
|
if env::var("RUST_LOG").is_err() {
|
||||||
|
env::set_var("RUST_LOG", "warn")
|
||||||
|
}
|
||||||
|
env_logger::try_init().expect("Logger initialized only once.");
|
||||||
|
|
||||||
match execute(env::args()) {
|
match execute(env::args()) {
|
||||||
Ok(result) => println!("{}", result),
|
Ok(result) => println!("{}", result),
|
||||||
|
Err(Error::Docopt(ref e)) => e.exit(),
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
println!("{}", err);
|
eprintln!("{}", err);
|
||||||
process::exit(1);
|
process::exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn key_dir(location: &str) -> Result<Box<KeyDirectory>, Error> {
|
fn key_dir(location: &str, password: Option<Password>) -> Result<Box<KeyDirectory>, Error> {
|
||||||
let dir: Box<KeyDirectory> = match location {
|
let dir: RootDiskDirectory = match location {
|
||||||
"geth" => Box::new(RootDiskDirectory::create(dir::geth(false))?),
|
"geth" => RootDiskDirectory::create(dir::geth(false))?,
|
||||||
"geth-test" => Box::new(RootDiskDirectory::create(dir::geth(true))?),
|
"geth-test" => RootDiskDirectory::create(dir::geth(true))?,
|
||||||
path if path.starts_with("parity") => {
|
path if path.starts_with("parity") => {
|
||||||
let chain = path.split('-').nth(1).unwrap_or("ethereum");
|
let chain = path.split('-').nth(1).unwrap_or("ethereum");
|
||||||
let path = dir::parity(chain);
|
let path = dir::parity(chain);
|
||||||
Box::new(RootDiskDirectory::create(path)?)
|
RootDiskDirectory::create(path)?
|
||||||
},
|
},
|
||||||
path => Box::new(RootDiskDirectory::create(path)?),
|
path => RootDiskDirectory::create(path)?,
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(dir)
|
Ok(Box::new(dir.with_password(password)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn open_args_vault(store: &EthStore, args: &Args) -> Result<SecretVaultRef, Error> {
|
fn open_args_vault(store: &EthStore, args: &Args) -> Result<SecretVaultRef, Error> {
|
||||||
@@ -200,20 +207,20 @@ fn format_vaults(vaults: &[String]) -> String {
|
|||||||
vaults.join("\n")
|
vaults.join("\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_password(path: &str) -> Result<String, Error> {
|
fn load_password(path: &str) -> Result<Password, Error> {
|
||||||
let mut file = fs::File::open(path).map_err(|e| ethstore::Error::Custom(format!("Error opening password file {}: {}", path, e)))?;
|
let mut file = fs::File::open(path).map_err(|e| ethstore::Error::Custom(format!("Error opening password file '{}': {}", path, e)))?;
|
||||||
let mut password = String::new();
|
let mut password = String::new();
|
||||||
file.read_to_string(&mut password).map_err(|e| ethstore::Error::Custom(format!("Error reading password file {}: {}", path, e)))?;
|
file.read_to_string(&mut password).map_err(|e| ethstore::Error::Custom(format!("Error reading password file '{}': {}", path, e)))?;
|
||||||
// drop EOF
|
// drop EOF
|
||||||
let _ = password.pop();
|
let _ = password.pop();
|
||||||
Ok(password)
|
Ok(password.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn execute<S, I>(command: I) -> Result<String, Error> where I: IntoIterator<Item=S>, S: AsRef<str> {
|
fn execute<S, I>(command: I) -> Result<String, Error> where I: IntoIterator<Item=S>, S: AsRef<str> {
|
||||||
let args: Args = Docopt::new(USAGE)
|
let args: Args = Docopt::new(USAGE)
|
||||||
.and_then(|d| d.argv(command).deserialize())?;
|
.and_then(|d| d.argv(command).deserialize())?;
|
||||||
|
|
||||||
let store = EthStore::open(key_dir(&args.flag_dir)?)?;
|
let store = EthStore::open(key_dir(&args.flag_dir, None)?)?;
|
||||||
|
|
||||||
return if args.cmd_insert {
|
return if args.cmd_insert {
|
||||||
let secret = args.arg_secret.parse().map_err(|_| ethstore::Error::InvalidSecret)?;
|
let secret = args.arg_secret.parse().map_err(|_| ethstore::Error::InvalidSecret)?;
|
||||||
@@ -238,8 +245,13 @@ fn execute<S, I>(command: I) -> Result<String, Error> where I: IntoIterator<Item
|
|||||||
.collect();
|
.collect();
|
||||||
Ok(format_accounts(&accounts))
|
Ok(format_accounts(&accounts))
|
||||||
} else if args.cmd_import {
|
} else if args.cmd_import {
|
||||||
let src = key_dir(&args.flag_src)?;
|
let password = match args.arg_password.as_ref() {
|
||||||
let dst = key_dir(&args.flag_dir)?;
|
"" => None,
|
||||||
|
_ => Some(load_password(&args.arg_password)?)
|
||||||
|
};
|
||||||
|
let src = key_dir(&args.flag_src, password)?;
|
||||||
|
let dst = key_dir(&args.flag_dir, None)?;
|
||||||
|
|
||||||
let accounts = import_accounts(&*src, &*dst)?;
|
let accounts = import_accounts(&*src, &*dst)?;
|
||||||
Ok(format_accounts(&accounts))
|
Ok(format_accounts(&accounts))
|
||||||
} else if args.cmd_import_wallet {
|
} else if args.cmd_import_wallet {
|
||||||
@@ -251,7 +263,7 @@ fn execute<S, I>(command: I) -> Result<String, Error> where I: IntoIterator<Item
|
|||||||
Ok(format!("0x{:x}", account_ref.address))
|
Ok(format!("0x{:x}", account_ref.address))
|
||||||
} else if args.cmd_find_wallet_pass {
|
} else if args.cmd_find_wallet_pass {
|
||||||
let passwords = load_password(&args.arg_password)?;
|
let passwords = load_password(&args.arg_password)?;
|
||||||
let passwords = passwords.lines().map(str::to_owned).collect::<VecDeque<_>>();
|
let passwords = passwords.as_str().lines().map(|line| str::to_owned(line).into()).collect::<VecDeque<_>>();
|
||||||
crack::run(passwords, &args.arg_path)?;
|
crack::run(passwords, &args.arg_path)?;
|
||||||
Ok(format!("Password not found."))
|
Ok(format!("Password not found."))
|
||||||
} else if args.cmd_remove {
|
} else if args.cmd_remove {
|
||||||
@@ -1,18 +1,18 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
// Copyright 2015-2019 Parity Technologies (UK) Ltd.
|
||||||
// This file is part of Parity.
|
// This file is part of Parity Ethereum.
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
// Parity Ethereum is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
// Parity Ethereum is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
extern crate tempdir;
|
extern crate tempdir;
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
@@ -74,7 +74,6 @@ fn cli_cmd() {
|
|||||||
"--vault-pwd", test_password]);
|
"--vault-pwd", test_password]);
|
||||||
assert_eq!(output, "0x54ab6e5cf0c5cb40043fdca5d15d611a3a94285414a076dafecc8dc9c04183f413296a3defff61092c0bb478dc9887ec01070e1275234211208fb8f4be4a9b0101\n");
|
assert_eq!(output, "0x54ab6e5cf0c5cb40043fdca5d15d611a3a94285414a076dafecc8dc9c04183f413296a3defff61092c0bb478dc9887ec01070e1275234211208fb8f4be4a9b0101\n");
|
||||||
|
|
||||||
|
|
||||||
let output = run(&["public", &address[2..], test_vault_addr,
|
let output = run(&["public", &address[2..], test_vault_addr,
|
||||||
"--dir", dir_str,
|
"--dir", dir_str,
|
||||||
"--vault", "test-vault",
|
"--vault", "test-vault",
|
||||||
@@ -1,18 +1,18 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
// Copyright 2015-2019 Parity Technologies (UK) Ltd.
|
||||||
// This file is part of Parity.
|
// This file is part of Parity Ethereum.
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
// Parity Ethereum is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
// Parity Ethereum is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use json;
|
use json;
|
||||||
|
|
||||||
@@ -1,27 +1,26 @@
|
|||||||
// Copyright 2015, 2016, 2017 Parity Technologies (UK) Ltd.
|
// Copyright 2015-2019 Parity Technologies (UK) Ltd.
|
||||||
// This file is part of Parity.
|
// This file is part of Parity Ethereum.
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
// Parity Ethereum is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
// Parity Ethereum is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use std::str;
|
use std::str;
|
||||||
use ethkey::Secret;
|
use ethkey::{Password, Secret};
|
||||||
use {json, Error, crypto};
|
use {json, Error, crypto};
|
||||||
use crypto::Keccak256;
|
use crypto::Keccak256;
|
||||||
use random::Random;
|
use random::Random;
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
use account::{Cipher, Kdf, Aes128Ctr, Pbkdf2, Prf};
|
use account::{Cipher, Kdf, Aes128Ctr, Pbkdf2, Prf};
|
||||||
use subtle;
|
|
||||||
|
|
||||||
/// Encrypted data
|
/// Encrypted data
|
||||||
#[derive(Debug, PartialEq, Clone)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
@@ -74,18 +73,19 @@ impl From<Crypto> for String {
|
|||||||
|
|
||||||
impl Crypto {
|
impl Crypto {
|
||||||
/// Encrypt account secret
|
/// Encrypt account secret
|
||||||
pub fn with_secret(secret: &Secret, password: &str, iterations: u32) -> Self {
|
pub fn with_secret(secret: &Secret, password: &Password, iterations: u32) -> Result<Self, crypto::Error> {
|
||||||
Crypto::with_plain(&*secret, password, iterations)
|
Crypto::with_plain(&*secret, password, iterations)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Encrypt custom plain data
|
/// Encrypt custom plain data
|
||||||
pub fn with_plain(plain: &[u8], password: &str, iterations: u32) -> Self {
|
pub fn with_plain(plain: &[u8], password: &Password, iterations: u32) -> Result<Self, crypto::Error> {
|
||||||
let salt: [u8; 32] = Random::random();
|
let salt: [u8; 32] = Random::random();
|
||||||
let iv: [u8; 16] = Random::random();
|
let iv: [u8; 16] = Random::random();
|
||||||
|
|
||||||
// two parts of derived key
|
// two parts of derived key
|
||||||
// DK = [ DK[0..15] DK[16..31] ] = [derived_left_bits, derived_right_bits]
|
// DK = [ DK[0..15] DK[16..31] ] = [derived_left_bits, derived_right_bits]
|
||||||
let (derived_left_bits, derived_right_bits) = crypto::derive_key_iterations(password, &salt, iterations);
|
let (derived_left_bits, derived_right_bits) =
|
||||||
|
crypto::derive_key_iterations(password.as_bytes(), &salt, iterations);
|
||||||
|
|
||||||
// preallocated (on-stack in case of `Secret`) buffer to hold cipher
|
// preallocated (on-stack in case of `Secret`) buffer to hold cipher
|
||||||
// length = length(plain) as we are using CTR-approach
|
// length = length(plain) as we are using CTR-approach
|
||||||
@@ -93,28 +93,28 @@ impl Crypto {
|
|||||||
let mut ciphertext: SmallVec<[u8; 32]> = SmallVec::from_vec(vec![0; plain_len]);
|
let mut ciphertext: SmallVec<[u8; 32]> = SmallVec::from_vec(vec![0; plain_len]);
|
||||||
|
|
||||||
// aes-128-ctr with initial vector of iv
|
// aes-128-ctr with initial vector of iv
|
||||||
crypto::aes::encrypt(&derived_left_bits, &iv, plain, &mut *ciphertext);
|
crypto::aes::encrypt_128_ctr(&derived_left_bits, &iv, plain, &mut *ciphertext)?;
|
||||||
|
|
||||||
// KECCAK(DK[16..31] ++ <ciphertext>), where DK[16..31] - derived_right_bits
|
// KECCAK(DK[16..31] ++ <ciphertext>), where DK[16..31] - derived_right_bits
|
||||||
let mac = crypto::derive_mac(&derived_right_bits, &*ciphertext).keccak256();
|
let mac = crypto::derive_mac(&derived_right_bits, &*ciphertext).keccak256();
|
||||||
|
|
||||||
Crypto {
|
Ok(Crypto {
|
||||||
cipher: Cipher::Aes128Ctr(Aes128Ctr {
|
cipher: Cipher::Aes128Ctr(Aes128Ctr {
|
||||||
iv: iv,
|
iv: iv,
|
||||||
}),
|
}),
|
||||||
ciphertext: ciphertext.into_vec(),
|
ciphertext: ciphertext.into_vec(),
|
||||||
kdf: Kdf::Pbkdf2(Pbkdf2 {
|
kdf: Kdf::Pbkdf2(Pbkdf2 {
|
||||||
dklen: crypto::KEY_LENGTH as u32,
|
dklen: crypto::KEY_LENGTH as u32,
|
||||||
salt: salt,
|
salt: salt.to_vec(),
|
||||||
c: iterations,
|
c: iterations,
|
||||||
prf: Prf::HmacSha256,
|
prf: Prf::HmacSha256,
|
||||||
}),
|
}),
|
||||||
mac: mac,
|
mac: mac,
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Try to decrypt and convert result to account secret
|
/// Try to decrypt and convert result to account secret
|
||||||
pub fn secret(&self, password: &str) -> Result<Secret, Error> {
|
pub fn secret(&self, password: &Password) -> Result<Secret, Error> {
|
||||||
if self.ciphertext.len() > 32 {
|
if self.ciphertext.len() > 32 {
|
||||||
return Err(Error::InvalidSecret);
|
return Err(Error::InvalidSecret);
|
||||||
}
|
}
|
||||||
@@ -124,21 +124,21 @@ impl Crypto {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Try to decrypt and return result as is
|
/// Try to decrypt and return result as is
|
||||||
pub fn decrypt(&self, password: &str) -> Result<Vec<u8>, Error> {
|
pub fn decrypt(&self, password: &Password) -> Result<Vec<u8>, Error> {
|
||||||
let expected_len = self.ciphertext.len();
|
let expected_len = self.ciphertext.len();
|
||||||
self.do_decrypt(password, expected_len)
|
self.do_decrypt(password, expected_len)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn do_decrypt(&self, password: &str, expected_len: usize) -> Result<Vec<u8>, Error> {
|
fn do_decrypt(&self, password: &Password, expected_len: usize) -> Result<Vec<u8>, Error> {
|
||||||
let (derived_left_bits, derived_right_bits) = match self.kdf {
|
let (derived_left_bits, derived_right_bits) = match self.kdf {
|
||||||
Kdf::Pbkdf2(ref params) => crypto::derive_key_iterations(password, ¶ms.salt, params.c),
|
Kdf::Pbkdf2(ref params) => crypto::derive_key_iterations(password.as_bytes(), ¶ms.salt, params.c),
|
||||||
Kdf::Scrypt(ref params) => crypto::derive_key_scrypt(password, ¶ms.salt, params.n, params.p, params.r)?,
|
Kdf::Scrypt(ref params) => crypto::scrypt::derive_key(password.as_bytes(), ¶ms.salt, params.n, params.p, params.r)?,
|
||||||
};
|
};
|
||||||
|
|
||||||
let mac = crypto::derive_mac(&derived_right_bits, &self.ciphertext).keccak256();
|
let mac = crypto::derive_mac(&derived_right_bits, &self.ciphertext).keccak256();
|
||||||
|
|
||||||
if subtle::slices_equal(&mac, &self.mac) == 0 {
|
if !crypto::is_equal(&mac, &self.mac) {
|
||||||
return Err(Error::InvalidPassword);
|
return Err(Error::InvalidPassword)
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut plain: SmallVec<[u8; 32]> = SmallVec::from_vec(vec![0; expected_len]);
|
let mut plain: SmallVec<[u8; 32]> = SmallVec::from_vec(vec![0; expected_len]);
|
||||||
@@ -149,7 +149,7 @@ impl Crypto {
|
|||||||
debug_assert!(expected_len >= self.ciphertext.len());
|
debug_assert!(expected_len >= self.ciphertext.len());
|
||||||
|
|
||||||
let from = expected_len - self.ciphertext.len();
|
let from = expected_len - self.ciphertext.len();
|
||||||
crypto::aes::decrypt(&derived_left_bits, ¶ms.iv, &self.ciphertext, &mut plain[from..]);
|
crypto::aes::decrypt_128_ctr(&derived_left_bits, ¶ms.iv, &self.ciphertext, &mut plain[from..])?;
|
||||||
Ok(plain.into_iter().collect())
|
Ok(plain.into_iter().collect())
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -164,39 +164,43 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn crypto_with_secret_create() {
|
fn crypto_with_secret_create() {
|
||||||
let keypair = Random.generate().unwrap();
|
let keypair = Random.generate().unwrap();
|
||||||
let crypto = Crypto::with_secret(keypair.secret(), "this is sparta", 10240);
|
let passwd = "this is sparta".into();
|
||||||
let secret = crypto.secret("this is sparta").unwrap();
|
let crypto = Crypto::with_secret(keypair.secret(), &passwd, 10240).unwrap();
|
||||||
|
let secret = crypto.secret(&passwd).unwrap();
|
||||||
assert_eq!(keypair.secret(), &secret);
|
assert_eq!(keypair.secret(), &secret);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn crypto_with_secret_invalid_password() {
|
fn crypto_with_secret_invalid_password() {
|
||||||
let keypair = Random.generate().unwrap();
|
let keypair = Random.generate().unwrap();
|
||||||
let crypto = Crypto::with_secret(keypair.secret(), "this is sparta", 10240);
|
let crypto = Crypto::with_secret(keypair.secret(), &"this is sparta".into(), 10240).unwrap();
|
||||||
assert_matches!(crypto.secret("this is sparta!"), Err(Error::InvalidPassword))
|
assert_matches!(crypto.secret(&"this is sparta!".into()), Err(Error::InvalidPassword))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn crypto_with_null_plain_data() {
|
fn crypto_with_null_plain_data() {
|
||||||
let original_data = b"";
|
let original_data = b"";
|
||||||
let crypto = Crypto::with_plain(&original_data[..], "this is sparta", 10240);
|
let passwd = "this is sparta".into();
|
||||||
let decrypted_data = crypto.decrypt("this is sparta").unwrap();
|
let crypto = Crypto::with_plain(&original_data[..], &passwd, 10240).unwrap();
|
||||||
|
let decrypted_data = crypto.decrypt(&passwd).unwrap();
|
||||||
assert_eq!(original_data[..], *decrypted_data);
|
assert_eq!(original_data[..], *decrypted_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn crypto_with_tiny_plain_data() {
|
fn crypto_with_tiny_plain_data() {
|
||||||
let original_data = b"{}";
|
let original_data = b"{}";
|
||||||
let crypto = Crypto::with_plain(&original_data[..], "this is sparta", 10240);
|
let passwd = "this is sparta".into();
|
||||||
let decrypted_data = crypto.decrypt("this is sparta").unwrap();
|
let crypto = Crypto::with_plain(&original_data[..], &passwd, 10240).unwrap();
|
||||||
|
let decrypted_data = crypto.decrypt(&passwd).unwrap();
|
||||||
assert_eq!(original_data[..], *decrypted_data);
|
assert_eq!(original_data[..], *decrypted_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn crypto_with_huge_plain_data() {
|
fn crypto_with_huge_plain_data() {
|
||||||
let original_data: Vec<_> = (1..65536).map(|i| (i % 256) as u8).collect();
|
let original_data: Vec<_> = (1..65536).map(|i| (i % 256) as u8).collect();
|
||||||
let crypto = Crypto::with_plain(&original_data, "this is sparta", 10240);
|
let passwd = "this is sparta".into();
|
||||||
let decrypted_data = crypto.decrypt("this is sparta").unwrap();
|
let crypto = Crypto::with_plain(&original_data, &passwd, 10240).unwrap();
|
||||||
|
let decrypted_data = crypto.decrypt(&passwd).unwrap();
|
||||||
assert_eq!(&original_data, &decrypted_data);
|
assert_eq!(&original_data, &decrypted_data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,18 +1,18 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
// Copyright 2015-2019 Parity Technologies (UK) Ltd.
|
||||||
// This file is part of Parity.
|
// This file is part of Parity Ethereum.
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
// Parity Ethereum is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
// Parity Ethereum is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use json;
|
use json;
|
||||||
|
|
||||||
@@ -26,7 +26,7 @@ pub struct Pbkdf2 {
|
|||||||
pub c: u32,
|
pub c: u32,
|
||||||
pub dklen: u32,
|
pub dklen: u32,
|
||||||
pub prf: Prf,
|
pub prf: Prf,
|
||||||
pub salt: [u8; 32],
|
pub salt: Vec<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
@@ -35,7 +35,7 @@ pub struct Scrypt {
|
|||||||
pub p: u32,
|
pub p: u32,
|
||||||
pub n: u32,
|
pub n: u32,
|
||||||
pub r: u32,
|
pub r: u32,
|
||||||
pub salt: [u8; 32],
|
pub salt: Vec<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
@@ -1,18 +1,18 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
// Copyright 2015-2019 Parity Technologies (UK) Ltd.
|
||||||
// This file is part of Parity.
|
// This file is part of Parity Ethereum.
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
// Parity Ethereum is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
// Parity Ethereum is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
mod cipher;
|
mod cipher;
|
||||||
mod crypto;
|
mod crypto;
|
||||||
@@ -25,4 +25,3 @@ pub use self::crypto::Crypto;
|
|||||||
pub use self::kdf::{Kdf, Pbkdf2, Scrypt, Prf};
|
pub use self::kdf::{Kdf, Pbkdf2, Scrypt, Prf};
|
||||||
pub use self::safe_account::SafeAccount;
|
pub use self::safe_account::SafeAccount;
|
||||||
pub use self::version::Version;
|
pub use self::version::Version;
|
||||||
|
|
||||||
@@ -1,23 +1,24 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
// Copyright 2015-2019 Parity Technologies (UK) Ltd.
|
||||||
// This file is part of Parity.
|
// This file is part of Parity Ethereum.
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
// Parity Ethereum is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
// Parity Ethereum is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use ethkey::{KeyPair, sign, Address, Signature, Message, Public, Secret};
|
use ethkey::{self, KeyPair, sign, Address, Password, Signature, Message, Public, Secret};
|
||||||
use crypto::ecdh::agree;
|
use ethkey::crypto::ecdh::agree;
|
||||||
use {json, Error, crypto};
|
use {json, Error};
|
||||||
use account::Version;
|
use account::Version;
|
||||||
|
use crypto;
|
||||||
use super::crypto::Crypto;
|
use super::crypto::Crypto;
|
||||||
|
|
||||||
/// Account representation.
|
/// Account representation.
|
||||||
@@ -44,7 +45,7 @@ impl Into<json::KeyFile> for SafeAccount {
|
|||||||
json::KeyFile {
|
json::KeyFile {
|
||||||
id: From::from(self.id),
|
id: From::from(self.id),
|
||||||
version: self.version.into(),
|
version: self.version.into(),
|
||||||
address: self.address.into(),
|
address: Some(self.address.into()),
|
||||||
crypto: self.crypto.into(),
|
crypto: self.crypto.into(),
|
||||||
name: Some(self.name.into()),
|
name: Some(self.name.into()),
|
||||||
meta: Some(self.meta.into()),
|
meta: Some(self.meta.into()),
|
||||||
@@ -57,64 +58,91 @@ impl SafeAccount {
|
|||||||
pub fn create(
|
pub fn create(
|
||||||
keypair: &KeyPair,
|
keypair: &KeyPair,
|
||||||
id: [u8; 16],
|
id: [u8; 16],
|
||||||
password: &str,
|
password: &Password,
|
||||||
iterations: u32,
|
iterations: u32,
|
||||||
name: String,
|
name: String,
|
||||||
meta: String
|
meta: String
|
||||||
) -> Self {
|
) -> Result<Self, crypto::Error> {
|
||||||
SafeAccount {
|
Ok(SafeAccount {
|
||||||
id: id,
|
id: id,
|
||||||
version: Version::V3,
|
version: Version::V3,
|
||||||
crypto: Crypto::with_secret(keypair.secret(), password, iterations),
|
crypto: Crypto::with_secret(keypair.secret(), password, iterations)?,
|
||||||
address: keypair.address(),
|
address: keypair.address(),
|
||||||
filename: None,
|
filename: None,
|
||||||
name: name,
|
name: name,
|
||||||
meta: meta,
|
meta: meta,
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new `SafeAccount` from the given `json`; if it was read from a
|
/// Create a new `SafeAccount` from the given `json`; if it was read from a
|
||||||
/// file, the `filename` should be `Some` name. If it is as yet anonymous, then it
|
/// file, the `filename` should be `Some` name. If it is as yet anonymous, then it
|
||||||
/// can be left `None`.
|
/// can be left `None`.
|
||||||
pub fn from_file(json: json::KeyFile, filename: Option<String>) -> Self {
|
/// In case `password` is provided, we will attempt to read the secret from the keyfile
|
||||||
SafeAccount {
|
/// and derive the address from it instead of reading it directly.
|
||||||
|
/// Providing password is required for `json::KeyFile`s with no address.
|
||||||
|
pub fn from_file(json: json::KeyFile, filename: Option<String>, password: &Option<Password>) -> Result<Self, Error> {
|
||||||
|
let crypto = Crypto::from(json.crypto);
|
||||||
|
let address = match (password, &json.address) {
|
||||||
|
(None, Some(json_address)) => json_address.into(),
|
||||||
|
(None, None) => Err(Error::Custom(
|
||||||
|
"This keystore does not contain address. You need to provide password to import it".into()))?,
|
||||||
|
(Some(password), json_address) => {
|
||||||
|
let derived_address = KeyPair::from_secret(
|
||||||
|
crypto.secret(&password).map_err(|_| Error::InvalidPassword)?
|
||||||
|
)?.address();
|
||||||
|
|
||||||
|
match json_address {
|
||||||
|
Some(json_address) => {
|
||||||
|
let json_address = json_address.into();
|
||||||
|
if derived_address != json_address {
|
||||||
|
warn!("Detected address mismatch when opening an account. Derived: {:?}, in json got: {:?}",
|
||||||
|
derived_address, json_address);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => {},
|
||||||
|
}
|
||||||
|
derived_address
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(SafeAccount {
|
||||||
id: json.id.into(),
|
id: json.id.into(),
|
||||||
version: json.version.into(),
|
version: json.version.into(),
|
||||||
address: json.address.into(),
|
address,
|
||||||
crypto: json.crypto.into(),
|
crypto,
|
||||||
filename: filename,
|
filename,
|
||||||
name: json.name.unwrap_or(String::new()),
|
name: json.name.unwrap_or(String::new()),
|
||||||
meta: json.meta.unwrap_or("{}".to_owned()),
|
meta: json.meta.unwrap_or("{}".to_owned()),
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new `SafeAccount` from the given vault `json`; if it was read from a
|
/// Create a new `SafeAccount` from the given vault `json`; if it was read from a
|
||||||
/// file, the `filename` should be `Some` name. If it is as yet anonymous, then it
|
/// file, the `filename` should be `Some` name. If it is as yet anonymous, then it
|
||||||
/// can be left `None`.
|
/// can be left `None`.
|
||||||
pub fn from_vault_file(password: &str, json: json::VaultKeyFile, filename: Option<String>) -> Result<Self, Error> {
|
pub fn from_vault_file(password: &Password, json: json::VaultKeyFile, filename: Option<String>) -> Result<Self, Error> {
|
||||||
let meta_crypto: Crypto = json.metacrypto.into();
|
let meta_crypto: Crypto = json.metacrypto.into();
|
||||||
let meta_plain = meta_crypto.decrypt(password)?;
|
let meta_plain = meta_crypto.decrypt(password)?;
|
||||||
let meta_plain = json::VaultKeyMeta::load(&meta_plain).map_err(|e| Error::Custom(format!("{:?}", e)))?;
|
let meta_plain = json::VaultKeyMeta::load(&meta_plain).map_err(|e| Error::Custom(format!("{:?}", e)))?;
|
||||||
|
|
||||||
Ok(SafeAccount::from_file(json::KeyFile {
|
SafeAccount::from_file(json::KeyFile {
|
||||||
id: json.id,
|
id: json.id,
|
||||||
version: json.version,
|
version: json.version,
|
||||||
crypto: json.crypto,
|
crypto: json.crypto,
|
||||||
address: meta_plain.address,
|
address: Some(meta_plain.address),
|
||||||
name: meta_plain.name,
|
name: meta_plain.name,
|
||||||
meta: meta_plain.meta,
|
meta: meta_plain.meta,
|
||||||
}, filename))
|
}, filename, &None)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new `VaultKeyFile` from the given `self`
|
/// Create a new `VaultKeyFile` from the given `self`
|
||||||
pub fn into_vault_file(self, iterations: u32, password: &str) -> Result<json::VaultKeyFile, Error> {
|
pub fn into_vault_file(self, iterations: u32, password: &Password) -> Result<json::VaultKeyFile, Error> {
|
||||||
let meta_plain = json::VaultKeyMeta {
|
let meta_plain = json::VaultKeyMeta {
|
||||||
address: self.address.into(),
|
address: self.address.into(),
|
||||||
name: Some(self.name),
|
name: Some(self.name),
|
||||||
meta: Some(self.meta),
|
meta: Some(self.meta),
|
||||||
};
|
};
|
||||||
let meta_plain = meta_plain.write().map_err(|e| Error::Custom(format!("{:?}", e)))?;
|
let meta_plain = meta_plain.write().map_err(|e| Error::Custom(format!("{:?}", e)))?;
|
||||||
let meta_crypto = Crypto::with_plain(&meta_plain, password, iterations);
|
let meta_crypto = Crypto::with_plain(&meta_plain, password, iterations)?;
|
||||||
|
|
||||||
Ok(json::VaultKeyFile {
|
Ok(json::VaultKeyFile {
|
||||||
id: self.id.into(),
|
id: self.id.into(),
|
||||||
@@ -125,36 +153,36 @@ impl SafeAccount {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Sign a message.
|
/// Sign a message.
|
||||||
pub fn sign(&self, password: &str, message: &Message) -> Result<Signature, Error> {
|
pub fn sign(&self, password: &Password, message: &Message) -> Result<Signature, Error> {
|
||||||
let secret = self.crypto.secret(password)?;
|
let secret = self.crypto.secret(password)?;
|
||||||
sign(&secret, message).map_err(From::from)
|
sign(&secret, message).map_err(From::from)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Decrypt a message.
|
/// Decrypt a message.
|
||||||
pub fn decrypt(&self, password: &str, shared_mac: &[u8], message: &[u8]) -> Result<Vec<u8>, Error> {
|
pub fn decrypt(&self, password: &Password, shared_mac: &[u8], message: &[u8]) -> Result<Vec<u8>, Error> {
|
||||||
let secret = self.crypto.secret(password)?;
|
let secret = self.crypto.secret(password)?;
|
||||||
crypto::ecies::decrypt(&secret, shared_mac, message).map_err(From::from)
|
ethkey::crypto::ecies::decrypt(&secret, shared_mac, message).map_err(From::from)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Agree on shared key.
|
/// Agree on shared key.
|
||||||
pub fn agree(&self, password: &str, other: &Public) -> Result<Secret, Error> {
|
pub fn agree(&self, password: &Password, other: &Public) -> Result<Secret, Error> {
|
||||||
let secret = self.crypto.secret(password)?;
|
let secret = self.crypto.secret(password)?;
|
||||||
agree(&secret, other).map_err(From::from)
|
agree(&secret, other).map_err(From::from)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Derive public key.
|
/// Derive public key.
|
||||||
pub fn public(&self, password: &str) -> Result<Public, Error> {
|
pub fn public(&self, password: &Password) -> Result<Public, Error> {
|
||||||
let secret = self.crypto.secret(password)?;
|
let secret = self.crypto.secret(password)?;
|
||||||
Ok(KeyPair::from_secret(secret)?.public().clone())
|
Ok(KeyPair::from_secret(secret)?.public().clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Change account's password.
|
/// Change account's password.
|
||||||
pub fn change_password(&self, old_password: &str, new_password: &str, iterations: u32) -> Result<Self, Error> {
|
pub fn change_password(&self, old_password: &Password, new_password: &Password, iterations: u32) -> Result<Self, Error> {
|
||||||
let secret = self.crypto.secret(old_password)?;
|
let secret = self.crypto.secret(old_password)?;
|
||||||
let result = SafeAccount {
|
let result = SafeAccount {
|
||||||
id: self.id.clone(),
|
id: self.id.clone(),
|
||||||
version: self.version.clone(),
|
version: self.version.clone(),
|
||||||
crypto: Crypto::with_secret(&secret, new_password, iterations),
|
crypto: Crypto::with_secret(&secret, new_password, iterations)?,
|
||||||
address: self.address.clone(),
|
address: self.address.clone(),
|
||||||
filename: self.filename.clone(),
|
filename: self.filename.clone(),
|
||||||
name: self.name.clone(),
|
name: self.name.clone(),
|
||||||
@@ -164,7 +192,7 @@ impl SafeAccount {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Check if password matches the account.
|
/// Check if password matches the account.
|
||||||
pub fn check_password(&self, password: &str) -> bool {
|
pub fn check_password(&self, password: &Password) -> bool {
|
||||||
self.crypto.secret(password).is_ok()
|
self.crypto.secret(password).is_ok()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -177,25 +205,25 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn sign_and_verify_public() {
|
fn sign_and_verify_public() {
|
||||||
let keypair = Random.generate().unwrap();
|
let keypair = Random.generate().unwrap();
|
||||||
let password = "hello world";
|
let password = "hello world".into();
|
||||||
let message = Message::default();
|
let message = Message::default();
|
||||||
let account = SafeAccount::create(&keypair, [0u8; 16], password, 10240, "Test".to_owned(), "{}".to_owned());
|
let account = SafeAccount::create(&keypair, [0u8; 16], &password, 10240, "Test".to_owned(), "{}".to_owned());
|
||||||
let signature = account.sign(password, &message).unwrap();
|
let signature = account.unwrap().sign(&password, &message).unwrap();
|
||||||
assert!(verify_public(keypair.public(), &signature, &message).unwrap());
|
assert!(verify_public(keypair.public(), &signature, &message).unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn change_password() {
|
fn change_password() {
|
||||||
let keypair = Random.generate().unwrap();
|
let keypair = Random.generate().unwrap();
|
||||||
let first_password = "hello world";
|
let first_password = "hello world".into();
|
||||||
let sec_password = "this is sparta";
|
let sec_password = "this is sparta".into();
|
||||||
let i = 10240;
|
let i = 10240;
|
||||||
let message = Message::default();
|
let message = Message::default();
|
||||||
let account = SafeAccount::create(&keypair, [0u8; 16], first_password, i, "Test".to_owned(), "{}".to_owned());
|
let account = SafeAccount::create(&keypair, [0u8; 16], &first_password, i, "Test".to_owned(), "{}".to_owned()).unwrap();
|
||||||
let new_account = account.change_password(first_password, sec_password, i).unwrap();
|
let new_account = account.change_password(&first_password, &sec_password, i).unwrap();
|
||||||
assert!(account.sign(first_password, &message).is_ok());
|
assert!(account.sign(&first_password, &message).is_ok());
|
||||||
assert!(account.sign(sec_password, &message).is_err());
|
assert!(account.sign(&sec_password, &message).is_err());
|
||||||
assert!(new_account.sign(first_password, &message).is_err());
|
assert!(new_account.sign(&first_password, &message).is_err());
|
||||||
assert!(new_account.sign(sec_password, &message).is_ok());
|
assert!(new_account.sign(&sec_password, &message).is_ok());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,18 +1,18 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
// Copyright 2015-2019 Parity Technologies (UK) Ltd.
|
||||||
// This file is part of Parity.
|
// This file is part of Parity Ethereum.
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
// Parity Ethereum is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
// Parity Ethereum is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use json;
|
use json;
|
||||||
|
|
||||||
@@ -1,18 +1,18 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
// Copyright 2015-2019 Parity Technologies (UK) Ltd.
|
||||||
// This file is part of Parity.
|
// This file is part of Parity Ethereum.
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
// Parity Ethereum is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
// Parity Ethereum is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use std::{fs, io};
|
use std::{fs, io};
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
@@ -23,6 +23,7 @@ use {json, SafeAccount, Error};
|
|||||||
use json::Uuid;
|
use json::Uuid;
|
||||||
use super::{KeyDirectory, VaultKeyDirectory, VaultKeyDirectoryProvider, VaultKey};
|
use super::{KeyDirectory, VaultKeyDirectory, VaultKeyDirectoryProvider, VaultKey};
|
||||||
use super::vault::{VAULT_FILE_NAME, VaultDiskDirectory};
|
use super::vault::{VAULT_FILE_NAME, VaultDiskDirectory};
|
||||||
|
use ethkey::Password;
|
||||||
|
|
||||||
const IGNORED_FILES: &'static [&'static str] = &[
|
const IGNORED_FILES: &'static [&'static str] = &[
|
||||||
"thumbs.db",
|
"thumbs.db",
|
||||||
@@ -33,22 +34,70 @@ const IGNORED_FILES: &'static [&'static str] = &[
|
|||||||
"vault.json",
|
"vault.json",
|
||||||
];
|
];
|
||||||
|
|
||||||
#[cfg(not(windows))]
|
/// Find a unique filename that does not exist using four-letter random suffix.
|
||||||
fn restrict_permissions_to_owner(file_path: &Path) -> Result<(), i32> {
|
pub fn find_unique_filename_using_random_suffix(parent_path: &Path, original_filename: &str) -> io::Result<String> {
|
||||||
use std::ffi;
|
let mut path = parent_path.join(original_filename);
|
||||||
use libc;
|
let mut deduped_filename = original_filename.to_string();
|
||||||
|
|
||||||
let cstr = ffi::CString::new(&*file_path.to_string_lossy())
|
if path.exists() {
|
||||||
.map_err(|_| -1)?;
|
const MAX_RETRIES: usize = 500;
|
||||||
match unsafe { libc::chmod(cstr.as_ptr(), libc::S_IWUSR | libc::S_IRUSR) } {
|
let mut retries = 0;
|
||||||
0 => Ok(()),
|
|
||||||
x => Err(x),
|
while path.exists() {
|
||||||
|
if retries >= MAX_RETRIES {
|
||||||
|
return Err(io::Error::new(io::ErrorKind::Other, "Exceeded maximum retries when deduplicating filename."));
|
||||||
|
}
|
||||||
|
|
||||||
|
let suffix = ::random::random_string(4);
|
||||||
|
deduped_filename = format!("{}-{}", original_filename, suffix);
|
||||||
|
path.set_file_name(&deduped_filename);
|
||||||
|
retries += 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ok(deduped_filename)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(windows)]
|
/// Create a new file and restrict permissions to owner only. It errors if the file already exists.
|
||||||
fn restrict_permissions_to_owner(_file_path: &Path) -> Result<(), i32> {
|
#[cfg(unix)]
|
||||||
Ok(())
|
pub fn create_new_file_with_permissions_to_owner(file_path: &Path) -> io::Result<fs::File> {
|
||||||
|
use libc;
|
||||||
|
use std::os::unix::fs::OpenOptionsExt;
|
||||||
|
|
||||||
|
fs::OpenOptions::new()
|
||||||
|
.write(true)
|
||||||
|
.create_new(true)
|
||||||
|
.mode((libc::S_IWUSR | libc::S_IRUSR) as u32)
|
||||||
|
.open(file_path)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a new file and restrict permissions to owner only. It errors if the file already exists.
|
||||||
|
#[cfg(not(unix))]
|
||||||
|
pub fn create_new_file_with_permissions_to_owner(file_path: &Path) -> io::Result<fs::File> {
|
||||||
|
fs::OpenOptions::new()
|
||||||
|
.write(true)
|
||||||
|
.create_new(true)
|
||||||
|
.open(file_path)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a new file and restrict permissions to owner only. It replaces the existing file if it already exists.
|
||||||
|
#[cfg(unix)]
|
||||||
|
pub fn replace_file_with_permissions_to_owner(file_path: &Path) -> io::Result<fs::File> {
|
||||||
|
use libc;
|
||||||
|
use std::os::unix::fs::PermissionsExt;
|
||||||
|
|
||||||
|
let file = fs::File::create(file_path)?;
|
||||||
|
let mut permissions = file.metadata()?.permissions();
|
||||||
|
permissions.set_mode((libc::S_IWUSR | libc::S_IRUSR) as u32);
|
||||||
|
file.set_permissions(permissions)?;
|
||||||
|
|
||||||
|
Ok(file)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a new file and restrict permissions to owner only. It replaces the existing file if it already exists.
|
||||||
|
#[cfg(not(unix))]
|
||||||
|
pub fn replace_file_with_permissions_to_owner(file_path: &Path) -> io::Result<fs::File> {
|
||||||
|
fs::File::create(file_path)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Root keys directory implementation
|
/// Root keys directory implementation
|
||||||
@@ -58,6 +107,7 @@ pub type RootDiskDirectory = DiskDirectory<DiskKeyFileManager>;
|
|||||||
pub trait KeyFileManager: Send + Sync {
|
pub trait KeyFileManager: Send + Sync {
|
||||||
/// Read `SafeAccount` from given key file stream
|
/// Read `SafeAccount` from given key file stream
|
||||||
fn read<T>(&self, filename: Option<String>, reader: T) -> Result<SafeAccount, Error> where T: io::Read;
|
fn read<T>(&self, filename: Option<String>, reader: T) -> Result<SafeAccount, Error> where T: io::Read;
|
||||||
|
|
||||||
/// Write `SafeAccount` to given key file stream
|
/// Write `SafeAccount` to given key file stream
|
||||||
fn write<T>(&self, account: SafeAccount, writer: &mut T) -> Result<(), Error> where T: io::Write;
|
fn write<T>(&self, account: SafeAccount, writer: &mut T) -> Result<(), Error> where T: io::Write;
|
||||||
}
|
}
|
||||||
@@ -69,7 +119,10 @@ pub struct DiskDirectory<T> where T: KeyFileManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Keys file manager for root keys directory
|
/// Keys file manager for root keys directory
|
||||||
pub struct DiskKeyFileManager;
|
#[derive(Default)]
|
||||||
|
pub struct DiskKeyFileManager {
|
||||||
|
password: Option<Password>,
|
||||||
|
}
|
||||||
|
|
||||||
impl RootDiskDirectory {
|
impl RootDiskDirectory {
|
||||||
pub fn create<P>(path: P) -> Result<Self, Error> where P: AsRef<Path> {
|
pub fn create<P>(path: P) -> Result<Self, Error> where P: AsRef<Path> {
|
||||||
@@ -77,8 +130,13 @@ impl RootDiskDirectory {
|
|||||||
Ok(Self::at(path))
|
Ok(Self::at(path))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// allows to read keyfiles with given password (needed for keyfiles w/o address)
|
||||||
|
pub fn with_password(&self, password: Option<Password>) -> Self {
|
||||||
|
DiskDirectory::new(&self.path, DiskKeyFileManager { password })
|
||||||
|
}
|
||||||
|
|
||||||
pub fn at<P>(path: P) -> Self where P: AsRef<Path> {
|
pub fn at<P>(path: P) -> Self where P: AsRef<Path> {
|
||||||
DiskDirectory::new(path, DiskKeyFileManager)
|
DiskDirectory::new(path, DiskKeyFileManager::default())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -153,20 +211,16 @@ impl<T> DiskDirectory<T> where T: KeyFileManager {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// insert account with given filename. if the filename is a duplicate of any stored account and dedup is set to
|
/// insert account with given filename. if the filename is a duplicate of any stored account and dedup is set to
|
||||||
/// true, a random suffix is appended to the filename.
|
/// true, a random suffix is appended to the filename.
|
||||||
pub fn insert_with_filename(&self, account: SafeAccount, mut filename: String, dedup: bool) -> Result<SafeAccount, Error> {
|
pub fn insert_with_filename(&self, account: SafeAccount, mut filename: String, dedup: bool) -> Result<SafeAccount, Error> {
|
||||||
// path to keyfile
|
if dedup {
|
||||||
let mut keyfile_path = self.path.join(filename.as_str());
|
filename = find_unique_filename_using_random_suffix(&self.path, &filename)?;
|
||||||
|
|
||||||
// check for duplicate filename and append random suffix
|
|
||||||
if dedup && keyfile_path.exists() {
|
|
||||||
let suffix = ::random::random_string(4);
|
|
||||||
filename.push_str(&format!("-{}", suffix));
|
|
||||||
keyfile_path.set_file_name(&filename);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// path to keyfile
|
||||||
|
let keyfile_path = self.path.join(filename.as_str());
|
||||||
|
|
||||||
// update account filename
|
// update account filename
|
||||||
let original_account = account.clone();
|
let original_account = account.clone();
|
||||||
let mut account = account;
|
let mut account = account;
|
||||||
@@ -174,17 +228,16 @@ impl<T> DiskDirectory<T> where T: KeyFileManager {
|
|||||||
|
|
||||||
{
|
{
|
||||||
// save the file
|
// save the file
|
||||||
let mut file = fs::File::create(&keyfile_path)?;
|
let mut file = if dedup {
|
||||||
|
create_new_file_with_permissions_to_owner(&keyfile_path)?
|
||||||
|
} else {
|
||||||
|
replace_file_with_permissions_to_owner(&keyfile_path)?
|
||||||
|
};
|
||||||
|
|
||||||
// write key content
|
// write key content
|
||||||
self.key_manager.write(original_account, &mut file).map_err(|e| Error::Custom(format!("{:?}", e)))?;
|
self.key_manager.write(original_account, &mut file).map_err(|e| Error::Custom(format!("{:?}", e)))?;
|
||||||
|
|
||||||
file.flush()?;
|
file.flush()?;
|
||||||
|
|
||||||
if let Err(_) = restrict_permissions_to_owner(keyfile_path.as_path()) {
|
|
||||||
return Err(Error::Io(io::Error::last_os_error()));
|
|
||||||
}
|
|
||||||
|
|
||||||
file.sync_all()?;
|
file.sync_all()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -276,7 +329,7 @@ impl<T> VaultKeyDirectoryProvider for DiskDirectory<T> where T: KeyFileManager {
|
|||||||
impl KeyFileManager for DiskKeyFileManager {
|
impl KeyFileManager for DiskKeyFileManager {
|
||||||
fn read<T>(&self, filename: Option<String>, reader: T) -> Result<SafeAccount, Error> where T: io::Read {
|
fn read<T>(&self, filename: Option<String>, reader: T) -> Result<SafeAccount, Error> where T: io::Read {
|
||||||
let key_file = json::KeyFile::load(reader).map_err(|e| Error::Custom(format!("{:?}", e)))?;
|
let key_file = json::KeyFile::load(reader).map_err(|e| Error::Custom(format!("{:?}", e)))?;
|
||||||
Ok(SafeAccount::from_file(key_file, filename))
|
SafeAccount::from_file(key_file, filename, &self.password)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write<T>(&self, mut account: SafeAccount, writer: &mut T) -> Result<(), Error> where T: io::Write {
|
fn write<T>(&self, mut account: SafeAccount, writer: &mut T) -> Result<(), Error> where T: io::Write {
|
||||||
@@ -314,12 +367,12 @@ mod test {
|
|||||||
let mut dir = env::temp_dir();
|
let mut dir = env::temp_dir();
|
||||||
dir.push("ethstore_should_create_new_account");
|
dir.push("ethstore_should_create_new_account");
|
||||||
let keypair = Random.generate().unwrap();
|
let keypair = Random.generate().unwrap();
|
||||||
let password = "hello world";
|
let password = "hello world".into();
|
||||||
let directory = RootDiskDirectory::create(dir.clone()).unwrap();
|
let directory = RootDiskDirectory::create(dir.clone()).unwrap();
|
||||||
|
|
||||||
// when
|
// when
|
||||||
let account = SafeAccount::create(&keypair, [0u8; 16], password, 1024, "Test".to_owned(), "{}".to_owned());
|
let account = SafeAccount::create(&keypair, [0u8; 16], &password, 1024, "Test".to_owned(), "{}".to_owned());
|
||||||
let res = directory.insert(account);
|
let res = directory.insert(account.unwrap());
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assert!(res.is_ok(), "Should save account succesfuly.");
|
assert!(res.is_ok(), "Should save account succesfuly.");
|
||||||
@@ -335,11 +388,11 @@ mod test {
|
|||||||
let mut dir = env::temp_dir();
|
let mut dir = env::temp_dir();
|
||||||
dir.push("ethstore_should_handle_duplicate_filenames");
|
dir.push("ethstore_should_handle_duplicate_filenames");
|
||||||
let keypair = Random.generate().unwrap();
|
let keypair = Random.generate().unwrap();
|
||||||
let password = "hello world";
|
let password = "hello world".into();
|
||||||
let directory = RootDiskDirectory::create(dir.clone()).unwrap();
|
let directory = RootDiskDirectory::create(dir.clone()).unwrap();
|
||||||
|
|
||||||
// when
|
// when
|
||||||
let account = SafeAccount::create(&keypair, [0u8; 16], password, 1024, "Test".to_owned(), "{}".to_owned());
|
let account = SafeAccount::create(&keypair, [0u8; 16], &password, 1024, "Test".to_owned(), "{}".to_owned()).unwrap();
|
||||||
let filename = "test".to_string();
|
let filename = "test".to_string();
|
||||||
let dedup = true;
|
let dedup = true;
|
||||||
|
|
||||||
@@ -368,14 +421,14 @@ mod test {
|
|||||||
dir.push("should_create_new_vault");
|
dir.push("should_create_new_vault");
|
||||||
let directory = RootDiskDirectory::create(dir.clone()).unwrap();
|
let directory = RootDiskDirectory::create(dir.clone()).unwrap();
|
||||||
let vault_name = "vault";
|
let vault_name = "vault";
|
||||||
let password = "password";
|
let password = "password".into();
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assert!(directory.as_vault_provider().is_some());
|
assert!(directory.as_vault_provider().is_some());
|
||||||
|
|
||||||
// and when
|
// and when
|
||||||
let before_root_items_count = fs::read_dir(&dir).unwrap().count();
|
let before_root_items_count = fs::read_dir(&dir).unwrap().count();
|
||||||
let vault = directory.as_vault_provider().unwrap().create(vault_name, VaultKey::new(password, 1024));
|
let vault = directory.as_vault_provider().unwrap().create(vault_name, VaultKey::new(&password, 1024));
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assert!(vault.is_ok());
|
assert!(vault.is_ok());
|
||||||
@@ -383,7 +436,7 @@ mod test {
|
|||||||
assert!(after_root_items_count > before_root_items_count);
|
assert!(after_root_items_count > before_root_items_count);
|
||||||
|
|
||||||
// and when
|
// and when
|
||||||
let vault = directory.as_vault_provider().unwrap().open(vault_name, VaultKey::new(password, 1024));
|
let vault = directory.as_vault_provider().unwrap().open(vault_name, VaultKey::new(&password, 1024));
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assert!(vault.is_ok());
|
assert!(vault.is_ok());
|
||||||
@@ -400,8 +453,8 @@ mod test {
|
|||||||
let temp_path = TempDir::new("").unwrap();
|
let temp_path = TempDir::new("").unwrap();
|
||||||
let directory = RootDiskDirectory::create(&temp_path).unwrap();
|
let directory = RootDiskDirectory::create(&temp_path).unwrap();
|
||||||
let vault_provider = directory.as_vault_provider().unwrap();
|
let vault_provider = directory.as_vault_provider().unwrap();
|
||||||
vault_provider.create("vault1", VaultKey::new("password1", 1)).unwrap();
|
vault_provider.create("vault1", VaultKey::new(&"password1".into(), 1)).unwrap();
|
||||||
vault_provider.create("vault2", VaultKey::new("password2", 1)).unwrap();
|
vault_provider.create("vault2", VaultKey::new(&"password2".into(), 1)).unwrap();
|
||||||
|
|
||||||
// then
|
// then
|
||||||
let vaults = vault_provider.list_vaults().unwrap();
|
let vaults = vault_provider.list_vaults().unwrap();
|
||||||
@@ -422,9 +475,9 @@ mod test {
|
|||||||
);
|
);
|
||||||
|
|
||||||
let keypair = Random.generate().unwrap();
|
let keypair = Random.generate().unwrap();
|
||||||
let password = "test pass";
|
let password = "test pass".into();
|
||||||
let account = SafeAccount::create(&keypair, [0u8; 16], password, 1024, "Test".to_owned(), "{}".to_owned());
|
let account = SafeAccount::create(&keypair, [0u8; 16], &password, 1024, "Test".to_owned(), "{}".to_owned());
|
||||||
directory.insert(account).expect("Account should be inserted ok");
|
directory.insert(account.unwrap()).expect("Account should be inserted ok");
|
||||||
|
|
||||||
let new_hash = directory.files_hash().expect("New files hash should be calculated ok");
|
let new_hash = directory.files_hash().expect("New files hash should be calculated ok");
|
||||||
|
|
||||||
@@ -1,22 +1,22 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
// Copyright 2015-2019 Parity Technologies (UK) Ltd.
|
||||||
// This file is part of Parity.
|
// This file is part of Parity Ethereum.
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
// Parity Ethereum is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
// Parity Ethereum is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use parking_lot::RwLock;
|
use parking_lot::RwLock;
|
||||||
use itertools::Itertools;
|
use itertools;
|
||||||
use ethkey::Address;
|
use ethkey::Address;
|
||||||
|
|
||||||
use {SafeAccount, Error};
|
use {SafeAccount, Error};
|
||||||
@@ -30,7 +30,7 @@ pub struct MemoryDirectory {
|
|||||||
|
|
||||||
impl KeyDirectory for MemoryDirectory {
|
impl KeyDirectory for MemoryDirectory {
|
||||||
fn load(&self) -> Result<Vec<SafeAccount>, Error> {
|
fn load(&self) -> Result<Vec<SafeAccount>, Error> {
|
||||||
Ok(self.accounts.read().values().cloned().flatten().collect())
|
Ok(itertools::Itertools::flatten(self.accounts.read().values().cloned()).collect())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(&self, account: SafeAccount) -> Result<SafeAccount, Error> {
|
fn update(&self, account: SafeAccount) -> Result<SafeAccount, Error> {
|
||||||
@@ -72,4 +72,3 @@ impl KeyDirectory for MemoryDirectory {
|
|||||||
Ok(val)
|
Ok(val)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1,21 +1,22 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
// Copyright 2015-2019 Parity Technologies (UK) Ltd.
|
||||||
// This file is part of Parity.
|
// This file is part of Parity Ethereum.
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
// Parity Ethereum is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
// Parity Ethereum is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
//! Accounts Directory
|
//! Accounts Directory
|
||||||
|
|
||||||
|
use ethkey::Password;
|
||||||
use std::path::{PathBuf};
|
use std::path::{PathBuf};
|
||||||
use {SafeAccount, Error};
|
use {SafeAccount, Error};
|
||||||
|
|
||||||
@@ -35,10 +36,10 @@ pub enum SetKeyError {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Vault key
|
/// Vault key
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Clone, PartialEq, Eq)]
|
||||||
pub struct VaultKey {
|
pub struct VaultKey {
|
||||||
/// Vault password
|
/// Vault password
|
||||||
pub password: String,
|
pub password: Password,
|
||||||
/// Number of iterations to produce a derived key from password
|
/// Number of iterations to produce a derived key from password
|
||||||
pub iterations: u32,
|
pub iterations: u32,
|
||||||
}
|
}
|
||||||
@@ -95,9 +96,9 @@ pub use self::vault::VaultDiskDirectory;
|
|||||||
|
|
||||||
impl VaultKey {
|
impl VaultKey {
|
||||||
/// Create new vault key
|
/// Create new vault key
|
||||||
pub fn new(password: &str, iterations: u32) -> Self {
|
pub fn new(password: &Password, iterations: u32) -> Self {
|
||||||
VaultKey {
|
VaultKey {
|
||||||
password: password.to_owned(),
|
password: password.clone(),
|
||||||
iterations: iterations,
|
iterations: iterations,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,18 +1,18 @@
|
|||||||
// Copyright 2015, 2016, 2017 Parity Technologies (UK) Ltd.
|
// Copyright 2015-2019 Parity Technologies (UK) Ltd.
|
||||||
// This file is part of Parity.
|
// This file is part of Parity Ethereum.
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
// Parity Ethereum is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
// Parity Ethereum is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use std::{fs, io};
|
use std::{fs, io};
|
||||||
use std::path::{PathBuf, Path};
|
use std::path::{PathBuf, Path};
|
||||||
@@ -21,7 +21,7 @@ use {json, SafeAccount, Error};
|
|||||||
use crypto::Keccak256;
|
use crypto::Keccak256;
|
||||||
use super::super::account::Crypto;
|
use super::super::account::Crypto;
|
||||||
use super::{KeyDirectory, VaultKeyDirectory, VaultKey, SetKeyError};
|
use super::{KeyDirectory, VaultKeyDirectory, VaultKey, SetKeyError};
|
||||||
use super::disk::{DiskDirectory, KeyFileManager};
|
use super::disk::{self, DiskDirectory, KeyFileManager};
|
||||||
|
|
||||||
/// Name of vault metadata file
|
/// Name of vault metadata file
|
||||||
pub const VAULT_FILE_NAME: &'static str = "vault.json";
|
pub const VAULT_FILE_NAME: &'static str = "vault.json";
|
||||||
@@ -234,17 +234,16 @@ fn check_vault_name(name: &str) -> bool {
|
|||||||
|
|
||||||
/// Vault can be empty, but still must be pluggable => we store vault password in separate file
|
/// Vault can be empty, but still must be pluggable => we store vault password in separate file
|
||||||
fn create_vault_file<P>(vault_dir_path: P, key: &VaultKey, meta: &str) -> Result<(), Error> where P: AsRef<Path> {
|
fn create_vault_file<P>(vault_dir_path: P, key: &VaultKey, meta: &str) -> Result<(), Error> where P: AsRef<Path> {
|
||||||
let password_hash = key.password.keccak256();
|
let password_hash = key.password.as_bytes().keccak256();
|
||||||
let crypto = Crypto::with_plain(&password_hash, &key.password, key.iterations);
|
let crypto = Crypto::with_plain(&password_hash, &key.password, key.iterations)?;
|
||||||
|
|
||||||
let mut vault_file_path: PathBuf = vault_dir_path.as_ref().into();
|
let vault_file_path = vault_dir_path.as_ref().join(VAULT_FILE_NAME);
|
||||||
vault_file_path.push(VAULT_FILE_NAME);
|
let temp_vault_file_name = disk::find_unique_filename_using_random_suffix(vault_dir_path.as_ref(), &VAULT_TEMP_FILE_NAME)?;
|
||||||
let mut temp_vault_file_path: PathBuf = vault_dir_path.as_ref().into();
|
let temp_vault_file_path = vault_dir_path.as_ref().join(&temp_vault_file_name);
|
||||||
temp_vault_file_path.push(VAULT_TEMP_FILE_NAME);
|
|
||||||
|
|
||||||
// this method is used to rewrite existing vault file
|
// this method is used to rewrite existing vault file
|
||||||
// => write to temporary file first, then rename temporary file to vault file
|
// => write to temporary file first, then rename temporary file to vault file
|
||||||
let mut vault_file = fs::File::create(&temp_vault_file_path)?;
|
let mut vault_file = disk::create_new_file_with_permissions_to_owner(&temp_vault_file_path)?;
|
||||||
let vault_file_contents = json::VaultFile {
|
let vault_file_contents = json::VaultFile {
|
||||||
crypto: crypto.into(),
|
crypto: crypto.into(),
|
||||||
meta: Some(meta.to_owned()),
|
meta: Some(meta.to_owned()),
|
||||||
@@ -268,7 +267,7 @@ fn read_vault_file<P>(vault_dir_path: P, key: Option<&VaultKey>) -> Result<Strin
|
|||||||
|
|
||||||
if let Some(key) = key {
|
if let Some(key) = key {
|
||||||
let password_bytes = vault_file_crypto.decrypt(&key.password)?;
|
let password_bytes = vault_file_crypto.decrypt(&key.password)?;
|
||||||
let password_hash = key.password.keccak256();
|
let password_hash = key.password.as_bytes().keccak256();
|
||||||
if password_hash != password_bytes.as_slice() {
|
if password_hash != password_bytes.as_slice() {
|
||||||
return Err(Error::InvalidPassword);
|
return Err(Error::InvalidPassword);
|
||||||
}
|
}
|
||||||
@@ -311,8 +310,10 @@ mod test {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn make_vault_dir_path_succeeds() {
|
fn make_vault_dir_path_succeeds() {
|
||||||
assert_eq!(make_vault_dir_path("/home/user/parity", "vault", true).unwrap().to_str().unwrap(), "/home/user/parity/vault");
|
use std::path::Path;
|
||||||
assert_eq!(make_vault_dir_path("/home/user/parity", "*bad-name*", false).unwrap().to_str().unwrap(), "/home/user/parity/*bad-name*");
|
|
||||||
|
assert_eq!(&make_vault_dir_path("/home/user/parity", "vault", true).unwrap(), &Path::new("/home/user/parity/vault"));
|
||||||
|
assert_eq!(&make_vault_dir_path("/home/user/parity", "*bad-name*", false).unwrap(), &Path::new("/home/user/parity/*bad-name*"));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -324,7 +325,7 @@ mod test {
|
|||||||
fn create_vault_file_succeeds() {
|
fn create_vault_file_succeeds() {
|
||||||
// given
|
// given
|
||||||
let temp_path = TempDir::new("").unwrap();
|
let temp_path = TempDir::new("").unwrap();
|
||||||
let key = VaultKey::new("password", 1024);
|
let key = VaultKey::new(&"password".into(), 1024);
|
||||||
let mut vault_dir: PathBuf = temp_path.path().into();
|
let mut vault_dir: PathBuf = temp_path.path().into();
|
||||||
vault_dir.push("vault");
|
vault_dir.push("vault");
|
||||||
fs::create_dir_all(&vault_dir).unwrap();
|
fs::create_dir_all(&vault_dir).unwrap();
|
||||||
@@ -343,7 +344,7 @@ mod test {
|
|||||||
fn read_vault_file_succeeds() {
|
fn read_vault_file_succeeds() {
|
||||||
// given
|
// given
|
||||||
let temp_path = TempDir::new("").unwrap();
|
let temp_path = TempDir::new("").unwrap();
|
||||||
let key = VaultKey::new("password", 1024);
|
let key = VaultKey::new(&"password".into(), 1024);
|
||||||
let vault_file_contents = r#"{"crypto":{"cipher":"aes-128-ctr","cipherparams":{"iv":"758696c8dc6378ab9b25bb42790da2f5"},"ciphertext":"54eb50683717d41caaeb12ea969f2c159daada5907383f26f327606a37dc7168","kdf":"pbkdf2","kdfparams":{"c":1024,"dklen":32,"prf":"hmac-sha256","salt":"3c320fa566a1a7963ac8df68a19548d27c8f40bf92ef87c84594dcd5bbc402b6"},"mac":"9e5c2314c2a0781962db85611417c614bd6756666b6b1e93840f5b6ed895f003"}}"#;
|
let vault_file_contents = r#"{"crypto":{"cipher":"aes-128-ctr","cipherparams":{"iv":"758696c8dc6378ab9b25bb42790da2f5"},"ciphertext":"54eb50683717d41caaeb12ea969f2c159daada5907383f26f327606a37dc7168","kdf":"pbkdf2","kdfparams":{"c":1024,"dklen":32,"prf":"hmac-sha256","salt":"3c320fa566a1a7963ac8df68a19548d27c8f40bf92ef87c84594dcd5bbc402b6"},"mac":"9e5c2314c2a0781962db85611417c614bd6756666b6b1e93840f5b6ed895f003"}}"#;
|
||||||
let dir: PathBuf = temp_path.path().into();
|
let dir: PathBuf = temp_path.path().into();
|
||||||
let mut vault_file_path: PathBuf = dir.clone();
|
let mut vault_file_path: PathBuf = dir.clone();
|
||||||
@@ -364,7 +365,7 @@ mod test {
|
|||||||
fn read_vault_file_fails() {
|
fn read_vault_file_fails() {
|
||||||
// given
|
// given
|
||||||
let temp_path = TempDir::new("").unwrap();
|
let temp_path = TempDir::new("").unwrap();
|
||||||
let key = VaultKey::new("password1", 1024);
|
let key = VaultKey::new(&"password1".into(), 1024);
|
||||||
let dir: PathBuf = temp_path.path().into();
|
let dir: PathBuf = temp_path.path().into();
|
||||||
let mut vault_file_path: PathBuf = dir.clone();
|
let mut vault_file_path: PathBuf = dir.clone();
|
||||||
vault_file_path.push(VAULT_FILE_NAME);
|
vault_file_path.push(VAULT_FILE_NAME);
|
||||||
@@ -393,7 +394,7 @@ mod test {
|
|||||||
fn vault_directory_can_be_created() {
|
fn vault_directory_can_be_created() {
|
||||||
// given
|
// given
|
||||||
let temp_path = TempDir::new("").unwrap();
|
let temp_path = TempDir::new("").unwrap();
|
||||||
let key = VaultKey::new("password", 1024);
|
let key = VaultKey::new(&"password".into(), 1024);
|
||||||
let dir: PathBuf = temp_path.path().into();
|
let dir: PathBuf = temp_path.path().into();
|
||||||
|
|
||||||
// when
|
// when
|
||||||
@@ -413,7 +414,7 @@ mod test {
|
|||||||
fn vault_directory_cannot_be_created_if_already_exists() {
|
fn vault_directory_cannot_be_created_if_already_exists() {
|
||||||
// given
|
// given
|
||||||
let temp_path = TempDir::new("").unwrap();
|
let temp_path = TempDir::new("").unwrap();
|
||||||
let key = VaultKey::new("password", 1024);
|
let key = VaultKey::new(&"password".into(), 1024);
|
||||||
let dir: PathBuf = temp_path.path().into();
|
let dir: PathBuf = temp_path.path().into();
|
||||||
let mut vault_dir = dir.clone();
|
let mut vault_dir = dir.clone();
|
||||||
vault_dir.push("vault");
|
vault_dir.push("vault");
|
||||||
@@ -430,7 +431,7 @@ mod test {
|
|||||||
fn vault_directory_cannot_be_opened_if_not_exists() {
|
fn vault_directory_cannot_be_opened_if_not_exists() {
|
||||||
// given
|
// given
|
||||||
let temp_path = TempDir::new("").unwrap();
|
let temp_path = TempDir::new("").unwrap();
|
||||||
let key = VaultKey::new("password", 1024);
|
let key = VaultKey::new(&"password".into(), 1024);
|
||||||
let dir: PathBuf = temp_path.path().into();
|
let dir: PathBuf = temp_path.path().into();
|
||||||
|
|
||||||
// when
|
// when
|
||||||
@@ -1,23 +1,23 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
// Copyright 2015-2019 Parity Technologies (UK) Ltd.
|
||||||
// This file is part of Parity.
|
// This file is part of Parity Ethereum.
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
// Parity Ethereum is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
// Parity Ethereum is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::io::Error as IoError;
|
use std::io::Error as IoError;
|
||||||
use ethkey::Error as EthKeyError;
|
use ethkey::{self, Error as EthKeyError};
|
||||||
use crypto::Error as EthCryptoError;
|
use crypto::{self, Error as EthCryptoError};
|
||||||
use ethkey::DerivationError;
|
use ethkey::DerivationError;
|
||||||
|
|
||||||
/// Account-related errors.
|
/// Account-related errors.
|
||||||
@@ -49,6 +49,8 @@ pub enum Error {
|
|||||||
CreationFailed,
|
CreationFailed,
|
||||||
/// `EthKey` error
|
/// `EthKey` error
|
||||||
EthKey(EthKeyError),
|
EthKey(EthKeyError),
|
||||||
|
/// `ethkey::crypto::Error`
|
||||||
|
EthKeyCrypto(ethkey::crypto::Error),
|
||||||
/// `EthCrypto` error
|
/// `EthCrypto` error
|
||||||
EthCrypto(EthCryptoError),
|
EthCrypto(EthCryptoError),
|
||||||
/// Derivation error
|
/// Derivation error
|
||||||
@@ -73,6 +75,7 @@ impl fmt::Display for Error {
|
|||||||
Error::VaultNotFound => "Vault not found".into(),
|
Error::VaultNotFound => "Vault not found".into(),
|
||||||
Error::CreationFailed => "Account creation failed".into(),
|
Error::CreationFailed => "Account creation failed".into(),
|
||||||
Error::EthKey(ref err) => err.to_string(),
|
Error::EthKey(ref err) => err.to_string(),
|
||||||
|
Error::EthKeyCrypto(ref err) => err.to_string(),
|
||||||
Error::EthCrypto(ref err) => err.to_string(),
|
Error::EthCrypto(ref err) => err.to_string(),
|
||||||
Error::Derivation(ref err) => format!("Derivation error: {:?}", err),
|
Error::Derivation(ref err) => format!("Derivation error: {:?}", err),
|
||||||
Error::Custom(ref s) => s.clone(),
|
Error::Custom(ref s) => s.clone(),
|
||||||
@@ -94,12 +97,30 @@ impl From<EthKeyError> for Error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<ethkey::crypto::Error> for Error {
|
||||||
|
fn from(err: ethkey::crypto::Error) -> Self {
|
||||||
|
Error::EthKeyCrypto(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl From<EthCryptoError> for Error {
|
impl From<EthCryptoError> for Error {
|
||||||
fn from(err: EthCryptoError) -> Self {
|
fn from(err: EthCryptoError) -> Self {
|
||||||
Error::EthCrypto(err)
|
Error::EthCrypto(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<crypto::error::ScryptError> for Error {
|
||||||
|
fn from(err: crypto::error::ScryptError) -> Self {
|
||||||
|
Error::EthCrypto(err.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<crypto::error::SymmError> for Error {
|
||||||
|
fn from(err: crypto::error::SymmError) -> Self {
|
||||||
|
Error::EthCrypto(err.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl From<DerivationError> for Error {
|
impl From<DerivationError> for Error {
|
||||||
fn from(err: DerivationError) -> Self {
|
fn from(err: DerivationError) -> Self {
|
||||||
Error::Derivation(err)
|
Error::Derivation(err)
|
||||||
@@ -1,18 +1,18 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
// Copyright 2015-2019 Parity Technologies (UK) Ltd.
|
||||||
// This file is part of Parity.
|
// This file is part of Parity Ethereum.
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
// Parity Ethereum is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
// Parity Ethereum is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
//! ethkey reexport to make documentation look pretty.
|
//! ethkey reexport to make documentation look pretty.
|
||||||
pub use _ethkey::*;
|
pub use _ethkey::*;
|
||||||
@@ -1,18 +1,18 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
// Copyright 2015-2019 Parity Technologies (UK) Ltd.
|
||||||
// This file is part of Parity.
|
// This file is part of Parity Ethereum.
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
// Parity Ethereum is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
// Parity Ethereum is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use std::collections::{BTreeMap, HashMap};
|
use std::collections::{BTreeMap, HashMap};
|
||||||
use std::mem;
|
use std::mem;
|
||||||
@@ -22,7 +22,7 @@ use std::time::{Instant, Duration};
|
|||||||
|
|
||||||
use crypto::KEY_ITERATIONS;
|
use crypto::KEY_ITERATIONS;
|
||||||
use random::Random;
|
use random::Random;
|
||||||
use ethkey::{self, Signature, Address, Message, Secret, Public, KeyPair, ExtendedKeyPair};
|
use ethkey::{self, Signature, Password, Address, Message, Secret, Public, KeyPair, ExtendedKeyPair};
|
||||||
use accounts_dir::{KeyDirectory, VaultKeyDirectory, VaultKey, SetKeyError};
|
use accounts_dir::{KeyDirectory, VaultKeyDirectory, VaultKey, SetKeyError};
|
||||||
use account::SafeAccount;
|
use account::SafeAccount;
|
||||||
use presale::PresaleWallet;
|
use presale::PresaleWallet;
|
||||||
@@ -64,17 +64,17 @@ impl EthStore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl SimpleSecretStore for EthStore {
|
impl SimpleSecretStore for EthStore {
|
||||||
fn insert_account(&self, vault: SecretVaultRef, secret: Secret, password: &str) -> Result<StoreAccountRef, Error> {
|
fn insert_account(&self, vault: SecretVaultRef, secret: Secret, password: &Password) -> Result<StoreAccountRef, Error> {
|
||||||
self.store.insert_account(vault, secret, password)
|
self.store.insert_account(vault, secret, password)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn insert_derived(&self, vault: SecretVaultRef, account_ref: &StoreAccountRef, password: &str, derivation: Derivation)
|
fn insert_derived(&self, vault: SecretVaultRef, account_ref: &StoreAccountRef, password: &Password, derivation: Derivation)
|
||||||
-> Result<StoreAccountRef, Error>
|
-> Result<StoreAccountRef, Error>
|
||||||
{
|
{
|
||||||
self.store.insert_derived(vault, account_ref, password, derivation)
|
self.store.insert_derived(vault, account_ref, password, derivation)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generate_derived(&self, account_ref: &StoreAccountRef, password: &str, derivation: Derivation) -> Result<Address, Error> {
|
fn generate_derived(&self, account_ref: &StoreAccountRef, password: &Password, derivation: Derivation) -> Result<Address, Error> {
|
||||||
self.store.generate_derived(account_ref, password, derivation)
|
self.store.generate_derived(account_ref, password, derivation)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,42 +86,42 @@ impl SimpleSecretStore for EthStore {
|
|||||||
self.store.accounts()
|
self.store.accounts()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn change_password(&self, account: &StoreAccountRef, old_password: &str, new_password: &str) -> Result<(), Error> {
|
fn change_password(&self, account: &StoreAccountRef, old_password: &Password, new_password: &Password) -> Result<(), Error> {
|
||||||
self.store.change_password(account, old_password, new_password)
|
self.store.change_password(account, old_password, new_password)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn export_account(&self, account: &StoreAccountRef, password: &str) -> Result<OpaqueKeyFile, Error> {
|
fn export_account(&self, account: &StoreAccountRef, password: &Password) -> Result<OpaqueKeyFile, Error> {
|
||||||
self.store.export_account(account, password)
|
self.store.export_account(account, password)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remove_account(&self, account: &StoreAccountRef, password: &str) -> Result<(), Error> {
|
fn remove_account(&self, account: &StoreAccountRef, password: &Password) -> Result<(), Error> {
|
||||||
self.store.remove_account(account, password)
|
self.store.remove_account(account, password)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sign(&self, account: &StoreAccountRef, password: &str, message: &Message) -> Result<Signature, Error> {
|
fn sign(&self, account: &StoreAccountRef, password: &Password, message: &Message) -> Result<Signature, Error> {
|
||||||
self.get(account)?.sign(password, message)
|
self.get(account)?.sign(password, message)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sign_derived(&self, account_ref: &StoreAccountRef, password: &str, derivation: Derivation, message: &Message)
|
fn sign_derived(&self, account_ref: &StoreAccountRef, password: &Password, derivation: Derivation, message: &Message)
|
||||||
-> Result<Signature, Error>
|
-> Result<Signature, Error>
|
||||||
{
|
{
|
||||||
self.store.sign_derived(account_ref, password, derivation, message)
|
self.store.sign_derived(account_ref, password, derivation, message)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn agree(&self, account: &StoreAccountRef, password: &str, other: &Public) -> Result<Secret, Error> {
|
fn agree(&self, account: &StoreAccountRef, password: &Password, other: &Public) -> Result<Secret, Error> {
|
||||||
self.store.agree(account, password, other)
|
self.store.agree(account, password, other)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn decrypt(&self, account: &StoreAccountRef, password: &str, shared_mac: &[u8], message: &[u8]) -> Result<Vec<u8>, Error> {
|
fn decrypt(&self, account: &StoreAccountRef, password: &Password, shared_mac: &[u8], message: &[u8]) -> Result<Vec<u8>, Error> {
|
||||||
let account = self.get(account)?;
|
let account = self.get(account)?;
|
||||||
account.decrypt(password, shared_mac, message)
|
account.decrypt(password, shared_mac, message)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_vault(&self, name: &str, password: &str) -> Result<(), Error> {
|
fn create_vault(&self, name: &str, password: &Password) -> Result<(), Error> {
|
||||||
self.store.create_vault(name, password)
|
self.store.create_vault(name, password)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn open_vault(&self, name: &str, password: &str) -> Result<(), Error> {
|
fn open_vault(&self, name: &str, password: &Password) -> Result<(), Error> {
|
||||||
self.store.open_vault(name, password)
|
self.store.open_vault(name, password)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -137,7 +137,7 @@ impl SimpleSecretStore for EthStore {
|
|||||||
self.store.list_opened_vaults()
|
self.store.list_opened_vaults()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn change_vault_password(&self, name: &str, new_password: &str) -> Result<(), Error> {
|
fn change_vault_password(&self, name: &str, new_password: &Password) -> Result<(), Error> {
|
||||||
self.store.change_vault_password(name, new_password)
|
self.store.change_vault_password(name, new_password)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -155,20 +155,20 @@ impl SimpleSecretStore for EthStore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl SecretStore for EthStore {
|
impl SecretStore for EthStore {
|
||||||
fn raw_secret(&self, account: &StoreAccountRef, password: &str) -> Result<OpaqueSecret, Error> {
|
fn raw_secret(&self, account: &StoreAccountRef, password: &Password) -> Result<OpaqueSecret, Error> {
|
||||||
Ok(OpaqueSecret(self.get(account)?.crypto.secret(password)?))
|
Ok(OpaqueSecret(self.get(account)?.crypto.secret(password)?))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn import_presale(&self, vault: SecretVaultRef, json: &[u8], password: &str) -> Result<StoreAccountRef, Error> {
|
fn import_presale(&self, vault: SecretVaultRef, json: &[u8], password: &Password) -> Result<StoreAccountRef, Error> {
|
||||||
let json_wallet = json::PresaleWallet::load(json).map_err(|_| Error::InvalidKeyFile("Invalid JSON format".to_owned()))?;
|
let json_wallet = json::PresaleWallet::load(json).map_err(|_| Error::InvalidKeyFile("Invalid JSON format".to_owned()))?;
|
||||||
let wallet = PresaleWallet::from(json_wallet);
|
let wallet = PresaleWallet::from(json_wallet);
|
||||||
let keypair = wallet.decrypt(password).map_err(|_| Error::InvalidPassword)?;
|
let keypair = wallet.decrypt(password).map_err(|_| Error::InvalidPassword)?;
|
||||||
self.insert_account(vault, keypair.secret().clone(), password)
|
self.insert_account(vault, keypair.secret().clone(), password)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn import_wallet(&self, vault: SecretVaultRef, json: &[u8], password: &str, gen_id: bool) -> Result<StoreAccountRef, Error> {
|
fn import_wallet(&self, vault: SecretVaultRef, json: &[u8], password: &Password, gen_id: bool) -> Result<StoreAccountRef, Error> {
|
||||||
let json_keyfile = json::KeyFile::load(json).map_err(|_| Error::InvalidKeyFile("Invalid JSON format".to_owned()))?;
|
let json_keyfile = json::KeyFile::load(json).map_err(|_| Error::InvalidKeyFile("Invalid JSON format".to_owned()))?;
|
||||||
let mut safe_account = SafeAccount::from_file(json_keyfile, None);
|
let mut safe_account = SafeAccount::from_file(json_keyfile, None, &None)?;
|
||||||
|
|
||||||
if gen_id {
|
if gen_id {
|
||||||
safe_account.id = Random::random();
|
safe_account.id = Random::random();
|
||||||
@@ -179,19 +179,19 @@ impl SecretStore for EthStore {
|
|||||||
self.store.import(vault, safe_account)
|
self.store.import(vault, safe_account)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_password(&self, account: &StoreAccountRef, password: &str) -> Result<bool, Error> {
|
fn test_password(&self, account: &StoreAccountRef, password: &Password) -> Result<bool, Error> {
|
||||||
let account = self.get(account)?;
|
let account = self.get(account)?;
|
||||||
Ok(account.check_password(password))
|
Ok(account.check_password(password))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn copy_account(&self, new_store: &SimpleSecretStore, new_vault: SecretVaultRef, account: &StoreAccountRef, password: &str, new_password: &str) -> Result<(), Error> {
|
fn copy_account(&self, new_store: &SimpleSecretStore, new_vault: SecretVaultRef, account: &StoreAccountRef, password: &Password, new_password: &Password) -> Result<(), Error> {
|
||||||
let account = self.get(account)?;
|
let account = self.get(account)?;
|
||||||
let secret = account.crypto.secret(password)?;
|
let secret = account.crypto.secret(password)?;
|
||||||
new_store.insert_account(new_vault, secret, new_password)?;
|
new_store.insert_account(new_vault, secret, new_password)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn public(&self, account: &StoreAccountRef, password: &str) -> Result<Public, Error> {
|
fn public(&self, account: &StoreAccountRef, password: &Password) -> Result<Public, Error> {
|
||||||
let account = self.get(account)?;
|
let account = self.get(account)?;
|
||||||
account.public(password)
|
account.public(password)
|
||||||
}
|
}
|
||||||
@@ -365,7 +365,7 @@ impl EthMultiStore {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_matching(&self, account: &StoreAccountRef, password: &str) -> Result<Vec<SafeAccount>, Error> {
|
fn get_matching(&self, account: &StoreAccountRef, password: &Password) -> Result<Vec<SafeAccount>, Error> {
|
||||||
let accounts = self.get_accounts(account)?;
|
let accounts = self.get_accounts(account)?;
|
||||||
|
|
||||||
Ok(accounts.into_iter()
|
Ok(accounts.into_iter()
|
||||||
@@ -455,14 +455,14 @@ impl EthMultiStore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl SimpleSecretStore for EthMultiStore {
|
impl SimpleSecretStore for EthMultiStore {
|
||||||
fn insert_account(&self, vault: SecretVaultRef, secret: Secret, password: &str) -> Result<StoreAccountRef, Error> {
|
fn insert_account(&self, vault: SecretVaultRef, secret: Secret, password: &Password) -> Result<StoreAccountRef, Error> {
|
||||||
let keypair = KeyPair::from_secret(secret).map_err(|_| Error::CreationFailed)?;
|
let keypair = KeyPair::from_secret(secret).map_err(|_| Error::CreationFailed)?;
|
||||||
let id: [u8; 16] = Random::random();
|
let id: [u8; 16] = Random::random();
|
||||||
let account = SafeAccount::create(&keypair, id, password, self.iterations, "".to_owned(), "{}".to_owned());
|
let account = SafeAccount::create(&keypair, id, password, self.iterations, "".to_owned(), "{}".to_owned())?;
|
||||||
self.import(vault, account)
|
self.import(vault, account)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn insert_derived(&self, vault: SecretVaultRef, account_ref: &StoreAccountRef, password: &str, derivation: Derivation)
|
fn insert_derived(&self, vault: SecretVaultRef, account_ref: &StoreAccountRef, password: &Password, derivation: Derivation)
|
||||||
-> Result<StoreAccountRef, Error>
|
-> Result<StoreAccountRef, Error>
|
||||||
{
|
{
|
||||||
let accounts = self.get_matching(account_ref, password)?;
|
let accounts = self.get_matching(account_ref, password)?;
|
||||||
@@ -473,7 +473,7 @@ impl SimpleSecretStore for EthMultiStore {
|
|||||||
Err(Error::InvalidPassword)
|
Err(Error::InvalidPassword)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generate_derived(&self, account_ref: &StoreAccountRef, password: &str, derivation: Derivation)
|
fn generate_derived(&self, account_ref: &StoreAccountRef, password: &Password, derivation: Derivation)
|
||||||
-> Result<Address, Error>
|
-> Result<Address, Error>
|
||||||
{
|
{
|
||||||
let accounts = self.get_matching(&account_ref, password)?;
|
let accounts = self.get_matching(&account_ref, password)?;
|
||||||
@@ -484,7 +484,7 @@ impl SimpleSecretStore for EthMultiStore {
|
|||||||
Err(Error::InvalidPassword)
|
Err(Error::InvalidPassword)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sign_derived(&self, account_ref: &StoreAccountRef, password: &str, derivation: Derivation, message: &Message)
|
fn sign_derived(&self, account_ref: &StoreAccountRef, password: &Password, derivation: Derivation, message: &Message)
|
||||||
-> Result<Signature, Error>
|
-> Result<Signature, Error>
|
||||||
{
|
{
|
||||||
let accounts = self.get_matching(&account_ref, password)?;
|
let accounts = self.get_matching(&account_ref, password)?;
|
||||||
@@ -518,7 +518,7 @@ impl SimpleSecretStore for EthMultiStore {
|
|||||||
Ok(self.cache.read().keys().cloned().collect())
|
Ok(self.cache.read().keys().cloned().collect())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remove_account(&self, account_ref: &StoreAccountRef, password: &str) -> Result<(), Error> {
|
fn remove_account(&self, account_ref: &StoreAccountRef, password: &Password) -> Result<(), Error> {
|
||||||
let accounts = self.get_matching(account_ref, password)?;
|
let accounts = self.get_matching(account_ref, password)?;
|
||||||
|
|
||||||
for account in accounts {
|
for account in accounts {
|
||||||
@@ -528,7 +528,7 @@ impl SimpleSecretStore for EthMultiStore {
|
|||||||
Err(Error::InvalidPassword)
|
Err(Error::InvalidPassword)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn change_password(&self, account_ref: &StoreAccountRef, old_password: &str, new_password: &str) -> Result<(), Error> {
|
fn change_password(&self, account_ref: &StoreAccountRef, old_password: &Password, new_password: &Password) -> Result<(), Error> {
|
||||||
let accounts = self.get_matching(account_ref, old_password)?;
|
let accounts = self.get_matching(account_ref, old_password)?;
|
||||||
|
|
||||||
if accounts.is_empty() {
|
if accounts.is_empty() {
|
||||||
@@ -544,11 +544,11 @@ impl SimpleSecretStore for EthMultiStore {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn export_account(&self, account_ref: &StoreAccountRef, password: &str) -> Result<OpaqueKeyFile, Error> {
|
fn export_account(&self, account_ref: &StoreAccountRef, password: &Password) -> Result<OpaqueKeyFile, Error> {
|
||||||
self.get_matching(account_ref, password)?.into_iter().nth(0).map(Into::into).ok_or(Error::InvalidPassword)
|
self.get_matching(account_ref, password)?.into_iter().nth(0).map(Into::into).ok_or(Error::InvalidPassword)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sign(&self, account: &StoreAccountRef, password: &str, message: &Message) -> Result<Signature, Error> {
|
fn sign(&self, account: &StoreAccountRef, password: &Password, message: &Message) -> Result<Signature, Error> {
|
||||||
let accounts = self.get_matching(account, password)?;
|
let accounts = self.get_matching(account, password)?;
|
||||||
match accounts.first() {
|
match accounts.first() {
|
||||||
Some(ref account) => account.sign(password, message),
|
Some(ref account) => account.sign(password, message),
|
||||||
@@ -556,7 +556,7 @@ impl SimpleSecretStore for EthMultiStore {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn decrypt(&self, account: &StoreAccountRef, password: &str, shared_mac: &[u8], message: &[u8]) -> Result<Vec<u8>, Error> {
|
fn decrypt(&self, account: &StoreAccountRef, password: &Password, shared_mac: &[u8], message: &[u8]) -> Result<Vec<u8>, Error> {
|
||||||
let accounts = self.get_matching(account, password)?;
|
let accounts = self.get_matching(account, password)?;
|
||||||
match accounts.first() {
|
match accounts.first() {
|
||||||
Some(ref account) => account.decrypt(password, shared_mac, message),
|
Some(ref account) => account.decrypt(password, shared_mac, message),
|
||||||
@@ -564,7 +564,7 @@ impl SimpleSecretStore for EthMultiStore {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn agree(&self, account: &StoreAccountRef, password: &str, other: &Public) -> Result<Secret, Error> {
|
fn agree(&self, account: &StoreAccountRef, password: &Password, other: &Public) -> Result<Secret, Error> {
|
||||||
let accounts = self.get_matching(account, password)?;
|
let accounts = self.get_matching(account, password)?;
|
||||||
match accounts.first() {
|
match accounts.first() {
|
||||||
Some(ref account) => account.agree(password, other),
|
Some(ref account) => account.agree(password, other),
|
||||||
@@ -572,7 +572,7 @@ impl SimpleSecretStore for EthMultiStore {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_vault(&self, name: &str, password: &str) -> Result<(), Error> {
|
fn create_vault(&self, name: &str, password: &Password) -> Result<(), Error> {
|
||||||
let is_vault_created = { // lock border
|
let is_vault_created = { // lock border
|
||||||
let mut vaults = self.vaults.lock();
|
let mut vaults = self.vaults.lock();
|
||||||
if !vaults.contains_key(&name.to_owned()) {
|
if !vaults.contains_key(&name.to_owned()) {
|
||||||
@@ -592,7 +592,7 @@ impl SimpleSecretStore for EthMultiStore {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn open_vault(&self, name: &str, password: &str) -> Result<(), Error> {
|
fn open_vault(&self, name: &str, password: &Password) -> Result<(), Error> {
|
||||||
let is_vault_opened = { // lock border
|
let is_vault_opened = { // lock border
|
||||||
let mut vaults = self.vaults.lock();
|
let mut vaults = self.vaults.lock();
|
||||||
if !vaults.contains_key(&name.to_owned()) {
|
if !vaults.contains_key(&name.to_owned()) {
|
||||||
@@ -629,7 +629,7 @@ impl SimpleSecretStore for EthMultiStore {
|
|||||||
Ok(self.vaults.lock().keys().cloned().collect())
|
Ok(self.vaults.lock().keys().cloned().collect())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn change_vault_password(&self, name: &str, new_password: &str) -> Result<(), Error> {
|
fn change_vault_password(&self, name: &str, new_password: &Password) -> Result<(), Error> {
|
||||||
let old_key = self.vaults.lock().get(name).map(|v| v.key()).ok_or(Error::VaultNotFound)?;
|
let old_key = self.vaults.lock().get(name).map(|v| v.key()).ok_or(Error::VaultNotFound)?;
|
||||||
let vault_provider = self.dir.as_vault_provider().ok_or(Error::VaultsAreNotSupported)?;
|
let vault_provider = self.dir.as_vault_provider().ok_or(Error::VaultsAreNotSupported)?;
|
||||||
let vault = vault_provider.open(name, old_key)?;
|
let vault = vault_provider.open(name, old_key)?;
|
||||||
@@ -732,7 +732,8 @@ mod tests {
|
|||||||
let keypair = keypair();
|
let keypair = keypair();
|
||||||
|
|
||||||
// when
|
// when
|
||||||
let address = store.insert_account(SecretVaultRef::Root, keypair.secret().clone(), "test").unwrap();
|
let passwd = "test".into();
|
||||||
|
let address = store.insert_account(SecretVaultRef::Root, keypair.secret().clone(), &passwd).unwrap();
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assert_eq!(address, StoreAccountRef::root(keypair.address()));
|
assert_eq!(address, StoreAccountRef::root(keypair.address()));
|
||||||
@@ -745,7 +746,8 @@ mod tests {
|
|||||||
// given
|
// given
|
||||||
let store = store();
|
let store = store();
|
||||||
let keypair = keypair();
|
let keypair = keypair();
|
||||||
let address = store.insert_account(SecretVaultRef::Root, keypair.secret().clone(), "test").unwrap();
|
let passwd = "test".into();
|
||||||
|
let address = store.insert_account(SecretVaultRef::Root, keypair.secret().clone(), &passwd).unwrap();
|
||||||
assert_eq!(&store.meta(&address).unwrap(), "{}");
|
assert_eq!(&store.meta(&address).unwrap(), "{}");
|
||||||
assert_eq!(&store.name(&address).unwrap(), "");
|
assert_eq!(&store.name(&address).unwrap(), "");
|
||||||
|
|
||||||
@@ -763,11 +765,12 @@ mod tests {
|
|||||||
fn should_remove_account() {
|
fn should_remove_account() {
|
||||||
// given
|
// given
|
||||||
let store = store();
|
let store = store();
|
||||||
|
let passwd = "test".into();
|
||||||
let keypair = keypair();
|
let keypair = keypair();
|
||||||
let address = store.insert_account(SecretVaultRef::Root, keypair.secret().clone(), "test").unwrap();
|
let address = store.insert_account(SecretVaultRef::Root, keypair.secret().clone(), &passwd).unwrap();
|
||||||
|
|
||||||
// when
|
// when
|
||||||
store.remove_account(&address, "test").unwrap();
|
store.remove_account(&address, &passwd).unwrap();
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assert_eq!(store.accounts().unwrap().len(), 0, "Should remove account.");
|
assert_eq!(store.accounts().unwrap().len(), 0, "Should remove account.");
|
||||||
@@ -777,12 +780,13 @@ mod tests {
|
|||||||
fn should_return_true_if_password_is_correct() {
|
fn should_return_true_if_password_is_correct() {
|
||||||
// given
|
// given
|
||||||
let store = store();
|
let store = store();
|
||||||
|
let passwd = "test".into();
|
||||||
let keypair = keypair();
|
let keypair = keypair();
|
||||||
let address = store.insert_account(SecretVaultRef::Root, keypair.secret().clone(), "test").unwrap();
|
let address = store.insert_account(SecretVaultRef::Root, keypair.secret().clone(), &passwd).unwrap();
|
||||||
|
|
||||||
// when
|
// when
|
||||||
let res1 = store.test_password(&address, "x").unwrap();
|
let res1 = store.test_password(&address, &"x".into()).unwrap();
|
||||||
let res2 = store.test_password(&address, "test").unwrap();
|
let res2 = store.test_password(&address, &passwd).unwrap();
|
||||||
|
|
||||||
assert!(!res1, "First password should be invalid.");
|
assert!(!res1, "First password should be invalid.");
|
||||||
assert!(res2, "Second password should be correct.");
|
assert!(res2, "Second password should be correct.");
|
||||||
@@ -792,16 +796,18 @@ mod tests {
|
|||||||
fn multistore_should_be_able_to_have_the_same_account_twice() {
|
fn multistore_should_be_able_to_have_the_same_account_twice() {
|
||||||
// given
|
// given
|
||||||
let store = multi_store();
|
let store = multi_store();
|
||||||
|
let passwd1 = "test".into();
|
||||||
|
let passwd2 = "xyz".into();
|
||||||
let keypair = keypair();
|
let keypair = keypair();
|
||||||
let address = store.insert_account(SecretVaultRef::Root, keypair.secret().clone(), "test").unwrap();
|
let address = store.insert_account(SecretVaultRef::Root, keypair.secret().clone(), &passwd1).unwrap();
|
||||||
let address2 = store.insert_account(SecretVaultRef::Root, keypair.secret().clone(), "xyz").unwrap();
|
let address2 = store.insert_account(SecretVaultRef::Root, keypair.secret().clone(), &passwd2).unwrap();
|
||||||
assert_eq!(address, address2);
|
assert_eq!(address, address2);
|
||||||
|
|
||||||
// when
|
// when
|
||||||
assert!(store.remove_account(&address, "test").is_ok(), "First password should work.");
|
assert!(store.remove_account(&address, &passwd1).is_ok(), "First password should work.");
|
||||||
assert_eq!(store.accounts().unwrap().len(), 1);
|
assert_eq!(store.accounts().unwrap().len(), 1);
|
||||||
|
|
||||||
assert!(store.remove_account(&address, "xyz").is_ok(), "Second password should work too.");
|
assert!(store.remove_account(&address, &passwd2).is_ok(), "Second password should work too.");
|
||||||
assert_eq!(store.accounts().unwrap().len(), 0);
|
assert_eq!(store.accounts().unwrap().len(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -809,17 +815,19 @@ mod tests {
|
|||||||
fn should_copy_account() {
|
fn should_copy_account() {
|
||||||
// given
|
// given
|
||||||
let store = store();
|
let store = store();
|
||||||
|
let passwd1 = "test".into();
|
||||||
|
let passwd2 = "xzy".into();
|
||||||
let multi_store = multi_store();
|
let multi_store = multi_store();
|
||||||
let keypair = keypair();
|
let keypair = keypair();
|
||||||
let address = store.insert_account(SecretVaultRef::Root, keypair.secret().clone(), "test").unwrap();
|
let address = store.insert_account(SecretVaultRef::Root, keypair.secret().clone(), &passwd1).unwrap();
|
||||||
assert_eq!(multi_store.accounts().unwrap().len(), 0);
|
assert_eq!(multi_store.accounts().unwrap().len(), 0);
|
||||||
|
|
||||||
// when
|
// when
|
||||||
store.copy_account(&multi_store, SecretVaultRef::Root, &address, "test", "xyz").unwrap();
|
store.copy_account(&multi_store, SecretVaultRef::Root, &address, &passwd1, &passwd2).unwrap();
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assert!(store.test_password(&address, "test").unwrap(), "First password should work for store.");
|
assert!(store.test_password(&address, &passwd1).unwrap(), "First password should work for store.");
|
||||||
assert!(multi_store.sign(&address, "xyz", &Default::default()).is_ok(), "Second password should work for second store.");
|
assert!(multi_store.sign(&address, &passwd2, &Default::default()).is_ok(), "Second password should work for second store.");
|
||||||
assert_eq!(multi_store.accounts().unwrap().len(), 1);
|
assert_eq!(multi_store.accounts().unwrap().len(), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -828,23 +836,23 @@ mod tests {
|
|||||||
// given
|
// given
|
||||||
let mut dir = RootDiskDirectoryGuard::new();
|
let mut dir = RootDiskDirectoryGuard::new();
|
||||||
let store = EthStore::open(dir.key_dir.take().unwrap()).unwrap();
|
let store = EthStore::open(dir.key_dir.take().unwrap()).unwrap();
|
||||||
let name1 = "vault1"; let password1 = "password1";
|
let name1 = "vault1"; let password1 = "password1".into();
|
||||||
let name2 = "vault2"; let password2 = "password2";
|
let name2 = "vault2"; let password2 = "password2".into();
|
||||||
let keypair1 = keypair();
|
let keypair1 = keypair();
|
||||||
let keypair2 = keypair();
|
let keypair2 = keypair();
|
||||||
let keypair3 = keypair(); let password3 = "password3";
|
let keypair3 = keypair(); let password3 = "password3".into();
|
||||||
|
|
||||||
// when
|
// when
|
||||||
store.create_vault(name1, password1).unwrap();
|
store.create_vault(name1, &password1).unwrap();
|
||||||
store.create_vault(name2, password2).unwrap();
|
store.create_vault(name2, &password2).unwrap();
|
||||||
|
|
||||||
// then [can create vaults] ^^^
|
// then [can create vaults] ^^^
|
||||||
|
|
||||||
// and when
|
// and when
|
||||||
store.insert_account(SecretVaultRef::Vault(name1.to_owned()), keypair1.secret().clone(), password1).unwrap();
|
store.insert_account(SecretVaultRef::Vault(name1.to_owned()), keypair1.secret().clone(), &password1).unwrap();
|
||||||
store.insert_account(SecretVaultRef::Vault(name2.to_owned()), keypair2.secret().clone(), password2).unwrap();
|
store.insert_account(SecretVaultRef::Vault(name2.to_owned()), keypair2.secret().clone(), &password2).unwrap();
|
||||||
store.insert_account(SecretVaultRef::Root, keypair3.secret().clone(), password3).unwrap();
|
store.insert_account(SecretVaultRef::Root, keypair3.secret().clone(), &password3).unwrap();
|
||||||
store.insert_account(SecretVaultRef::Vault("vault3".to_owned()), keypair1.secret().clone(), password3).unwrap_err();
|
store.insert_account(SecretVaultRef::Vault("vault3".to_owned()), keypair1.secret().clone(), &password3).unwrap_err();
|
||||||
let accounts = store.accounts().unwrap();
|
let accounts = store.accounts().unwrap();
|
||||||
|
|
||||||
// then [can create accounts in vaults]
|
// then [can create accounts in vaults]
|
||||||
@@ -864,10 +872,10 @@ mod tests {
|
|||||||
assert!(accounts.iter().any(|a| a.vault == SecretVaultRef::Root));
|
assert!(accounts.iter().any(|a| a.vault == SecretVaultRef::Root));
|
||||||
|
|
||||||
// and when
|
// and when
|
||||||
store.open_vault(name1, password2).unwrap_err();
|
store.open_vault(name1, &password2).unwrap_err();
|
||||||
store.open_vault(name2, password1).unwrap_err();
|
store.open_vault(name2, &password1).unwrap_err();
|
||||||
store.open_vault(name1, password1).unwrap();
|
store.open_vault(name1, &password1).unwrap();
|
||||||
store.open_vault(name2, password2).unwrap();
|
store.open_vault(name2, &password2).unwrap();
|
||||||
let accounts = store.accounts().unwrap();
|
let accounts = store.accounts().unwrap();
|
||||||
|
|
||||||
// then [can check vaults on open + can reopen vaults + accounts from vaults appear]
|
// then [can check vaults on open + can reopen vaults + accounts from vaults appear]
|
||||||
@@ -882,19 +890,19 @@ mod tests {
|
|||||||
// given
|
// given
|
||||||
let mut dir = RootDiskDirectoryGuard::new();
|
let mut dir = RootDiskDirectoryGuard::new();
|
||||||
let store = EthStore::open(dir.key_dir.take().unwrap()).unwrap();
|
let store = EthStore::open(dir.key_dir.take().unwrap()).unwrap();
|
||||||
let name1 = "vault1"; let password1 = "password1";
|
let name1 = "vault1"; let password1 = "password1".into();
|
||||||
let name2 = "vault2"; let password2 = "password2";
|
let name2 = "vault2"; let password2 = "password2".into();
|
||||||
let password3 = "password3";
|
let password3 = "password3".into();
|
||||||
let keypair1 = keypair();
|
let keypair1 = keypair();
|
||||||
let keypair2 = keypair();
|
let keypair2 = keypair();
|
||||||
let keypair3 = keypair();
|
let keypair3 = keypair();
|
||||||
|
|
||||||
// when
|
// when
|
||||||
store.create_vault(name1, password1).unwrap();
|
store.create_vault(name1, &password1).unwrap();
|
||||||
store.create_vault(name2, password2).unwrap();
|
store.create_vault(name2, &password2).unwrap();
|
||||||
let account1 = store.insert_account(SecretVaultRef::Vault(name1.to_owned()), keypair1.secret().clone(), password1).unwrap();
|
let account1 = store.insert_account(SecretVaultRef::Vault(name1.to_owned()), keypair1.secret().clone(), &password1).unwrap();
|
||||||
let account2 = store.insert_account(SecretVaultRef::Vault(name1.to_owned()), keypair2.secret().clone(), password1).unwrap();
|
let account2 = store.insert_account(SecretVaultRef::Vault(name1.to_owned()), keypair2.secret().clone(), &password1).unwrap();
|
||||||
let account3 = store.insert_account(SecretVaultRef::Root, keypair3.secret().clone(), password3).unwrap();
|
let account3 = store.insert_account(SecretVaultRef::Root, keypair3.secret().clone(), &password3).unwrap();
|
||||||
|
|
||||||
// then
|
// then
|
||||||
let account1 = store.change_account_vault(SecretVaultRef::Root, account1.clone()).unwrap();
|
let account1 = store.change_account_vault(SecretVaultRef::Root, account1.clone()).unwrap();
|
||||||
@@ -917,11 +925,11 @@ mod tests {
|
|||||||
// given
|
// given
|
||||||
let mut dir = RootDiskDirectoryGuard::new();
|
let mut dir = RootDiskDirectoryGuard::new();
|
||||||
let store = EthStore::open(dir.key_dir.take().unwrap()).unwrap();
|
let store = EthStore::open(dir.key_dir.take().unwrap()).unwrap();
|
||||||
let password1 = "password1";
|
let password1 = "password1".into();
|
||||||
let keypair1 = keypair();
|
let keypair1 = keypair();
|
||||||
|
|
||||||
// when
|
// when
|
||||||
let account1 = store.insert_account(SecretVaultRef::Root, keypair1.secret().clone(), password1).unwrap();
|
let account1 = store.insert_account(SecretVaultRef::Root, keypair1.secret().clone(), &password1).unwrap();
|
||||||
store.change_account_vault(SecretVaultRef::Root, account1).unwrap();
|
store.change_account_vault(SecretVaultRef::Root, account1).unwrap();
|
||||||
|
|
||||||
// then
|
// then
|
||||||
@@ -934,16 +942,16 @@ mod tests {
|
|||||||
// given
|
// given
|
||||||
let mut dir = RootDiskDirectoryGuard::new();
|
let mut dir = RootDiskDirectoryGuard::new();
|
||||||
let store = EthStore::open(dir.key_dir.take().unwrap()).unwrap();
|
let store = EthStore::open(dir.key_dir.take().unwrap()).unwrap();
|
||||||
let name1 = "vault1"; let password1 = "password1";
|
let name1 = "vault1"; let password1 = "password1".into();
|
||||||
let keypair1 = keypair();
|
let keypair1 = keypair();
|
||||||
|
|
||||||
// when
|
// when
|
||||||
store.create_vault(name1, password1).unwrap();
|
store.create_vault(name1, &password1).unwrap();
|
||||||
let account1 = store.insert_account(SecretVaultRef::Vault(name1.to_owned()), keypair1.secret().clone(), password1).unwrap();
|
let account1 = store.insert_account(SecretVaultRef::Vault(name1.to_owned()), keypair1.secret().clone(), &password1).unwrap();
|
||||||
assert_eq!(store.accounts().unwrap().len(), 1);
|
assert_eq!(store.accounts().unwrap().len(), 1);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
store.remove_account(&account1, password1).unwrap();
|
store.remove_account(&account1, &password1).unwrap();
|
||||||
assert_eq!(store.accounts().unwrap().len(), 0);
|
assert_eq!(store.accounts().unwrap().len(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -952,17 +960,17 @@ mod tests {
|
|||||||
// given
|
// given
|
||||||
let mut dir = RootDiskDirectoryGuard::new();
|
let mut dir = RootDiskDirectoryGuard::new();
|
||||||
let store = EthStore::open(dir.key_dir.take().unwrap()).unwrap();
|
let store = EthStore::open(dir.key_dir.take().unwrap()).unwrap();
|
||||||
let name1 = "vault1"; let password1 = "password1";
|
let name1 = "vault1"; let password1 = "password1".into();
|
||||||
let password2 = "password2";
|
let password2 = "password2".into();
|
||||||
let keypair1 = keypair();
|
let keypair1 = keypair();
|
||||||
|
|
||||||
// when
|
// when
|
||||||
store.create_vault(name1, password1).unwrap();
|
store.create_vault(name1, &password1).unwrap();
|
||||||
let account1 = store.insert_account(SecretVaultRef::Vault(name1.to_owned()), keypair1.secret().clone(), password1).unwrap();
|
let account1 = store.insert_account(SecretVaultRef::Vault(name1.to_owned()), keypair1.secret().clone(), &password1).unwrap();
|
||||||
assert_eq!(store.accounts().unwrap().len(), 1);
|
assert_eq!(store.accounts().unwrap().len(), 1);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
store.remove_account(&account1, password2).unwrap_err();
|
store.remove_account(&account1, &password2).unwrap_err();
|
||||||
assert_eq!(store.accounts().unwrap().len(), 1);
|
assert_eq!(store.accounts().unwrap().len(), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -971,24 +979,24 @@ mod tests {
|
|||||||
// given
|
// given
|
||||||
let mut dir = RootDiskDirectoryGuard::new();
|
let mut dir = RootDiskDirectoryGuard::new();
|
||||||
let store = EthStore::open(dir.key_dir.take().unwrap()).unwrap();
|
let store = EthStore::open(dir.key_dir.take().unwrap()).unwrap();
|
||||||
let name = "vault"; let password = "password";
|
let name = "vault"; let password = "password".into();
|
||||||
let keypair = keypair();
|
let keypair = keypair();
|
||||||
|
|
||||||
// when
|
// when
|
||||||
store.create_vault(name, password).unwrap();
|
store.create_vault(name, &password).unwrap();
|
||||||
store.insert_account(SecretVaultRef::Vault(name.to_owned()), keypair.secret().clone(), password).unwrap();
|
store.insert_account(SecretVaultRef::Vault(name.to_owned()), keypair.secret().clone(), &password).unwrap();
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assert_eq!(store.accounts().unwrap().len(), 1);
|
assert_eq!(store.accounts().unwrap().len(), 1);
|
||||||
let new_password = "new_password";
|
let new_password = "new_password".into();
|
||||||
store.change_vault_password(name, new_password).unwrap();
|
store.change_vault_password(name, &new_password).unwrap();
|
||||||
assert_eq!(store.accounts().unwrap().len(), 1);
|
assert_eq!(store.accounts().unwrap().len(), 1);
|
||||||
|
|
||||||
// and when
|
// and when
|
||||||
store.close_vault(name).unwrap();
|
store.close_vault(name).unwrap();
|
||||||
|
|
||||||
// then
|
// then
|
||||||
store.open_vault(name, new_password).unwrap();
|
store.open_vault(name, &new_password).unwrap();
|
||||||
assert_eq!(store.accounts().unwrap().len(), 1);
|
assert_eq!(store.accounts().unwrap().len(), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -997,18 +1005,18 @@ mod tests {
|
|||||||
// given
|
// given
|
||||||
let mut dir = RootDiskDirectoryGuard::new();
|
let mut dir = RootDiskDirectoryGuard::new();
|
||||||
let store = EthStore::open(dir.key_dir.take().unwrap()).unwrap();
|
let store = EthStore::open(dir.key_dir.take().unwrap()).unwrap();
|
||||||
let name = "vault"; let password = "password";
|
let name = "vault"; let password = "password".into();
|
||||||
let secret_password = "sec_password";
|
let secret_password = "sec_password".into();
|
||||||
let keypair = keypair();
|
let keypair = keypair();
|
||||||
|
|
||||||
// when
|
// when
|
||||||
store.create_vault(name, password).unwrap();
|
store.create_vault(name, &password).unwrap();
|
||||||
let account_ref = store.insert_account(SecretVaultRef::Vault(name.to_owned()), keypair.secret().clone(), secret_password).unwrap();
|
let account_ref = store.insert_account(SecretVaultRef::Vault(name.to_owned()), keypair.secret().clone(), &secret_password).unwrap();
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assert_eq!(store.accounts().unwrap().len(), 1);
|
assert_eq!(store.accounts().unwrap().len(), 1);
|
||||||
let new_secret_password = "new_sec_password";
|
let new_secret_password = "new_sec_password".into();
|
||||||
store.change_password(&account_ref, secret_password, new_secret_password).unwrap();
|
store.change_password(&account_ref, &secret_password, &new_secret_password).unwrap();
|
||||||
assert_eq!(store.accounts().unwrap().len(), 1);
|
assert_eq!(store.accounts().unwrap().len(), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1017,14 +1025,14 @@ mod tests {
|
|||||||
// given
|
// given
|
||||||
let mut dir = RootDiskDirectoryGuard::new();
|
let mut dir = RootDiskDirectoryGuard::new();
|
||||||
let store = EthStore::open(dir.key_dir.take().unwrap()).unwrap();
|
let store = EthStore::open(dir.key_dir.take().unwrap()).unwrap();
|
||||||
let name1 = "vault1"; let password1 = "password1";
|
let name1 = "vault1"; let password1 = "password1".into();
|
||||||
let name2 = "vault2"; let password2 = "password2";
|
let name2 = "vault2"; let password2 = "password2".into();
|
||||||
let name3 = "vault3"; let password3 = "password3";
|
let name3 = "vault3"; let password3 = "password3".into();
|
||||||
|
|
||||||
// when
|
// when
|
||||||
store.create_vault(name1, password1).unwrap();
|
store.create_vault(name1, &password1).unwrap();
|
||||||
store.create_vault(name2, password2).unwrap();
|
store.create_vault(name2, &password2).unwrap();
|
||||||
store.create_vault(name3, password3).unwrap();
|
store.create_vault(name3, &password3).unwrap();
|
||||||
store.close_vault(name2).unwrap();
|
store.close_vault(name2).unwrap();
|
||||||
|
|
||||||
// then
|
// then
|
||||||
@@ -1039,10 +1047,10 @@ mod tests {
|
|||||||
// given
|
// given
|
||||||
let mut dir = RootDiskDirectoryGuard::new();
|
let mut dir = RootDiskDirectoryGuard::new();
|
||||||
let store = EthStore::open(dir.key_dir.take().unwrap()).unwrap();
|
let store = EthStore::open(dir.key_dir.take().unwrap()).unwrap();
|
||||||
let name1 = "vault1"; let password1 = "password1";
|
let name1 = "vault1"; let password1 = "password1".into();
|
||||||
|
|
||||||
// when
|
// when
|
||||||
store.create_vault(name1, password1).unwrap();
|
store.create_vault(name1, &password1).unwrap();
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assert_eq!(store.get_vault_meta(name1).unwrap(), "{}".to_owned());
|
assert_eq!(store.get_vault_meta(name1).unwrap(), "{}".to_owned());
|
||||||
@@ -1051,7 +1059,7 @@ mod tests {
|
|||||||
|
|
||||||
// and when
|
// and when
|
||||||
store.close_vault(name1).unwrap();
|
store.close_vault(name1).unwrap();
|
||||||
store.open_vault(name1, password1).unwrap();
|
store.open_vault(name1, &password1).unwrap();
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assert_eq!(store.get_vault_meta(name1).unwrap(), "Hello, world!!!".to_owned());
|
assert_eq!(store.get_vault_meta(name1).unwrap(), "Hello, world!!!".to_owned());
|
||||||
@@ -1069,13 +1077,13 @@ mod tests {
|
|||||||
// given we have one account in the store
|
// given we have one account in the store
|
||||||
let store = store();
|
let store = store();
|
||||||
let keypair = keypair();
|
let keypair = keypair();
|
||||||
let address = store.insert_account(SecretVaultRef::Root, keypair.secret().clone(), "test").unwrap();
|
let address = store.insert_account(SecretVaultRef::Root, keypair.secret().clone(), &"test".into()).unwrap();
|
||||||
|
|
||||||
// when we deriving from that account
|
// when we deriving from that account
|
||||||
let derived = store.insert_derived(
|
let derived = store.insert_derived(
|
||||||
SecretVaultRef::Root,
|
SecretVaultRef::Root,
|
||||||
&address,
|
&address,
|
||||||
"test",
|
&"test".into(),
|
||||||
Derivation::HardHash(H256::from(0)),
|
Derivation::HardHash(H256::from(0)),
|
||||||
).unwrap();
|
).unwrap();
|
||||||
|
|
||||||
@@ -1084,7 +1092,7 @@ mod tests {
|
|||||||
assert_eq!(accounts.len(), 2);
|
assert_eq!(accounts.len(), 2);
|
||||||
|
|
||||||
// and we can sign with the derived contract
|
// and we can sign with the derived contract
|
||||||
assert!(store.sign(&derived, "test", &Default::default()).is_ok(), "Second password should work for second store.");
|
assert!(store.sign(&derived, &"test".into(), &Default::default()).is_ok(), "Second password should work for second store.");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -1092,13 +1100,13 @@ mod tests {
|
|||||||
// given
|
// given
|
||||||
let mut dir = RootDiskDirectoryGuard::new();
|
let mut dir = RootDiskDirectoryGuard::new();
|
||||||
let store = EthStore::open(dir.key_dir.take().unwrap()).unwrap();
|
let store = EthStore::open(dir.key_dir.take().unwrap()).unwrap();
|
||||||
let name = "vault"; let password = "password1";
|
let name = "vault"; let password = "password1".into();
|
||||||
let new_password = "password2";
|
let new_password = "password2".into();
|
||||||
|
|
||||||
// when
|
// when
|
||||||
store.create_vault(name, password).unwrap();
|
store.create_vault(name, &password).unwrap();
|
||||||
store.set_vault_meta(name, "OldMeta").unwrap();
|
store.set_vault_meta(name, "OldMeta").unwrap();
|
||||||
store.change_vault_password(name, new_password).unwrap();
|
store.change_vault_password(name, &new_password).unwrap();
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assert_eq!(store.get_vault_meta(name).unwrap(), "OldMeta".to_owned());
|
assert_eq!(store.get_vault_meta(name).unwrap(), "OldMeta".to_owned());
|
||||||
@@ -1109,10 +1117,10 @@ mod tests {
|
|||||||
// given
|
// given
|
||||||
let store = store();
|
let store = store();
|
||||||
let keypair = keypair();
|
let keypair = keypair();
|
||||||
let address = store.insert_account(SecretVaultRef::Root, keypair.secret().clone(), "test").unwrap();
|
let address = store.insert_account(SecretVaultRef::Root, keypair.secret().clone(), &"test".into()).unwrap();
|
||||||
|
|
||||||
// when
|
// when
|
||||||
let exported = store.export_account(&address, "test");
|
let exported = store.export_account(&address, &"test".into());
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assert!(exported.is_ok(), "Should export single account: {:?}", exported);
|
assert!(exported.is_ok(), "Should export single account: {:?}", exported);
|
||||||
@@ -1,18 +1,18 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
// Copyright 2015-2019 Parity Technologies (UK) Ltd.
|
||||||
// This file is part of Parity.
|
// This file is part of Parity Ethereum.
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
// Parity Ethereum is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
// Parity Ethereum is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
@@ -25,7 +25,7 @@ use Error;
|
|||||||
|
|
||||||
/// Import an account from a file.
|
/// Import an account from a file.
|
||||||
pub fn import_account(path: &Path, dst: &KeyDirectory) -> Result<Address, Error> {
|
pub fn import_account(path: &Path, dst: &KeyDirectory) -> Result<Address, Error> {
|
||||||
let key_manager = DiskKeyFileManager;
|
let key_manager = DiskKeyFileManager::default();
|
||||||
let existing_accounts = dst.load()?.into_iter().map(|a| a.address).collect::<HashSet<_>>();
|
let existing_accounts = dst.load()?.into_iter().map(|a| a.address).collect::<HashSet<_>>();
|
||||||
let filename = path.file_name().and_then(|n| n.to_str()).map(|f| f.to_owned());
|
let filename = path.file_name().and_then(|n| n.to_str()).map(|f| f.to_owned());
|
||||||
let account = fs::File::open(&path)
|
let account = fs::File::open(&path)
|
||||||
@@ -42,7 +42,9 @@ pub fn import_account(path: &Path, dst: &KeyDirectory) -> Result<Address, Error>
|
|||||||
/// Import all accounts from one directory to the other.
|
/// Import all accounts from one directory to the other.
|
||||||
pub fn import_accounts(src: &KeyDirectory, dst: &KeyDirectory) -> Result<Vec<Address>, Error> {
|
pub fn import_accounts(src: &KeyDirectory, dst: &KeyDirectory) -> Result<Vec<Address>, Error> {
|
||||||
let accounts = src.load()?;
|
let accounts = src.load()?;
|
||||||
let existing_accounts = dst.load()?.into_iter().map(|a| a.address).collect::<HashSet<_>>();
|
let existing_accounts = dst.load()?.into_iter()
|
||||||
|
.map(|a| a.address)
|
||||||
|
.collect::<HashSet<_>>();
|
||||||
|
|
||||||
accounts.into_iter()
|
accounts.into_iter()
|
||||||
.filter(|a| !existing_accounts.contains(&a.address))
|
.filter(|a| !existing_accounts.contains(&a.address))
|
||||||
@@ -1,18 +1,18 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
// Copyright 2015-2019 Parity Technologies (UK) Ltd.
|
||||||
// This file is part of Parity.
|
// This file is part of Parity Ethereum.
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
// Parity Ethereum is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
// Parity Ethereum is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use std::{ops, str};
|
use std::{ops, str};
|
||||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||||
@@ -72,4 +72,3 @@ impl From<Bytes> for Vec<u8> {
|
|||||||
b.0
|
b.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1,18 +1,18 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
// Copyright 2015-2019 Parity Technologies (UK) Ltd.
|
||||||
// This file is part of Parity.
|
// This file is part of Parity Ethereum.
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
// Parity Ethereum is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
// Parity Ethereum is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use serde::{Serialize, Serializer, Deserialize, Deserializer};
|
use serde::{Serialize, Serializer, Deserialize, Deserializer};
|
||||||
@@ -1,18 +1,18 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
// Copyright 2015-2019 Parity Technologies (UK) Ltd.
|
||||||
// This file is part of Parity.
|
// This file is part of Parity Ethereum.
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
// Parity Ethereum is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
// Parity Ethereum is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use std::{fmt, str};
|
use std::{fmt, str};
|
||||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||||
@@ -52,6 +52,7 @@ enum CryptoField {
|
|||||||
Kdf,
|
Kdf,
|
||||||
KdfParams,
|
KdfParams,
|
||||||
Mac,
|
Mac,
|
||||||
|
Version,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Deserialize<'a> for CryptoField {
|
impl<'a> Deserialize<'a> for CryptoField {
|
||||||
@@ -81,6 +82,7 @@ impl<'a> Visitor<'a> for CryptoFieldVisitor {
|
|||||||
"kdf" => Ok(CryptoField::Kdf),
|
"kdf" => Ok(CryptoField::Kdf),
|
||||||
"kdfparams" => Ok(CryptoField::KdfParams),
|
"kdfparams" => Ok(CryptoField::KdfParams),
|
||||||
"mac" => Ok(CryptoField::Mac),
|
"mac" => Ok(CryptoField::Mac),
|
||||||
|
"version" => Ok(CryptoField::Version),
|
||||||
_ => Err(Error::custom(format!("Unknown field: '{}'", value))),
|
_ => Err(Error::custom(format!("Unknown field: '{}'", value))),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -122,6 +124,8 @@ impl<'a> Visitor<'a> for CryptoVisitor {
|
|||||||
Some(CryptoField::Kdf) => { kdf = Some(visitor.next_value()?); }
|
Some(CryptoField::Kdf) => { kdf = Some(visitor.next_value()?); }
|
||||||
Some(CryptoField::KdfParams) => { kdfparams = Some(visitor.next_value()?); }
|
Some(CryptoField::KdfParams) => { kdfparams = Some(visitor.next_value()?); }
|
||||||
Some(CryptoField::Mac) => { mac = Some(visitor.next_value()?); }
|
Some(CryptoField::Mac) => { mac = Some(visitor.next_value()?); }
|
||||||
|
// skip not required version field (it appears in pyethereum generated keystores)
|
||||||
|
Some(CryptoField::Version) => { visitor.next_value().unwrap_or(()) }
|
||||||
None => { break; }
|
None => { break; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,18 +1,18 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
// Copyright 2015-2019 Parity Technologies (UK) Ltd.
|
||||||
// This file is part of Parity.
|
// This file is part of Parity Ethereum.
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
// Parity Ethereum is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
// Parity Ethereum is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
@@ -1,18 +1,18 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
// Copyright 2015-2019 Parity Technologies (UK) Ltd.
|
||||||
// This file is part of Parity.
|
// This file is part of Parity Ethereum.
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
// Parity Ethereum is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
// Parity Ethereum is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use std::{ops, fmt, str};
|
use std::{ops, fmt, str};
|
||||||
use rustc_hex::{FromHex, ToHex};
|
use rustc_hex::{FromHex, ToHex};
|
||||||
@@ -1,18 +1,18 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
// Copyright 2015-2019 Parity Technologies (UK) Ltd.
|
||||||
// This file is part of Parity.
|
// This file is part of Parity Ethereum.
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
// Parity Ethereum is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
// Parity Ethereum is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
//! Universaly unique identifier.
|
//! Universaly unique identifier.
|
||||||
use std::{fmt, str};
|
use std::{fmt, str};
|
||||||
@@ -1,23 +1,23 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
// Copyright 2015-2019 Parity Technologies (UK) Ltd.
|
||||||
// This file is part of Parity.
|
// This file is part of Parity Ethereum.
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
// Parity Ethereum is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
// Parity Ethereum is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use serde::{Serialize, Serializer, Deserialize, Deserializer};
|
use serde::{Serialize, Serializer, Deserialize, Deserializer};
|
||||||
use serde::de::{Visitor, Error as SerdeError};
|
use serde::de::{Visitor, Error as SerdeError};
|
||||||
use super::{Error, H256};
|
use super::{Error, Bytes};
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub enum KdfSer {
|
pub enum KdfSer {
|
||||||
@@ -111,7 +111,7 @@ pub struct Pbkdf2 {
|
|||||||
pub c: u32,
|
pub c: u32,
|
||||||
pub dklen: u32,
|
pub dklen: u32,
|
||||||
pub prf: Prf,
|
pub prf: Prf,
|
||||||
pub salt: H256,
|
pub salt: Bytes,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||||
@@ -120,7 +120,7 @@ pub struct Scrypt {
|
|||||||
pub p: u32,
|
pub p: u32,
|
||||||
pub n: u32,
|
pub n: u32,
|
||||||
pub r: u32,
|
pub r: u32,
|
||||||
pub salt: H256,
|
pub salt: Bytes,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
@@ -1,18 +1,18 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
// Copyright 2015-2019 Parity Technologies (UK) Ltd.
|
||||||
// This file is part of Parity.
|
// This file is part of Parity Ethereum.
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
// Parity Ethereum is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
// Parity Ethereum is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::io::{Read, Write};
|
use std::io::{Read, Write};
|
||||||
@@ -46,7 +46,7 @@ pub struct KeyFile {
|
|||||||
pub id: Uuid,
|
pub id: Uuid,
|
||||||
pub version: Version,
|
pub version: Version,
|
||||||
pub crypto: Crypto,
|
pub crypto: Crypto,
|
||||||
pub address: H160,
|
pub address: Option<H160>,
|
||||||
pub name: Option<String>,
|
pub name: Option<String>,
|
||||||
pub meta: Option<String>,
|
pub meta: Option<String>,
|
||||||
}
|
}
|
||||||
@@ -102,7 +102,6 @@ impl<'a> Deserialize<'a> for KeyFile {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn none_if_empty<'a, T>(v: Option<serde_json::Value>) -> Option<T> where
|
fn none_if_empty<'a, T>(v: Option<serde_json::Value>) -> Option<T> where
|
||||||
T: DeserializeOwned
|
T: DeserializeOwned
|
||||||
{
|
{
|
||||||
@@ -159,11 +158,6 @@ impl<'a> Visitor<'a> for KeyFileVisitor {
|
|||||||
None => return Err(V::Error::missing_field("crypto")),
|
None => return Err(V::Error::missing_field("crypto")),
|
||||||
};
|
};
|
||||||
|
|
||||||
let address = match address {
|
|
||||||
Some(address) => address,
|
|
||||||
None => return Err(V::Error::missing_field("address")),
|
|
||||||
};
|
|
||||||
|
|
||||||
let result = KeyFile {
|
let result = KeyFile {
|
||||||
id: id,
|
id: id,
|
||||||
version: version,
|
version: version,
|
||||||
@@ -223,7 +217,7 @@ mod tests {
|
|||||||
let expected = KeyFile {
|
let expected = KeyFile {
|
||||||
id: Uuid::from_str("8777d9f6-7860-4b9b-88b7-0b57ee6b3a73").unwrap(),
|
id: Uuid::from_str("8777d9f6-7860-4b9b-88b7-0b57ee6b3a73").unwrap(),
|
||||||
version: Version::V3,
|
version: Version::V3,
|
||||||
address: "6edddfc6349aff20bc6467ccf276c5b52487f7a8".into(),
|
address: Some("6edddfc6349aff20bc6467ccf276c5b52487f7a8".into()),
|
||||||
crypto: Crypto {
|
crypto: Crypto {
|
||||||
cipher: Cipher::Aes128Ctr(Aes128Ctr {
|
cipher: Cipher::Aes128Ctr(Aes128Ctr {
|
||||||
iv: "b5a7ec855ec9e2c405371356855fec83".into(),
|
iv: "b5a7ec855ec9e2c405371356855fec83".into(),
|
||||||
@@ -274,7 +268,7 @@ mod tests {
|
|||||||
let expected = KeyFile {
|
let expected = KeyFile {
|
||||||
id: "8777d9f6-7860-4b9b-88b7-0b57ee6b3a73".into(),
|
id: "8777d9f6-7860-4b9b-88b7-0b57ee6b3a73".into(),
|
||||||
version: Version::V3,
|
version: Version::V3,
|
||||||
address: "6edddfc6349aff20bc6467ccf276c5b52487f7a8".into(),
|
address: Some("6edddfc6349aff20bc6467ccf276c5b52487f7a8".into()),
|
||||||
crypto: Crypto {
|
crypto: Crypto {
|
||||||
cipher: Cipher::Aes128Ctr(Aes128Ctr {
|
cipher: Cipher::Aes128Ctr(Aes128Ctr {
|
||||||
iv: "b5a7ec855ec9e2c405371356855fec83".into(),
|
iv: "b5a7ec855ec9e2c405371356855fec83".into(),
|
||||||
@@ -302,7 +296,7 @@ mod tests {
|
|||||||
let file = KeyFile {
|
let file = KeyFile {
|
||||||
id: "8777d9f6-7860-4b9b-88b7-0b57ee6b3a73".into(),
|
id: "8777d9f6-7860-4b9b-88b7-0b57ee6b3a73".into(),
|
||||||
version: Version::V3,
|
version: Version::V3,
|
||||||
address: "6edddfc6349aff20bc6467ccf276c5b52487f7a8".into(),
|
address: Some("6edddfc6349aff20bc6467ccf276c5b52487f7a8".into()),
|
||||||
crypto: Crypto {
|
crypto: Crypto {
|
||||||
cipher: Cipher::Aes128Ctr(Aes128Ctr {
|
cipher: Cipher::Aes128Ctr(Aes128Ctr {
|
||||||
iv: "b5a7ec855ec9e2c405371356855fec83".into(),
|
iv: "b5a7ec855ec9e2c405371356855fec83".into(),
|
||||||
@@ -1,18 +1,18 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
// Copyright 2015-2019 Parity Technologies (UK) Ltd.
|
||||||
// This file is part of Parity.
|
// This file is part of Parity Ethereum.
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
// Parity Ethereum is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
// Parity Ethereum is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
//! Contract interface specification.
|
//! Contract interface specification.
|
||||||
|
|
||||||
@@ -1,3 +1,19 @@
|
|||||||
|
// Copyright 2015-2019 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity Ethereum.
|
||||||
|
|
||||||
|
// Parity Ethereum is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity Ethereum is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
use serde_json;
|
use serde_json;
|
||||||
use super::{H160, Bytes};
|
use super::{H160, Bytes};
|
||||||
@@ -1,18 +1,18 @@
|
|||||||
// Copyright 2015, 2016, 2017 Parity Technologies (UK) Ltd.
|
// Copyright 2015-2019 Parity Technologies (UK) Ltd.
|
||||||
// This file is part of Parity.
|
// This file is part of Parity Ethereum.
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
// Parity Ethereum is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
// Parity Ethereum is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use std::io::{Read, Write};
|
use std::io::{Read, Write};
|
||||||
use serde_json;
|
use serde_json;
|
||||||
@@ -1,18 +1,18 @@
|
|||||||
// Copyright 2015, 2016, 2017 Parity Technologies (UK) Ltd.
|
// Copyright 2015-2019 Parity Technologies (UK) Ltd.
|
||||||
// This file is part of Parity.
|
// This file is part of Parity Ethereum.
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
// Parity Ethereum is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
// Parity Ethereum is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use std::io::{Read, Write};
|
use std::io::{Read, Write};
|
||||||
use serde::de::Error;
|
use serde::de::Error;
|
||||||
@@ -1,18 +1,18 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
// Copyright 2015-2019 Parity Technologies (UK) Ltd.
|
||||||
// This file is part of Parity.
|
// This file is part of Parity Ethereum.
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
// Parity Ethereum is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
// Parity Ethereum is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use serde::{Serialize, Serializer, Deserialize, Deserializer};
|
use serde::{Serialize, Serializer, Deserialize, Deserializer};
|
||||||
@@ -56,4 +56,3 @@ impl<'a> Visitor<'a> for VersionVisitor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1,24 +1,23 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
// Copyright 2015-2019 Parity Technologies (UK) Ltd.
|
||||||
// This file is part of Parity.
|
// This file is part of Parity Ethereum.
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
// Parity Ethereum is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
// Parity Ethereum is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
//! Ethereum key-management.
|
//! Ethereum key-management.
|
||||||
|
|
||||||
#![warn(missing_docs)]
|
#![warn(missing_docs)]
|
||||||
|
|
||||||
extern crate crypto as rcrypto;
|
|
||||||
extern crate dir;
|
extern crate dir;
|
||||||
extern crate itertools;
|
extern crate itertools;
|
||||||
extern crate libc;
|
extern crate libc;
|
||||||
@@ -28,12 +27,11 @@ extern crate rustc_hex;
|
|||||||
extern crate serde;
|
extern crate serde;
|
||||||
extern crate serde_json;
|
extern crate serde_json;
|
||||||
extern crate smallvec;
|
extern crate smallvec;
|
||||||
extern crate subtle;
|
|
||||||
extern crate time;
|
extern crate time;
|
||||||
extern crate tiny_keccak;
|
extern crate tiny_keccak;
|
||||||
extern crate tempdir;
|
extern crate tempdir;
|
||||||
|
|
||||||
extern crate ethcore_crypto as crypto;
|
extern crate parity_crypto as crypto;
|
||||||
extern crate ethereum_types;
|
extern crate ethereum_types;
|
||||||
extern crate ethkey as _ethkey;
|
extern crate ethkey as _ethkey;
|
||||||
extern crate parity_wordlist;
|
extern crate parity_wordlist;
|
||||||
@@ -1,11 +1,24 @@
|
|||||||
|
// Copyright 2015-2019 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity Ethereum.
|
||||||
|
|
||||||
|
// Parity Ethereum is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity Ethereum is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use rcrypto::pbkdf2::pbkdf2;
|
|
||||||
use rcrypto::sha2::Sha256;
|
|
||||||
use rcrypto::hmac::Hmac;
|
|
||||||
use json;
|
use json;
|
||||||
use ethkey::{Address, Secret, KeyPair};
|
use ethkey::{Address, Secret, KeyPair, Password};
|
||||||
use crypto::Keccak256;
|
use crypto::{Keccak256, pbkdf2};
|
||||||
use {crypto, Error};
|
use {crypto, Error};
|
||||||
|
|
||||||
/// Pre-sale wallet.
|
/// Pre-sale wallet.
|
||||||
@@ -41,13 +54,15 @@ impl PresaleWallet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Decrypt the wallet.
|
/// Decrypt the wallet.
|
||||||
pub fn decrypt(&self, password: &str) -> Result<KeyPair, Error> {
|
pub fn decrypt(&self, password: &Password) -> Result<KeyPair, Error> {
|
||||||
let mut h_mac = Hmac::new(Sha256::new(), password.as_bytes());
|
let mut derived_key = [0u8; 32];
|
||||||
let mut derived_key = vec![0u8; 16];
|
let salt = pbkdf2::Salt(password.as_bytes());
|
||||||
pbkdf2(&mut h_mac, password.as_bytes(), 2000, &mut derived_key);
|
let sec = pbkdf2::Secret(password.as_bytes());
|
||||||
|
pbkdf2::sha256(2000, salt, sec, &mut derived_key);
|
||||||
|
|
||||||
let mut key = vec![0; self.ciphertext.len()];
|
let mut key = vec![0; self.ciphertext.len()];
|
||||||
let len = crypto::aes::decrypt_cbc(&derived_key, &self.iv, &self.ciphertext, &mut key).map_err(|_| Error::InvalidPassword)?;
|
let len = crypto::aes::decrypt_128_cbc(&derived_key[0..16], &self.iv, &self.ciphertext, &mut key)
|
||||||
|
.map_err(|_| Error::InvalidPassword)?;
|
||||||
let unpadded = &key[..len];
|
let unpadded = &key[..len];
|
||||||
|
|
||||||
let secret = Secret::from_unsafe_slice(&unpadded.keccak256())?;
|
let secret = Secret::from_unsafe_slice(&unpadded.keccak256())?;
|
||||||
@@ -78,7 +93,7 @@ mod tests {
|
|||||||
|
|
||||||
let wallet = json::PresaleWallet::load(json.as_bytes()).unwrap();
|
let wallet = json::PresaleWallet::load(json.as_bytes()).unwrap();
|
||||||
let wallet = PresaleWallet::from(wallet);
|
let wallet = PresaleWallet::from(wallet);
|
||||||
assert!(wallet.decrypt("123").is_ok());
|
assert!(wallet.decrypt(&"123".into()).is_ok());
|
||||||
assert!(wallet.decrypt("124").is_err());
|
assert!(wallet.decrypt(&"124".into()).is_err());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,18 +1,18 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
// Copyright 2015-2019 Parity Technologies (UK) Ltd.
|
||||||
// This file is part of Parity.
|
// This file is part of Parity Ethereum.
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
// Parity Ethereum is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
// Parity Ethereum is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use rand::{Rng, OsRng};
|
use rand::{Rng, OsRng};
|
||||||
|
|
||||||
@@ -43,4 +43,3 @@ pub fn random_string(length: usize) -> String {
|
|||||||
let mut rng = OsRng::new().expect("Not able to operate without random source.");
|
let mut rng = OsRng::new().expect("Not able to operate without random source.");
|
||||||
rng.gen_ascii_chars().take(length).collect()
|
rng.gen_ascii_chars().take(length).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1,23 +1,23 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
// Copyright 2015-2019 Parity Technologies (UK) Ltd.
|
||||||
// This file is part of Parity.
|
// This file is part of Parity Ethereum.
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
// Parity Ethereum is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
// Parity Ethereum is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use ethkey::{Address, Message, Signature, Secret, Public};
|
use ethkey::{Address, Message, Signature, Secret, Password, Public};
|
||||||
use Error;
|
use Error;
|
||||||
use json::{Uuid, OpaqueKeyFile};
|
use json::{Uuid, OpaqueKeyFile};
|
||||||
use ethereum_types::H256;
|
use ethereum_types::H256;
|
||||||
@@ -56,25 +56,25 @@ impl ::std::borrow::Borrow<Address> for StoreAccountRef {
|
|||||||
/// Simple Secret Store API
|
/// Simple Secret Store API
|
||||||
pub trait SimpleSecretStore: Send + Sync {
|
pub trait SimpleSecretStore: Send + Sync {
|
||||||
/// Inserts new accounts to the store (or vault) with given password.
|
/// Inserts new accounts to the store (or vault) with given password.
|
||||||
fn insert_account(&self, vault: SecretVaultRef, secret: Secret, password: &str) -> Result<StoreAccountRef, Error>;
|
fn insert_account(&self, vault: SecretVaultRef, secret: Secret, password: &Password) -> Result<StoreAccountRef, Error>;
|
||||||
/// Inserts new derived account to the store (or vault) with given password.
|
/// Inserts new derived account to the store (or vault) with given password.
|
||||||
fn insert_derived(&self, vault: SecretVaultRef, account_ref: &StoreAccountRef, password: &str, derivation: Derivation) -> Result<StoreAccountRef, Error>;
|
fn insert_derived(&self, vault: SecretVaultRef, account_ref: &StoreAccountRef, password: &Password, derivation: Derivation) -> Result<StoreAccountRef, Error>;
|
||||||
/// Changes accounts password.
|
/// Changes accounts password.
|
||||||
fn change_password(&self, account: &StoreAccountRef, old_password: &str, new_password: &str) -> Result<(), Error>;
|
fn change_password(&self, account: &StoreAccountRef, old_password: &Password, new_password: &Password) -> Result<(), Error>;
|
||||||
/// Exports key details for account.
|
/// Exports key details for account.
|
||||||
fn export_account(&self, account: &StoreAccountRef, password: &str) -> Result<OpaqueKeyFile, Error>;
|
fn export_account(&self, account: &StoreAccountRef, password: &Password) -> Result<OpaqueKeyFile, Error>;
|
||||||
/// Entirely removes account from the store and underlying storage.
|
/// Entirely removes account from the store and underlying storage.
|
||||||
fn remove_account(&self, account: &StoreAccountRef, password: &str) -> Result<(), Error>;
|
fn remove_account(&self, account: &StoreAccountRef, password: &Password) -> Result<(), Error>;
|
||||||
/// Generates new derived account.
|
/// Generates new derived account.
|
||||||
fn generate_derived(&self, account_ref: &StoreAccountRef, password: &str, derivation: Derivation) -> Result<Address, Error>;
|
fn generate_derived(&self, account_ref: &StoreAccountRef, password: &Password, derivation: Derivation) -> Result<Address, Error>;
|
||||||
/// Sign a message with given account.
|
/// Sign a message with given account.
|
||||||
fn sign(&self, account: &StoreAccountRef, password: &str, message: &Message) -> Result<Signature, Error>;
|
fn sign(&self, account: &StoreAccountRef, password: &Password, message: &Message) -> Result<Signature, Error>;
|
||||||
/// Sign a message with derived account.
|
/// Sign a message with derived account.
|
||||||
fn sign_derived(&self, account_ref: &StoreAccountRef, password: &str, derivation: Derivation, message: &Message) -> Result<Signature, Error>;
|
fn sign_derived(&self, account_ref: &StoreAccountRef, password: &Password, derivation: Derivation, message: &Message) -> Result<Signature, Error>;
|
||||||
/// Decrypt a messages with given account.
|
/// Decrypt a messages with given account.
|
||||||
fn decrypt(&self, account: &StoreAccountRef, password: &str, shared_mac: &[u8], message: &[u8]) -> Result<Vec<u8>, Error>;
|
fn decrypt(&self, account: &StoreAccountRef, password: &Password, shared_mac: &[u8], message: &[u8]) -> Result<Vec<u8>, Error>;
|
||||||
/// Agree on shared key.
|
/// Agree on shared key.
|
||||||
fn agree(&self, account: &StoreAccountRef, password: &str, other: &Public) -> Result<Secret, Error>;
|
fn agree(&self, account: &StoreAccountRef, password: &Password, other: &Public) -> Result<Secret, Error>;
|
||||||
|
|
||||||
/// Returns all accounts in this secret store.
|
/// Returns all accounts in this secret store.
|
||||||
fn accounts(&self) -> Result<Vec<StoreAccountRef>, Error>;
|
fn accounts(&self) -> Result<Vec<StoreAccountRef>, Error>;
|
||||||
@@ -83,9 +83,9 @@ pub trait SimpleSecretStore: Send + Sync {
|
|||||||
fn account_ref(&self, address: &Address) -> Result<StoreAccountRef, Error>;
|
fn account_ref(&self, address: &Address) -> Result<StoreAccountRef, Error>;
|
||||||
|
|
||||||
/// Create new vault with given password
|
/// Create new vault with given password
|
||||||
fn create_vault(&self, name: &str, password: &str) -> Result<(), Error>;
|
fn create_vault(&self, name: &str, password: &Password) -> Result<(), Error>;
|
||||||
/// Open vault with given password
|
/// Open vault with given password
|
||||||
fn open_vault(&self, name: &str, password: &str) -> Result<(), Error>;
|
fn open_vault(&self, name: &str, password: &Password) -> Result<(), Error>;
|
||||||
/// Close vault
|
/// Close vault
|
||||||
fn close_vault(&self, name: &str) -> Result<(), Error>;
|
fn close_vault(&self, name: &str) -> Result<(), Error>;
|
||||||
/// List all vaults
|
/// List all vaults
|
||||||
@@ -93,7 +93,7 @@ pub trait SimpleSecretStore: Send + Sync {
|
|||||||
/// List all currently opened vaults
|
/// List all currently opened vaults
|
||||||
fn list_opened_vaults(&self) -> Result<Vec<String>, Error>;
|
fn list_opened_vaults(&self) -> Result<Vec<String>, Error>;
|
||||||
/// Change vault password
|
/// Change vault password
|
||||||
fn change_vault_password(&self, name: &str, new_password: &str) -> Result<(), Error>;
|
fn change_vault_password(&self, name: &str, new_password: &Password) -> Result<(), Error>;
|
||||||
/// Cnage account' vault
|
/// Cnage account' vault
|
||||||
fn change_account_vault(&self, vault: SecretVaultRef, account: StoreAccountRef) -> Result<StoreAccountRef, Error>;
|
fn change_account_vault(&self, vault: SecretVaultRef, account: StoreAccountRef) -> Result<StoreAccountRef, Error>;
|
||||||
/// Get vault metadata string.
|
/// Get vault metadata string.
|
||||||
@@ -106,7 +106,7 @@ pub trait SimpleSecretStore: Send + Sync {
|
|||||||
pub trait SecretStore: SimpleSecretStore {
|
pub trait SecretStore: SimpleSecretStore {
|
||||||
|
|
||||||
/// Returns a raw opaque Secret that can be later used to sign a message.
|
/// Returns a raw opaque Secret that can be later used to sign a message.
|
||||||
fn raw_secret(&self, account: &StoreAccountRef, password: &str) -> Result<OpaqueSecret, Error>;
|
fn raw_secret(&self, account: &StoreAccountRef, password: &Password) -> Result<OpaqueSecret, Error>;
|
||||||
|
|
||||||
/// Signs a message with raw secret.
|
/// Signs a message with raw secret.
|
||||||
fn sign_with_secret(&self, secret: &OpaqueSecret, message: &Message) -> Result<Signature, Error> {
|
fn sign_with_secret(&self, secret: &OpaqueSecret, message: &Message) -> Result<Signature, Error> {
|
||||||
@@ -114,16 +114,16 @@ pub trait SecretStore: SimpleSecretStore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Imports presale wallet
|
/// Imports presale wallet
|
||||||
fn import_presale(&self, vault: SecretVaultRef, json: &[u8], password: &str) -> Result<StoreAccountRef, Error>;
|
fn import_presale(&self, vault: SecretVaultRef, json: &[u8], password: &Password) -> Result<StoreAccountRef, Error>;
|
||||||
/// Imports existing JSON wallet
|
/// Imports existing JSON wallet
|
||||||
fn import_wallet(&self, vault: SecretVaultRef, json: &[u8], password: &str, gen_id: bool) -> Result<StoreAccountRef, Error>;
|
fn import_wallet(&self, vault: SecretVaultRef, json: &[u8], password: &Password, gen_id: bool) -> Result<StoreAccountRef, Error>;
|
||||||
/// Copies account between stores and vaults.
|
/// Copies account between stores and vaults.
|
||||||
fn copy_account(&self, new_store: &SimpleSecretStore, new_vault: SecretVaultRef, account: &StoreAccountRef, password: &str, new_password: &str) -> Result<(), Error>;
|
fn copy_account(&self, new_store: &SimpleSecretStore, new_vault: SecretVaultRef, account: &StoreAccountRef, password: &Password, new_password: &Password) -> Result<(), Error>;
|
||||||
/// Checks if password matches given account.
|
/// Checks if password matches given account.
|
||||||
fn test_password(&self, account: &StoreAccountRef, password: &str) -> Result<bool, Error>;
|
fn test_password(&self, account: &StoreAccountRef, password: &Password) -> Result<bool, Error>;
|
||||||
|
|
||||||
/// Returns a public key for given account.
|
/// Returns a public key for given account.
|
||||||
fn public(&self, account: &StoreAccountRef, password: &str) -> Result<Public, Error>;
|
fn public(&self, account: &StoreAccountRef, password: &Password) -> Result<Public, Error>;
|
||||||
|
|
||||||
/// Returns uuid of an account.
|
/// Returns uuid of an account.
|
||||||
fn uuid(&self, account: &StoreAccountRef) -> Result<Uuid, Error>;
|
fn uuid(&self, account: &StoreAccountRef) -> Result<Uuid, Error>;
|
||||||
@@ -1,18 +1,18 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
// Copyright 2015-2019 Parity Technologies (UK) Ltd.
|
||||||
// This file is part of Parity.
|
// This file is part of Parity Ethereum.
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
// Parity Ethereum is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
// Parity Ethereum is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
extern crate rand;
|
extern crate rand;
|
||||||
extern crate ethstore;
|
extern crate ethstore;
|
||||||
@@ -46,9 +46,9 @@ fn secret_store_create_account() {
|
|||||||
let dir = TransientDir::create().unwrap();
|
let dir = TransientDir::create().unwrap();
|
||||||
let store = EthStore::open(Box::new(dir)).unwrap();
|
let store = EthStore::open(Box::new(dir)).unwrap();
|
||||||
assert_eq!(store.accounts().unwrap().len(), 0);
|
assert_eq!(store.accounts().unwrap().len(), 0);
|
||||||
assert!(store.insert_account(SecretVaultRef::Root, random_secret(), "").is_ok());
|
assert!(store.insert_account(SecretVaultRef::Root, random_secret(), &"".into()).is_ok());
|
||||||
assert_eq!(store.accounts().unwrap().len(), 1);
|
assert_eq!(store.accounts().unwrap().len(), 1);
|
||||||
assert!(store.insert_account(SecretVaultRef::Root, random_secret(), "").is_ok());
|
assert!(store.insert_account(SecretVaultRef::Root, random_secret(), &"".into()).is_ok());
|
||||||
assert_eq!(store.accounts().unwrap().len(), 2);
|
assert_eq!(store.accounts().unwrap().len(), 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,36 +56,36 @@ fn secret_store_create_account() {
|
|||||||
fn secret_store_sign() {
|
fn secret_store_sign() {
|
||||||
let dir = TransientDir::create().unwrap();
|
let dir = TransientDir::create().unwrap();
|
||||||
let store = EthStore::open(Box::new(dir)).unwrap();
|
let store = EthStore::open(Box::new(dir)).unwrap();
|
||||||
assert!(store.insert_account(SecretVaultRef::Root, random_secret(), "").is_ok());
|
assert!(store.insert_account(SecretVaultRef::Root, random_secret(), &"".into()).is_ok());
|
||||||
let accounts = store.accounts().unwrap();
|
let accounts = store.accounts().unwrap();
|
||||||
assert_eq!(accounts.len(), 1);
|
assert_eq!(accounts.len(), 1);
|
||||||
assert!(store.sign(&accounts[0], "", &Default::default()).is_ok());
|
assert!(store.sign(&accounts[0], &"".into(), &Default::default()).is_ok());
|
||||||
assert!(store.sign(&accounts[0], "1", &Default::default()).is_err());
|
assert!(store.sign(&accounts[0], &"1".into(), &Default::default()).is_err());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn secret_store_change_password() {
|
fn secret_store_change_password() {
|
||||||
let dir = TransientDir::create().unwrap();
|
let dir = TransientDir::create().unwrap();
|
||||||
let store = EthStore::open(Box::new(dir)).unwrap();
|
let store = EthStore::open(Box::new(dir)).unwrap();
|
||||||
assert!(store.insert_account(SecretVaultRef::Root, random_secret(), "").is_ok());
|
assert!(store.insert_account(SecretVaultRef::Root, random_secret(), &"".into()).is_ok());
|
||||||
let accounts = store.accounts().unwrap();
|
let accounts = store.accounts().unwrap();
|
||||||
assert_eq!(accounts.len(), 1);
|
assert_eq!(accounts.len(), 1);
|
||||||
assert!(store.sign(&accounts[0], "", &Default::default()).is_ok());
|
assert!(store.sign(&accounts[0], &"".into(), &Default::default()).is_ok());
|
||||||
assert!(store.change_password(&accounts[0], "", "1").is_ok());
|
assert!(store.change_password(&accounts[0], &"".into(), &"1".into()).is_ok());
|
||||||
assert!(store.sign(&accounts[0], "", &Default::default()).is_err());
|
assert!(store.sign(&accounts[0], &"".into(), &Default::default()).is_err());
|
||||||
assert!(store.sign(&accounts[0], "1", &Default::default()).is_ok());
|
assert!(store.sign(&accounts[0], &"1".into(), &Default::default()).is_ok());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn secret_store_remove_account() {
|
fn secret_store_remove_account() {
|
||||||
let dir = TransientDir::create().unwrap();
|
let dir = TransientDir::create().unwrap();
|
||||||
let store = EthStore::open(Box::new(dir)).unwrap();
|
let store = EthStore::open(Box::new(dir)).unwrap();
|
||||||
assert!(store.insert_account(SecretVaultRef::Root, random_secret(), "").is_ok());
|
assert!(store.insert_account(SecretVaultRef::Root, random_secret(), &"".into()).is_ok());
|
||||||
let accounts = store.accounts().unwrap();
|
let accounts = store.accounts().unwrap();
|
||||||
assert_eq!(accounts.len(), 1);
|
assert_eq!(accounts.len(), 1);
|
||||||
assert!(store.remove_account(&accounts[0], "").is_ok());
|
assert!(store.remove_account(&accounts[0], &"".into()).is_ok());
|
||||||
assert_eq!(store.accounts().unwrap().len(), 0);
|
assert_eq!(store.accounts().unwrap().len(), 0);
|
||||||
assert!(store.remove_account(&accounts[0], "").is_err());
|
assert!(store.remove_account(&accounts[0], &"".into()).is_err());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_path() -> &'static str {
|
fn test_path() -> &'static str {
|
||||||
@@ -146,8 +146,8 @@ fn test_decrypting_files_with_short_ciphertext() {
|
|||||||
|
|
||||||
let message = Default::default();
|
let message = Default::default();
|
||||||
|
|
||||||
let s1 = store.sign(&accounts[0], "foo", &message).unwrap();
|
let s1 = store.sign(&accounts[0], &"foo".into(), &message).unwrap();
|
||||||
let s2 = store.sign(&accounts[1], "foo", &message).unwrap();
|
let s2 = store.sign(&accounts[1], &"foo".into(), &message).unwrap();
|
||||||
assert!(verify_address(&accounts[0].address, &s1, &message).unwrap());
|
assert!(verify_address(&accounts[0].address, &s1, &message).unwrap());
|
||||||
assert!(verify_address(&kp1.address(), &s1, &message).unwrap());
|
assert!(verify_address(&kp1.address(), &s1, &message).unwrap());
|
||||||
assert!(verify_address(&kp2.address(), &s2, &message).unwrap());
|
assert!(verify_address(&kp2.address(), &s2, &message).unwrap());
|
||||||
@@ -1,18 +1,18 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
// Copyright 2015-2019 Parity Technologies (UK) Ltd.
|
||||||
// This file is part of Parity.
|
// This file is part of Parity Ethereum.
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
// Parity Ethereum is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
// Parity Ethereum is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
mod transient_dir;
|
mod transient_dir;
|
||||||
|
|
||||||
@@ -1,18 +1,18 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
// Copyright 2015-2019 Parity Technologies (UK) Ltd.
|
||||||
// This file is part of Parity.
|
// This file is part of Parity Ethereum.
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
// Parity Ethereum is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
// Parity Ethereum is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::{env, fs};
|
use std::{env, fs};
|
||||||
10
accounts/fake-hardware-wallet/Cargo.toml
Normal file
10
accounts/fake-hardware-wallet/Cargo.toml
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
[package]
|
||||||
|
description = "Fake hardware-wallet, for OS' that don't support libusb"
|
||||||
|
name = "fake-hardware-wallet"
|
||||||
|
version = "0.0.1"
|
||||||
|
license = "GPL-3.0"
|
||||||
|
authors = ["Parity Technologies <admin@parity.io>"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
ethereum-types = "0.4"
|
||||||
|
ethkey = { path = "../../accounts/ethkey" }
|
||||||
101
accounts/fake-hardware-wallet/src/lib.rs
Normal file
101
accounts/fake-hardware-wallet/src/lib.rs
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
// Copyright 2015-2019 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity Ethereum.
|
||||||
|
|
||||||
|
// Parity Ethereum is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity Ethereum is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
//! Dummy module for platforms that does not provide support for hardware wallets (libusb)
|
||||||
|
|
||||||
|
extern crate ethereum_types;
|
||||||
|
extern crate ethkey;
|
||||||
|
|
||||||
|
use std::fmt;
|
||||||
|
use ethereum_types::U256;
|
||||||
|
use ethkey::{Address, Signature};
|
||||||
|
|
||||||
|
pub struct WalletInfo {
|
||||||
|
pub address: Address,
|
||||||
|
pub name: String,
|
||||||
|
pub manufacturer: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
/// `ErrorType` for devices with no `hardware wallet`
|
||||||
|
pub enum Error {
|
||||||
|
NoWallet,
|
||||||
|
KeyNotFound,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct TransactionInfo {
|
||||||
|
/// Nonce
|
||||||
|
pub nonce: U256,
|
||||||
|
/// Gas price
|
||||||
|
pub gas_price: U256,
|
||||||
|
/// Gas limit
|
||||||
|
pub gas_limit: U256,
|
||||||
|
/// Receiver
|
||||||
|
pub to: Option<Address>,
|
||||||
|
/// Value
|
||||||
|
pub value: U256,
|
||||||
|
/// Data
|
||||||
|
pub data: Vec<u8>,
|
||||||
|
/// Chain ID
|
||||||
|
pub chain_id: Option<u64>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum KeyPath {
|
||||||
|
/// Ethereum.
|
||||||
|
Ethereum,
|
||||||
|
/// Ethereum classic.
|
||||||
|
EthereumClassic,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// `HardwareWalletManager` for devices with no `hardware wallet`
|
||||||
|
pub struct HardwareWalletManager;
|
||||||
|
|
||||||
|
impl HardwareWalletManager {
|
||||||
|
pub fn new() -> Result<Self, Error> {
|
||||||
|
Err(Error::NoWallet)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_key_path(&self, _key_path: KeyPath) {}
|
||||||
|
|
||||||
|
pub fn wallet_info(&self, _: &Address) -> Option<WalletInfo> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn list_wallets(&self) -> Vec<WalletInfo> {
|
||||||
|
Vec::with_capacity(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn list_locked_wallets(&self) -> Result<Vec<String>, Error> {
|
||||||
|
Err(Error::NoWallet)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pin_matrix_ack(&self, _: &str, _: &str) -> Result<bool, Error> {
|
||||||
|
Err(Error::NoWallet)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sign_transaction(&self, _address: &Address, _transaction: &TransactionInfo, _rlp_transaction: &[u8]) -> Result<Signature, Error> {
|
||||||
|
Err(Error::NoWallet) }
|
||||||
|
|
||||||
|
pub fn sign_message(&self, _address: &Address, _msg: &[u8]) -> Result<Signature, Error> {
|
||||||
|
Err(Error::NoWallet)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Error {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(f, "No hardware wallet!!")
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,18 +3,19 @@ description = "Hardware wallet support."
|
|||||||
homepage = "http://parity.io"
|
homepage = "http://parity.io"
|
||||||
license = "GPL-3.0"
|
license = "GPL-3.0"
|
||||||
name = "hardware-wallet"
|
name = "hardware-wallet"
|
||||||
version = "1.11.0"
|
version = "1.12.0"
|
||||||
authors = ["Parity Technologies <admin@parity.io>"]
|
authors = ["Parity Technologies <admin@parity.io>"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
log = "0.3"
|
log = "0.4"
|
||||||
parking_lot = "0.5"
|
parking_lot = "0.7"
|
||||||
protobuf = "1.4"
|
protobuf = "1.4"
|
||||||
hidapi = { git = "https://github.com/paritytech/hidapi-rs" }
|
hidapi = { git = "https://github.com/paritytech/hidapi-rs" }
|
||||||
libusb = { git = "https://github.com/paritytech/libusb-rs" }
|
libusb = { git = "https://github.com/paritytech/libusb-rs" }
|
||||||
trezor-sys = { git = "https://github.com/paritytech/trezor-sys" }
|
trezor-sys = { git = "https://github.com/paritytech/trezor-sys" }
|
||||||
ethkey = { path = "../ethkey" }
|
ethkey = { path = "../ethkey" }
|
||||||
ethereum-types = "0.3"
|
ethereum-types = "0.4"
|
||||||
|
semver = "0.9"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
rustc-hex = "1.0"
|
rustc-hex = "1.0"
|
||||||
534
accounts/hw/src/ledger.rs
Normal file
534
accounts/hw/src/ledger.rs
Normal file
File diff suppressed because one or more lines are too long
402
accounts/hw/src/lib.rs
Normal file
402
accounts/hw/src/lib.rs
Normal file
@@ -0,0 +1,402 @@
|
|||||||
|
// Copyright 2015-2019 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity Ethereum.
|
||||||
|
|
||||||
|
// Parity Ethereum is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity Ethereum is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
//! Hardware wallet management.
|
||||||
|
|
||||||
|
#![warn(missing_docs)]
|
||||||
|
#![warn(warnings)]
|
||||||
|
|
||||||
|
extern crate ethereum_types;
|
||||||
|
extern crate ethkey;
|
||||||
|
extern crate hidapi;
|
||||||
|
extern crate libusb;
|
||||||
|
extern crate parking_lot;
|
||||||
|
extern crate protobuf;
|
||||||
|
extern crate semver;
|
||||||
|
extern crate trezor_sys;
|
||||||
|
|
||||||
|
#[macro_use] extern crate log;
|
||||||
|
#[cfg(test)] extern crate rustc_hex;
|
||||||
|
|
||||||
|
mod ledger;
|
||||||
|
mod trezor;
|
||||||
|
|
||||||
|
use std::sync::{Arc, atomic, atomic::AtomicBool, Weak};
|
||||||
|
use std::{fmt, time::Duration};
|
||||||
|
use std::thread;
|
||||||
|
|
||||||
|
use ethereum_types::U256;
|
||||||
|
use ethkey::{Address, Signature};
|
||||||
|
use parking_lot::Mutex;
|
||||||
|
|
||||||
|
const HID_GLOBAL_USAGE_PAGE: u16 = 0xFF00;
|
||||||
|
const HID_USB_DEVICE_CLASS: u8 = 0;
|
||||||
|
const MAX_POLLING_DURATION: Duration = Duration::from_millis(500);
|
||||||
|
const USB_EVENT_POLLING_INTERVAL: Duration = Duration::from_millis(500);
|
||||||
|
|
||||||
|
/// `HardwareWallet` device
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Device {
|
||||||
|
path: String,
|
||||||
|
info: WalletInfo,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// `Wallet` trait
|
||||||
|
pub trait Wallet<'a> {
|
||||||
|
/// Error
|
||||||
|
type Error;
|
||||||
|
/// Transaction data format
|
||||||
|
type Transaction;
|
||||||
|
|
||||||
|
/// Sign transaction data with wallet managing `address`.
|
||||||
|
fn sign_transaction(&self, address: &Address, transaction: Self::Transaction) -> Result<Signature, Self::Error>;
|
||||||
|
|
||||||
|
/// Set key derivation path for a chain.
|
||||||
|
fn set_key_path(&self, key_path: KeyPath);
|
||||||
|
|
||||||
|
/// Re-populate device list
|
||||||
|
/// Note, this assumes all devices are iterated over and updated
|
||||||
|
fn update_devices(&self, device_direction: DeviceDirection) -> Result<usize, Self::Error>;
|
||||||
|
|
||||||
|
/// Read device info
|
||||||
|
fn read_device(&self, usb: &hidapi::HidApi, dev_info: &hidapi::HidDeviceInfo) -> Result<Device, Self::Error>;
|
||||||
|
|
||||||
|
/// List connected and acknowledged wallets
|
||||||
|
fn list_devices(&self) -> Vec<WalletInfo>;
|
||||||
|
|
||||||
|
/// List locked wallets
|
||||||
|
/// This may be moved if it is the wrong assumption, for example this is not supported by Ledger
|
||||||
|
/// Then this method return a empty vector
|
||||||
|
fn list_locked_devices(&self) -> Vec<String>;
|
||||||
|
|
||||||
|
/// Get wallet info.
|
||||||
|
fn get_wallet(&self, address: &Address) -> Option<WalletInfo>;
|
||||||
|
|
||||||
|
/// Generate ethereum address for a Wallet
|
||||||
|
fn get_address(&self, device: &hidapi::HidDevice) -> Result<Option<Address>, Self::Error>;
|
||||||
|
|
||||||
|
/// Open a device using `device path`
|
||||||
|
/// Note, f - is a closure that borrows HidResult<HidDevice>
|
||||||
|
/// HidDevice is in turn a type alias for a `c_void function pointer`
|
||||||
|
/// For further information see:
|
||||||
|
/// * <https://github.com/paritytech/hidapi-rs>
|
||||||
|
/// * <https://github.com/rust-lang/libc>
|
||||||
|
fn open_path<R, F>(&self, f: F) -> Result<R, Self::Error>
|
||||||
|
where F: Fn() -> Result<R, &'static str>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Hardware wallet error.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Error {
|
||||||
|
/// Ledger device error.
|
||||||
|
LedgerDevice(ledger::Error),
|
||||||
|
/// Trezor device error
|
||||||
|
TrezorDevice(trezor::Error),
|
||||||
|
/// USB error.
|
||||||
|
Usb(libusb::Error),
|
||||||
|
/// HID error
|
||||||
|
Hid(String),
|
||||||
|
/// Hardware wallet not found for specified key.
|
||||||
|
KeyNotFound,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This is the transaction info we need to supply to Trezor message. It's more
|
||||||
|
/// or less a duplicate of `ethcore::transaction::Transaction`, but we can't
|
||||||
|
/// import ethcore here as that would be a circular dependency.
|
||||||
|
pub struct TransactionInfo {
|
||||||
|
/// Nonce
|
||||||
|
pub nonce: U256,
|
||||||
|
/// Gas price
|
||||||
|
pub gas_price: U256,
|
||||||
|
/// Gas limit
|
||||||
|
pub gas_limit: U256,
|
||||||
|
/// Receiver
|
||||||
|
pub to: Option<Address>,
|
||||||
|
/// Value
|
||||||
|
pub value: U256,
|
||||||
|
/// Data
|
||||||
|
pub data: Vec<u8>,
|
||||||
|
/// Chain ID
|
||||||
|
pub chain_id: Option<u64>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Hardware wallet information.
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct WalletInfo {
|
||||||
|
/// Wallet device name.
|
||||||
|
pub name: String,
|
||||||
|
/// Wallet device manufacturer.
|
||||||
|
pub manufacturer: String,
|
||||||
|
/// Wallet device serial number.
|
||||||
|
pub serial: String,
|
||||||
|
/// Ethereum address.
|
||||||
|
pub address: Address,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Key derivation paths used on hardware wallets.
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub enum KeyPath {
|
||||||
|
/// Ethereum.
|
||||||
|
Ethereum,
|
||||||
|
/// Ethereum classic.
|
||||||
|
EthereumClassic,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Error {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
||||||
|
match *self {
|
||||||
|
Error::KeyNotFound => write!(f, "Key not found for given address."),
|
||||||
|
Error::LedgerDevice(ref e) => write!(f, "{}", e),
|
||||||
|
Error::TrezorDevice(ref e) => write!(f, "{}", e),
|
||||||
|
Error::Usb(ref e) => write!(f, "{}", e),
|
||||||
|
Error::Hid(ref e) => write!(f, "{}", e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ledger::Error> for Error {
|
||||||
|
fn from(err: ledger::Error) -> Self {
|
||||||
|
match err {
|
||||||
|
ledger::Error::KeyNotFound => Error::KeyNotFound,
|
||||||
|
_ => Error::LedgerDevice(err),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<trezor::Error> for Error {
|
||||||
|
fn from(err: trezor::Error) -> Self {
|
||||||
|
match err {
|
||||||
|
trezor::Error::KeyNotFound => Error::KeyNotFound,
|
||||||
|
_ => Error::TrezorDevice(err),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<libusb::Error> for Error {
|
||||||
|
fn from(err: libusb::Error) -> Self {
|
||||||
|
Error::Usb(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Specifies the direction of the `HardwareWallet` i.e, whether it arrived or left
|
||||||
|
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||||
|
pub enum DeviceDirection {
|
||||||
|
/// Device arrived
|
||||||
|
Arrived,
|
||||||
|
/// Device left
|
||||||
|
Left,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for DeviceDirection {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
DeviceDirection::Arrived => write!(f, "arrived"),
|
||||||
|
DeviceDirection::Left => write!(f, "left"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Hardware wallet management interface.
|
||||||
|
pub struct HardwareWalletManager {
|
||||||
|
exiting: Arc<AtomicBool>,
|
||||||
|
ledger: Arc<ledger::Manager>,
|
||||||
|
trezor: Arc<trezor::Manager>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HardwareWalletManager {
|
||||||
|
/// Hardware wallet constructor
|
||||||
|
pub fn new() -> Result<Self, Error> {
|
||||||
|
let exiting = Arc::new(AtomicBool::new(false));
|
||||||
|
let hidapi = Arc::new(Mutex::new(hidapi::HidApi::new().map_err(|e| Error::Hid(e.to_string().clone()))?));
|
||||||
|
let ledger = ledger::Manager::new(hidapi.clone());
|
||||||
|
let trezor = trezor::Manager::new(hidapi.clone());
|
||||||
|
let usb_context = Arc::new(libusb::Context::new()?);
|
||||||
|
|
||||||
|
let l = ledger.clone();
|
||||||
|
let t = trezor.clone();
|
||||||
|
let exit = exiting.clone();
|
||||||
|
|
||||||
|
// Subscribe to all vendor IDs (VIDs) and product IDs (PIDs)
|
||||||
|
// This means that the `HardwareWalletManager` is responsible to validate the detected device
|
||||||
|
usb_context.register_callback(
|
||||||
|
None, None, Some(HID_USB_DEVICE_CLASS),
|
||||||
|
Box::new(EventHandler::new(
|
||||||
|
Arc::downgrade(&ledger),
|
||||||
|
Arc::downgrade(&trezor)
|
||||||
|
))
|
||||||
|
)?;
|
||||||
|
|
||||||
|
// Hardware event subscriber thread
|
||||||
|
thread::Builder::new()
|
||||||
|
.name("hw_wallet_manager".to_string())
|
||||||
|
.spawn(move || {
|
||||||
|
if let Err(e) = l.update_devices(DeviceDirection::Arrived) {
|
||||||
|
debug!(target: "hw", "Ledger couldn't connect at startup, error: {}", e);
|
||||||
|
}
|
||||||
|
if let Err(e) = t.update_devices(DeviceDirection::Arrived) {
|
||||||
|
debug!(target: "hw", "Trezor couldn't connect at startup, error: {}", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
while !exit.load(atomic::Ordering::Acquire) {
|
||||||
|
if let Err(e) = usb_context.handle_events(Some(USB_EVENT_POLLING_INTERVAL)) {
|
||||||
|
debug!(target: "hw", "HardwareWalletManager event handler error: {}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.ok();
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
exiting,
|
||||||
|
trezor,
|
||||||
|
ledger,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Select key derivation path for a chain.
|
||||||
|
/// Currently, only one hard-coded keypath is supported
|
||||||
|
/// It is managed by `ethcore/account_provider`
|
||||||
|
pub fn set_key_path(&self, key_path: KeyPath) {
|
||||||
|
self.ledger.set_key_path(key_path);
|
||||||
|
self.trezor.set_key_path(key_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// List connected wallets. This only returns wallets that are ready to be used.
|
||||||
|
pub fn list_wallets(&self) -> Vec<WalletInfo> {
|
||||||
|
let mut wallets = Vec::new();
|
||||||
|
wallets.extend(self.ledger.list_devices());
|
||||||
|
wallets.extend(self.trezor.list_devices());
|
||||||
|
wallets
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return a list of paths to locked hardware wallets
|
||||||
|
/// This is only applicable to Trezor because Ledger only appears as
|
||||||
|
/// a device when it is unlocked
|
||||||
|
pub fn list_locked_wallets(&self) -> Result<Vec<String>, Error> {
|
||||||
|
Ok(self.trezor.list_locked_devices())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get connected wallet info.
|
||||||
|
pub fn wallet_info(&self, address: &Address) -> Option<WalletInfo> {
|
||||||
|
if let Some(info) = self.ledger.get_wallet(address) {
|
||||||
|
Some(info)
|
||||||
|
} else {
|
||||||
|
self.trezor.get_wallet(address)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sign a message with the wallet (only supported by Ledger)
|
||||||
|
pub fn sign_message(&self, address: &Address, msg: &[u8]) -> Result<Signature, Error> {
|
||||||
|
if self.ledger.get_wallet(address).is_some() {
|
||||||
|
Ok(self.ledger.sign_message(address, msg)?)
|
||||||
|
} else if self.trezor.get_wallet(address).is_some() {
|
||||||
|
Err(Error::TrezorDevice(trezor::Error::NoSigningMessage))
|
||||||
|
} else {
|
||||||
|
Err(Error::KeyNotFound)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sign transaction data with wallet managing `address`.
|
||||||
|
pub fn sign_transaction(&self, address: &Address, t_info: &TransactionInfo, encoded_transaction: &[u8]) -> Result<Signature, Error> {
|
||||||
|
if self.ledger.get_wallet(address).is_some() {
|
||||||
|
Ok(self.ledger.sign_transaction(address, encoded_transaction)?)
|
||||||
|
} else if self.trezor.get_wallet(address).is_some() {
|
||||||
|
Ok(self.trezor.sign_transaction(address, t_info)?)
|
||||||
|
} else {
|
||||||
|
Err(Error::KeyNotFound)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Send a pin to a device at a certain path to unlock it
|
||||||
|
/// This is only applicable to Trezor because Ledger only appears as
|
||||||
|
/// a device when it is unlocked
|
||||||
|
pub fn pin_matrix_ack(&self, path: &str, pin: &str) -> Result<bool, Error> {
|
||||||
|
self.trezor.pin_matrix_ack(path, pin).map_err(Error::TrezorDevice)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for HardwareWalletManager {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
// Indicate to the USB Hotplug handler that it
|
||||||
|
// shall terminate but don't wait for it to terminate.
|
||||||
|
// If it doesn't terminate for some reason USB Hotplug events will be handled
|
||||||
|
// even if the HardwareWalletManger has been dropped
|
||||||
|
self.exiting.store(true, atomic::Ordering::Release);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Hardware wallet event handler
|
||||||
|
///
|
||||||
|
/// Note, that this runs to completion and race-conditions can't occur but it can
|
||||||
|
/// stop other events for being processed with an infinite loop or similar
|
||||||
|
struct EventHandler {
|
||||||
|
ledger: Weak<ledger::Manager>,
|
||||||
|
trezor: Weak<trezor::Manager>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EventHandler {
|
||||||
|
/// Trezor event handler constructor
|
||||||
|
pub fn new(ledger: Weak<ledger::Manager>, trezor: Weak<trezor::Manager>) -> Self {
|
||||||
|
Self { ledger, trezor }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn extract_device_info(device: &libusb::Device) -> Result<(u16, u16), Error> {
|
||||||
|
let desc = device.device_descriptor()?;
|
||||||
|
Ok((desc.vendor_id(), desc.product_id()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl libusb::Hotplug for EventHandler {
|
||||||
|
fn device_arrived(&mut self, device: libusb::Device) {
|
||||||
|
// Upgrade reference to an Arc
|
||||||
|
if let (Some(ledger), Some(trezor)) = (self.ledger.upgrade(), self.trezor.upgrade()) {
|
||||||
|
// Version ID and Product ID are available
|
||||||
|
if let Ok((vid, pid)) = Self::extract_device_info(&device) {
|
||||||
|
if trezor::is_valid_trezor(vid, pid) {
|
||||||
|
if !trezor::try_connect_polling(&trezor, &MAX_POLLING_DURATION, DeviceDirection::Arrived) {
|
||||||
|
trace!(target: "hw", "Trezor device was detected but connection failed");
|
||||||
|
}
|
||||||
|
} else if ledger::is_valid_ledger(vid, pid) {
|
||||||
|
if !ledger::try_connect_polling(&ledger, &MAX_POLLING_DURATION, DeviceDirection::Arrived) {
|
||||||
|
trace!(target: "hw", "Ledger device was detected but connection failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn device_left(&mut self, device: libusb::Device) {
|
||||||
|
// Upgrade reference to an Arc
|
||||||
|
if let (Some(ledger), Some(trezor)) = (self.ledger.upgrade(), self.trezor.upgrade()) {
|
||||||
|
// Version ID and Product ID are available
|
||||||
|
if let Ok((vid, pid)) = Self::extract_device_info(&device) {
|
||||||
|
if trezor::is_valid_trezor(vid, pid) {
|
||||||
|
if !trezor::try_connect_polling(&trezor, &MAX_POLLING_DURATION, DeviceDirection::Left) {
|
||||||
|
trace!(target: "hw", "Trezor device was detected but disconnection failed");
|
||||||
|
}
|
||||||
|
} else if ledger::is_valid_ledger(vid, pid) {
|
||||||
|
if !ledger::try_connect_polling(&ledger, &MAX_POLLING_DURATION, DeviceDirection::Left) {
|
||||||
|
trace!(target: "hw", "Ledger device was detected but disconnection failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Helper to determine if a device is a valid HID
|
||||||
|
pub fn is_valid_hid_device(usage_page: u16, interface_number: i32) -> bool {
|
||||||
|
usage_page == HID_GLOBAL_USAGE_PAGE || interface_number == HID_USB_DEVICE_CLASS as i32
|
||||||
|
}
|
||||||
@@ -1,48 +1,45 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
// Copyright 2015-2019 Parity Technologies (UK) Ltd.
|
||||||
// This file is part of Parity.
|
// This file is part of Parity Ethereum.
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
// Parity Ethereum is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
// Parity Ethereum is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
//! Trezor hardware wallet module. Supports Trezor v1.
|
//! Trezor hardware wallet module. Supports Trezor v1.
|
||||||
//! See http://doc.satoshilabs.com/trezor-tech/api-protobuf.html
|
//! See <http://doc.satoshilabs.com/trezor-tech/api-protobuf.html>
|
||||||
//! and https://github.com/trezor/trezor-common/blob/master/protob/protocol.md
|
//! and <https://github.com/trezor/trezor-common/blob/master/protob/protocol.md>
|
||||||
//! for protocol details.
|
//! for protocol details.
|
||||||
|
|
||||||
use super::{WalletInfo, TransactionInfo, KeyPath};
|
|
||||||
|
|
||||||
use std::cmp::{min, max};
|
use std::cmp::{min, max};
|
||||||
use std::fmt;
|
use std::sync::Arc;
|
||||||
use std::sync::{Arc, Weak};
|
|
||||||
use std::time::{Duration, Instant};
|
use std::time::{Duration, Instant};
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
use ethereum_types::{U256, H256, Address};
|
use ethereum_types::{U256, H256, Address};
|
||||||
use ethkey::Signature;
|
use ethkey::Signature;
|
||||||
use hidapi;
|
use hidapi;
|
||||||
use libusb;
|
use libusb;
|
||||||
use parking_lot::{Mutex, RwLock};
|
use parking_lot::{Mutex, RwLock};
|
||||||
use protobuf;
|
use protobuf::{self, Message, ProtobufEnum};
|
||||||
use protobuf::{Message, ProtobufEnum};
|
use super::{DeviceDirection, WalletInfo, TransactionInfo, KeyPath, Wallet, Device, is_valid_hid_device};
|
||||||
|
|
||||||
use trezor_sys::messages::{EthereumAddress, PinMatrixAck, MessageType, EthereumTxRequest, EthereumSignTx, EthereumGetAddress, EthereumTxAck, ButtonAck};
|
use trezor_sys::messages::{EthereumAddress, PinMatrixAck, MessageType, EthereumTxRequest, EthereumSignTx, EthereumGetAddress, EthereumTxAck, ButtonAck};
|
||||||
|
|
||||||
/// Trezor v1 vendor ID
|
/// Trezor v1 vendor ID
|
||||||
pub const TREZOR_VID: u16 = 0x534c;
|
const TREZOR_VID: u16 = 0x534c;
|
||||||
/// Trezor product IDs
|
/// Trezor product IDs
|
||||||
pub const TREZOR_PIDS: [u16; 1] = [0x0001];
|
const TREZOR_PIDS: [u16; 1] = [0x0001];
|
||||||
|
|
||||||
const ETH_DERIVATION_PATH: [u32; 5] = [0x8000002C, 0x8000003C, 0x80000000, 0, 0]; // m/44'/60'/0'/0/0
|
const ETH_DERIVATION_PATH: [u32; 5] = [0x8000_002C, 0x8000_003C, 0x8000_0000, 0, 0]; // m/44'/60'/0'/0/0
|
||||||
const ETC_DERIVATION_PATH: [u32; 5] = [0x8000002C, 0x8000003D, 0x80000000, 0, 0]; // m/44'/61'/0'/0/0
|
const ETC_DERIVATION_PATH: [u32; 5] = [0x8000_002C, 0x8000_003D, 0x8000_0000, 0, 0]; // m/44'/61'/0'/0/0
|
||||||
|
|
||||||
/// Hardware wallet error.
|
/// Hardware wallet error.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@@ -51,6 +48,8 @@ pub enum Error {
|
|||||||
Protocol(&'static str),
|
Protocol(&'static str),
|
||||||
/// Hidapi error.
|
/// Hidapi error.
|
||||||
Usb(hidapi::HidError),
|
Usb(hidapi::HidError),
|
||||||
|
/// Libusb error
|
||||||
|
LibUsb(libusb::Error),
|
||||||
/// Device with request key is not available.
|
/// Device with request key is not available.
|
||||||
KeyNotFound,
|
KeyNotFound,
|
||||||
/// Signing has been cancelled by user.
|
/// Signing has been cancelled by user.
|
||||||
@@ -59,6 +58,14 @@ pub enum Error {
|
|||||||
BadMessageType,
|
BadMessageType,
|
||||||
/// Trying to read from a closed device at the given path
|
/// Trying to read from a closed device at the given path
|
||||||
LockedDevice(String),
|
LockedDevice(String),
|
||||||
|
/// Signing messages are not supported by Trezor
|
||||||
|
NoSigningMessage,
|
||||||
|
/// No device arrived
|
||||||
|
NoDeviceArrived,
|
||||||
|
/// No device left
|
||||||
|
NoDeviceLeft,
|
||||||
|
/// Invalid PID or VID
|
||||||
|
InvalidDevice,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for Error {
|
impl fmt::Display for Error {
|
||||||
@@ -66,27 +73,38 @@ impl fmt::Display for Error {
|
|||||||
match *self {
|
match *self {
|
||||||
Error::Protocol(ref s) => write!(f, "Trezor protocol error: {}", s),
|
Error::Protocol(ref s) => write!(f, "Trezor protocol error: {}", s),
|
||||||
Error::Usb(ref e) => write!(f, "USB communication error: {}", e),
|
Error::Usb(ref e) => write!(f, "USB communication error: {}", e),
|
||||||
|
Error::LibUsb(ref e) => write!(f, "LibUSB communication error: {}", e),
|
||||||
Error::KeyNotFound => write!(f, "Key not found"),
|
Error::KeyNotFound => write!(f, "Key not found"),
|
||||||
Error::UserCancel => write!(f, "Operation has been cancelled"),
|
Error::UserCancel => write!(f, "Operation has been cancelled"),
|
||||||
Error::BadMessageType => write!(f, "Bad Message Type in RPC call"),
|
Error::BadMessageType => write!(f, "Bad Message Type in RPC call"),
|
||||||
Error::LockedDevice(ref s) => write!(f, "Device is locked, needs PIN to perform operations: {}", s),
|
Error::LockedDevice(ref s) => write!(f, "Device is locked, needs PIN to perform operations: {}", s),
|
||||||
|
Error::NoSigningMessage=> write!(f, "Signing messages are not supported by Trezor"),
|
||||||
|
Error::NoDeviceArrived => write!(f, "No device arrived"),
|
||||||
|
Error::NoDeviceLeft => write!(f, "No device left"),
|
||||||
|
Error::InvalidDevice => write!(f, "Device with non-supported product ID or vendor ID was detected"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<hidapi::HidError> for Error {
|
impl From<hidapi::HidError> for Error {
|
||||||
fn from(err: hidapi::HidError) -> Error {
|
fn from(err: hidapi::HidError) -> Self {
|
||||||
Error::Usb(err)
|
Error::Usb(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<libusb::Error> for Error {
|
||||||
|
fn from(err: libusb::Error) -> Self {
|
||||||
|
Error::LibUsb(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl From<protobuf::ProtobufError> for Error {
|
impl From<protobuf::ProtobufError> for Error {
|
||||||
fn from(_: protobuf::ProtobufError) -> Error {
|
fn from(_: protobuf::ProtobufError) -> Self {
|
||||||
Error::Protocol(&"Could not read response from Trezor Device")
|
Error::Protocol(&"Could not read response from Trezor Device")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Ledger device manager
|
/// Trezor device manager
|
||||||
pub struct Manager {
|
pub struct Manager {
|
||||||
usb: Arc<Mutex<hidapi::HidApi>>,
|
usb: Arc<Mutex<hidapi::HidApi>>,
|
||||||
devices: RwLock<Vec<Device>>,
|
devices: RwLock<Vec<Device>>,
|
||||||
@@ -94,12 +112,6 @@ pub struct Manager {
|
|||||||
key_path: RwLock<KeyPath>,
|
key_path: RwLock<KeyPath>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
struct Device {
|
|
||||||
path: String,
|
|
||||||
info: WalletInfo,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// HID Version used for the Trezor device
|
/// HID Version used for the Trezor device
|
||||||
enum HidVersion {
|
enum HidVersion {
|
||||||
V1,
|
V1,
|
||||||
@@ -108,102 +120,13 @@ enum HidVersion {
|
|||||||
|
|
||||||
impl Manager {
|
impl Manager {
|
||||||
/// Create a new instance.
|
/// Create a new instance.
|
||||||
pub fn new(hidapi: Arc<Mutex<hidapi::HidApi>>) -> Manager {
|
pub fn new(usb: Arc<Mutex<hidapi::HidApi>>) -> Arc<Self> {
|
||||||
Manager {
|
Arc::new(Self {
|
||||||
usb: hidapi,
|
usb,
|
||||||
devices: RwLock::new(Vec::new()),
|
devices: RwLock::new(Vec::new()),
|
||||||
locked_devices: RwLock::new(Vec::new()),
|
locked_devices: RwLock::new(Vec::new()),
|
||||||
key_path: RwLock::new(KeyPath::Ethereum),
|
key_path: RwLock::new(KeyPath::Ethereum),
|
||||||
}
|
})
|
||||||
}
|
|
||||||
|
|
||||||
/// Re-populate device list
|
|
||||||
pub fn update_devices(&self) -> Result<usize, Error> {
|
|
||||||
let mut usb = self.usb.lock();
|
|
||||||
usb.refresh_devices();
|
|
||||||
let devices = usb.devices();
|
|
||||||
let mut new_devices = Vec::new();
|
|
||||||
let mut locked_devices = Vec::new();
|
|
||||||
let mut error = None;
|
|
||||||
for usb_device in devices {
|
|
||||||
let is_trezor = usb_device.vendor_id == TREZOR_VID;
|
|
||||||
let is_supported_product = TREZOR_PIDS.contains(&usb_device.product_id);
|
|
||||||
let is_valid = usb_device.usage_page == 0xFF00 || usb_device.interface_number == 0;
|
|
||||||
|
|
||||||
trace!(
|
|
||||||
"Checking device: {:?}, trezor: {:?}, prod: {:?}, valid: {:?}",
|
|
||||||
usb_device,
|
|
||||||
is_trezor,
|
|
||||||
is_supported_product,
|
|
||||||
is_valid,
|
|
||||||
);
|
|
||||||
if !is_trezor || !is_supported_product || !is_valid {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
match self.read_device_info(&usb, &usb_device) {
|
|
||||||
Ok(device) => new_devices.push(device),
|
|
||||||
Err(Error::LockedDevice(path)) => locked_devices.push(path.to_string()),
|
|
||||||
Err(e) => {
|
|
||||||
warn!("Error reading device: {:?}", e);
|
|
||||||
error = Some(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let count = new_devices.len();
|
|
||||||
trace!("Got devices: {:?}, closed: {:?}", new_devices, locked_devices);
|
|
||||||
*self.devices.write() = new_devices;
|
|
||||||
*self.locked_devices.write() = locked_devices;
|
|
||||||
match error {
|
|
||||||
Some(e) => Err(e),
|
|
||||||
None => Ok(count),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn read_device_info(&self, usb: &hidapi::HidApi, dev_info: &hidapi::HidDeviceInfo) -> Result<Device, Error> {
|
|
||||||
let handle = self.open_path(|| usb.open_path(&dev_info.path))?;
|
|
||||||
let manufacturer = dev_info.manufacturer_string.clone().unwrap_or("Unknown".to_owned());
|
|
||||||
let name = dev_info.product_string.clone().unwrap_or("Unknown".to_owned());
|
|
||||||
let serial = dev_info.serial_number.clone().unwrap_or("Unknown".to_owned());
|
|
||||||
match self.get_address(&handle) {
|
|
||||||
Ok(Some(addr)) => {
|
|
||||||
Ok(Device {
|
|
||||||
path: dev_info.path.clone(),
|
|
||||||
info: WalletInfo {
|
|
||||||
name: name,
|
|
||||||
manufacturer: manufacturer,
|
|
||||||
serial: serial,
|
|
||||||
address: addr,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
Ok(None) => Err(Error::LockedDevice(dev_info.path.clone())),
|
|
||||||
Err(e) => Err(e),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Select key derivation path for a known chain.
|
|
||||||
pub fn set_key_path(&self, key_path: KeyPath) {
|
|
||||||
*self.key_path.write() = key_path;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// List connected wallets. This only returns wallets that are ready to be used.
|
|
||||||
pub fn list_devices(&self) -> Vec<WalletInfo> {
|
|
||||||
self.devices.read().iter().map(|d| d.info.clone()).collect()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn list_locked_devices(&self) -> Vec<String> {
|
|
||||||
(*self.locked_devices.read()).clone()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get wallet info.
|
|
||||||
pub fn device_info(&self, address: &Address) -> Option<WalletInfo> {
|
|
||||||
self.devices.read().iter().find(|d| &d.info.address == address).map(|d| d.info.clone())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn open_path<R, F>(&self, f: F) -> Result<R, Error>
|
|
||||||
where F: Fn() -> Result<R, &'static str>
|
|
||||||
{
|
|
||||||
f().map_err(Into::into)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn pin_matrix_ack(&self, device_path: &str, pin: &str) -> Result<bool, Error> {
|
pub fn pin_matrix_ack(&self, device_path: &str, pin: &str) -> Result<bool, Error> {
|
||||||
@@ -213,7 +136,7 @@ impl Manager {
|
|||||||
let t = MessageType::MessageType_PinMatrixAck;
|
let t = MessageType::MessageType_PinMatrixAck;
|
||||||
let mut m = PinMatrixAck::new();
|
let mut m = PinMatrixAck::new();
|
||||||
m.set_pin(pin.to_string());
|
m.set_pin(pin.to_string());
|
||||||
self.send_device_message(&device, &t, &m)?;
|
self.send_device_message(&device, t, &m)?;
|
||||||
let (resp_type, _) = self.read_device_response(&device)?;
|
let (resp_type, _) = self.read_device_response(&device)?;
|
||||||
match resp_type {
|
match resp_type {
|
||||||
// Getting an Address back means it's unlocked, this is undocumented behavior
|
// Getting an Address back means it's unlocked, this is undocumented behavior
|
||||||
@@ -223,68 +146,12 @@ impl Manager {
|
|||||||
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
self.update_devices()?;
|
self.update_devices(DeviceDirection::Arrived)?;
|
||||||
unlocked
|
unlocked
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_address(&self, device: &hidapi::HidDevice) -> Result<Option<Address>, Error> {
|
|
||||||
let typ = MessageType::MessageType_EthereumGetAddress;
|
|
||||||
let mut message = EthereumGetAddress::new();
|
|
||||||
match *self.key_path.read() {
|
|
||||||
KeyPath::Ethereum => message.set_address_n(ETH_DERIVATION_PATH.to_vec()),
|
|
||||||
KeyPath::EthereumClassic => message.set_address_n(ETC_DERIVATION_PATH.to_vec()),
|
|
||||||
}
|
|
||||||
message.set_show_display(false);
|
|
||||||
self.send_device_message(&device, &typ, &message)?;
|
|
||||||
|
|
||||||
let (resp_type, bytes) = self.read_device_response(&device)?;
|
|
||||||
match resp_type {
|
|
||||||
MessageType::MessageType_EthereumAddress => {
|
|
||||||
let response: EthereumAddress = protobuf::core::parse_from_bytes(&bytes)?;
|
|
||||||
Ok(Some(From::from(response.get_address())))
|
|
||||||
}
|
|
||||||
_ => Ok(None),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sign transaction data with wallet managing `address`.
|
|
||||||
pub fn sign_transaction(&self, address: &Address, t_info: &TransactionInfo) -> Result<Signature, Error> {
|
|
||||||
let usb = self.usb.lock();
|
|
||||||
let devices = self.devices.read();
|
|
||||||
let device = devices.iter().find(|d| &d.info.address == address).ok_or(Error::KeyNotFound)?;
|
|
||||||
let handle = self.open_path(|| usb.open_path(&device.path))?;
|
|
||||||
let msg_type = MessageType::MessageType_EthereumSignTx;
|
|
||||||
let mut message = EthereumSignTx::new();
|
|
||||||
match *self.key_path.read() {
|
|
||||||
KeyPath::Ethereum => message.set_address_n(ETH_DERIVATION_PATH.to_vec()),
|
|
||||||
KeyPath::EthereumClassic => message.set_address_n(ETC_DERIVATION_PATH.to_vec()),
|
|
||||||
}
|
|
||||||
message.set_nonce(self.u256_to_be_vec(&t_info.nonce));
|
|
||||||
message.set_gas_limit(self.u256_to_be_vec(&t_info.gas_limit));
|
|
||||||
message.set_gas_price(self.u256_to_be_vec(&t_info.gas_price));
|
|
||||||
message.set_value(self.u256_to_be_vec(&t_info.value));
|
|
||||||
|
|
||||||
match t_info.to {
|
|
||||||
Some(addr) => {
|
|
||||||
message.set_to(addr.to_vec())
|
|
||||||
}
|
|
||||||
None => (),
|
|
||||||
}
|
|
||||||
let first_chunk_length = min(t_info.data.len(), 1024);
|
|
||||||
let chunk = &t_info.data[0..first_chunk_length];
|
|
||||||
message.set_data_initial_chunk(chunk.to_vec());
|
|
||||||
message.set_data_length(t_info.data.len() as u32);
|
|
||||||
if let Some(c_id) = t_info.chain_id {
|
|
||||||
message.set_chain_id(c_id as u32);
|
|
||||||
}
|
|
||||||
|
|
||||||
self.send_device_message(&handle, &msg_type, &message)?;
|
|
||||||
|
|
||||||
self.signing_loop(&handle, &t_info.chain_id, &t_info.data[first_chunk_length..])
|
|
||||||
}
|
|
||||||
|
|
||||||
fn u256_to_be_vec(&self, val: &U256) -> Vec<u8> {
|
fn u256_to_be_vec(&self, val: &U256) -> Vec<u8> {
|
||||||
let mut buf = [0u8; 32];
|
let mut buf = [0_u8; 32];
|
||||||
val.to_big_endian(&mut buf);
|
val.to_big_endian(&mut buf);
|
||||||
buf.iter().skip_while(|x| **x == 0).cloned().collect()
|
buf.iter().skip_while(|x| **x == 0).cloned().collect()
|
||||||
}
|
}
|
||||||
@@ -294,7 +161,7 @@ impl Manager {
|
|||||||
match resp_type {
|
match resp_type {
|
||||||
MessageType::MessageType_Cancel => Err(Error::UserCancel),
|
MessageType::MessageType_Cancel => Err(Error::UserCancel),
|
||||||
MessageType::MessageType_ButtonRequest => {
|
MessageType::MessageType_ButtonRequest => {
|
||||||
self.send_device_message(handle, &MessageType::MessageType_ButtonAck, &ButtonAck::new())?;
|
self.send_device_message(handle, MessageType::MessageType_ButtonAck, &ButtonAck::new())?;
|
||||||
// Signing loop goes back to the top and reading blocks
|
// Signing loop goes back to the top and reading blocks
|
||||||
// for up to 5 minutes waiting for response from the device
|
// for up to 5 minutes waiting for response from the device
|
||||||
// if the user doesn't click any button within 5 minutes you
|
// if the user doesn't click any button within 5 minutes you
|
||||||
@@ -307,7 +174,7 @@ impl Manager {
|
|||||||
let mut msg = EthereumTxAck::new();
|
let mut msg = EthereumTxAck::new();
|
||||||
let len = resp.get_data_length() as usize;
|
let len = resp.get_data_length() as usize;
|
||||||
msg.set_data_chunk(data[..len].to_vec());
|
msg.set_data_chunk(data[..len].to_vec());
|
||||||
self.send_device_message(handle, &MessageType::MessageType_EthereumTxAck, &msg)?;
|
self.send_device_message(handle, MessageType::MessageType_EthereumTxAck, &msg)?;
|
||||||
self.signing_loop(handle, chain_id, &data[len..])
|
self.signing_loop(handle, chain_id, &data[len..])
|
||||||
} else {
|
} else {
|
||||||
let v = resp.get_signature_v();
|
let v = resp.get_signature_v();
|
||||||
@@ -332,15 +199,15 @@ impl Manager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_device_message(&self, device: &hidapi::HidDevice, msg_type: &MessageType, msg: &Message) -> Result<usize, Error> {
|
fn send_device_message(&self, device: &hidapi::HidDevice, msg_type: MessageType, msg: &Message) -> Result<usize, Error> {
|
||||||
let msg_id = *msg_type as u16;
|
let msg_id = msg_type as u16;
|
||||||
let mut message = msg.write_to_bytes()?;
|
let mut message = msg.write_to_bytes()?;
|
||||||
let msg_size = message.len();
|
let msg_size = message.len();
|
||||||
let mut data = Vec::new();
|
let mut data = Vec::new();
|
||||||
let hid_version = self.probe_hid_version(device)?;
|
let hid_version = self.probe_hid_version(device)?;
|
||||||
// Magic constants
|
// Magic constants
|
||||||
data.push('#' as u8);
|
data.push(b'#');
|
||||||
data.push('#' as u8);
|
data.push(b'#');
|
||||||
// Convert msg_id to BE and split into bytes
|
// Convert msg_id to BE and split into bytes
|
||||||
data.push(((msg_id >> 8) & 0xFF) as u8);
|
data.push(((msg_id >> 8) & 0xFF) as u8);
|
||||||
data.push((msg_id & 0xFF) as u8);
|
data.push((msg_id & 0xFF) as u8);
|
||||||
@@ -356,8 +223,8 @@ impl Manager {
|
|||||||
let mut total_written = 0;
|
let mut total_written = 0;
|
||||||
for chunk in data.chunks(63) {
|
for chunk in data.chunks(63) {
|
||||||
let mut padded_chunk = match hid_version {
|
let mut padded_chunk = match hid_version {
|
||||||
HidVersion::V1 => vec!['?' as u8],
|
HidVersion::V1 => vec![b'?'],
|
||||||
HidVersion::V2 => vec![0, '?' as u8],
|
HidVersion::V2 => vec![0, b'?'],
|
||||||
};
|
};
|
||||||
padded_chunk.extend_from_slice(&chunk);
|
padded_chunk.extend_from_slice(&chunk);
|
||||||
total_written += device.write(&padded_chunk)?;
|
total_written += device.write(&padded_chunk)?;
|
||||||
@@ -366,10 +233,10 @@ impl Manager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn probe_hid_version(&self, device: &hidapi::HidDevice) -> Result<HidVersion, Error> {
|
fn probe_hid_version(&self, device: &hidapi::HidDevice) -> Result<HidVersion, Error> {
|
||||||
let mut buf2 = [0xFFu8; 65];
|
let mut buf2 = [0xFF_u8; 65];
|
||||||
buf2[0] = 0;
|
buf2[0] = 0;
|
||||||
buf2[1] = 63;
|
buf2[1] = 63;
|
||||||
let mut buf1 = [0xFFu8; 64];
|
let mut buf1 = [0xFF_u8; 64];
|
||||||
buf1[0] = 63;
|
buf1[0] = 63;
|
||||||
if device.write(&buf2)? == 65 {
|
if device.write(&buf2)? == 65 {
|
||||||
Ok(HidVersion::V2)
|
Ok(HidVersion::V2)
|
||||||
@@ -385,7 +252,7 @@ impl Manager {
|
|||||||
let mut buf = vec![0; 64];
|
let mut buf = vec![0; 64];
|
||||||
|
|
||||||
let first_chunk = device.read_timeout(&mut buf, 300_000)?;
|
let first_chunk = device.read_timeout(&mut buf, 300_000)?;
|
||||||
if first_chunk < 9 || buf[0] != '?' as u8 || buf[1] != '#' as u8 || buf[2] != '#' as u8 {
|
if first_chunk < 9 || buf[0] != b'?' || buf[1] != b'#' || buf[2] != b'#' {
|
||||||
return Err(protocol_err);
|
return Err(protocol_err);
|
||||||
}
|
}
|
||||||
let msg_type = MessageType::from_i32(((buf[3] as i32 & 0xFF) << 8) + (buf[4] as i32 & 0xFF)).ok_or(protocol_err)?;
|
let msg_type = MessageType::from_i32(((buf[3] as i32 & 0xFF) << 8) + (buf[4] as i32 & 0xFF)).ok_or(protocol_err)?;
|
||||||
@@ -400,51 +267,165 @@ impl Manager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to connect to the device using polling in at most the time specified by the `timeout`
|
impl<'a> Wallet<'a> for Manager {
|
||||||
fn try_connect_polling(trezor: Arc<Manager>, duration: Duration) -> bool {
|
type Error = Error;
|
||||||
|
type Transaction = &'a TransactionInfo;
|
||||||
|
|
||||||
|
fn sign_transaction(&self, address: &Address, t_info: Self::Transaction) ->
|
||||||
|
Result<Signature, Error> {
|
||||||
|
let usb = self.usb.lock();
|
||||||
|
let devices = self.devices.read();
|
||||||
|
let device = devices.iter().find(|d| &d.info.address == address).ok_or(Error::KeyNotFound)?;
|
||||||
|
let handle = self.open_path(|| usb.open_path(&device.path))?;
|
||||||
|
let msg_type = MessageType::MessageType_EthereumSignTx;
|
||||||
|
let mut message = EthereumSignTx::new();
|
||||||
|
match *self.key_path.read() {
|
||||||
|
KeyPath::Ethereum => message.set_address_n(ETH_DERIVATION_PATH.to_vec()),
|
||||||
|
KeyPath::EthereumClassic => message.set_address_n(ETC_DERIVATION_PATH.to_vec()),
|
||||||
|
}
|
||||||
|
message.set_nonce(self.u256_to_be_vec(&t_info.nonce));
|
||||||
|
message.set_gas_limit(self.u256_to_be_vec(&t_info.gas_limit));
|
||||||
|
message.set_gas_price(self.u256_to_be_vec(&t_info.gas_price));
|
||||||
|
message.set_value(self.u256_to_be_vec(&t_info.value));
|
||||||
|
|
||||||
|
if let Some(addr) = t_info.to {
|
||||||
|
message.set_to(addr.to_vec())
|
||||||
|
}
|
||||||
|
let first_chunk_length = min(t_info.data.len(), 1024);
|
||||||
|
let chunk = &t_info.data[0..first_chunk_length];
|
||||||
|
message.set_data_initial_chunk(chunk.to_vec());
|
||||||
|
message.set_data_length(t_info.data.len() as u32);
|
||||||
|
if let Some(c_id) = t_info.chain_id {
|
||||||
|
message.set_chain_id(c_id as u32);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.send_device_message(&handle, msg_type, &message)?;
|
||||||
|
|
||||||
|
self.signing_loop(&handle, &t_info.chain_id, &t_info.data[first_chunk_length..])
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_key_path(&self, key_path: KeyPath) {
|
||||||
|
*self.key_path.write() = key_path;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_devices(&self, device_direction: DeviceDirection) -> Result<usize, Error> {
|
||||||
|
let mut usb = self.usb.lock();
|
||||||
|
usb.refresh_devices();
|
||||||
|
let devices = usb.devices();
|
||||||
|
let num_prev_devices = self.devices.read().len();
|
||||||
|
|
||||||
|
let detected_devices = devices.iter()
|
||||||
|
.filter(|&d| is_valid_trezor(d.vendor_id, d.product_id) &&
|
||||||
|
is_valid_hid_device(d.usage_page, d.interface_number)
|
||||||
|
)
|
||||||
|
.fold(Vec::new(), |mut v, d| {
|
||||||
|
match self.read_device(&usb, &d) {
|
||||||
|
Ok(info) => {
|
||||||
|
trace!(target: "hw", "Found device: {:?}", info);
|
||||||
|
v.push(info);
|
||||||
|
}
|
||||||
|
Err(e) => trace!(target: "hw", "Error reading device info: {}", e),
|
||||||
|
};
|
||||||
|
v
|
||||||
|
});
|
||||||
|
|
||||||
|
let num_curr_devices = detected_devices.len();
|
||||||
|
*self.devices.write() = detected_devices;
|
||||||
|
|
||||||
|
match device_direction {
|
||||||
|
DeviceDirection::Arrived => {
|
||||||
|
if num_curr_devices > num_prev_devices {
|
||||||
|
Ok(num_curr_devices - num_prev_devices)
|
||||||
|
} else {
|
||||||
|
Err(Error::NoDeviceArrived)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DeviceDirection::Left => {
|
||||||
|
if num_prev_devices > num_curr_devices {
|
||||||
|
Ok(num_prev_devices - num_curr_devices)
|
||||||
|
} else {
|
||||||
|
Err(Error::NoDeviceLeft)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_device(&self, usb: &hidapi::HidApi, dev_info: &hidapi::HidDeviceInfo) -> Result<Device, Error> {
|
||||||
|
let handle = self.open_path(|| usb.open_path(&dev_info.path))?;
|
||||||
|
let manufacturer = dev_info.manufacturer_string.clone().unwrap_or_else(|| "Unknown".to_owned());
|
||||||
|
let name = dev_info.product_string.clone().unwrap_or_else(|| "Unknown".to_owned());
|
||||||
|
let serial = dev_info.serial_number.clone().unwrap_or_else(|| "Unknown".to_owned());
|
||||||
|
match self.get_address(&handle) {
|
||||||
|
Ok(Some(addr)) => {
|
||||||
|
Ok(Device {
|
||||||
|
path: dev_info.path.clone(),
|
||||||
|
info: WalletInfo {
|
||||||
|
name,
|
||||||
|
manufacturer,
|
||||||
|
serial,
|
||||||
|
address: addr,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
Ok(None) => Err(Error::LockedDevice(dev_info.path.clone())),
|
||||||
|
Err(e) => Err(e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn list_devices(&self) -> Vec<WalletInfo> {
|
||||||
|
self.devices.read().iter().map(|d| d.info.clone()).collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn list_locked_devices(&self) -> Vec<String> {
|
||||||
|
(*self.locked_devices.read()).clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_wallet(&self, address: &Address) -> Option<WalletInfo> {
|
||||||
|
self.devices.read().iter().find(|d| &d.info.address == address).map(|d| d.info.clone())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_address(&self, device: &hidapi::HidDevice) -> Result<Option<Address>, Error> {
|
||||||
|
let typ = MessageType::MessageType_EthereumGetAddress;
|
||||||
|
let mut message = EthereumGetAddress::new();
|
||||||
|
match *self.key_path.read() {
|
||||||
|
KeyPath::Ethereum => message.set_address_n(ETH_DERIVATION_PATH.to_vec()),
|
||||||
|
KeyPath::EthereumClassic => message.set_address_n(ETC_DERIVATION_PATH.to_vec()),
|
||||||
|
}
|
||||||
|
message.set_show_display(false);
|
||||||
|
self.send_device_message(&device, typ, &message)?;
|
||||||
|
|
||||||
|
let (resp_type, bytes) = self.read_device_response(&device)?;
|
||||||
|
match resp_type {
|
||||||
|
MessageType::MessageType_EthereumAddress => {
|
||||||
|
let response: EthereumAddress = protobuf::core::parse_from_bytes(&bytes)?;
|
||||||
|
Ok(Some(From::from(response.get_address())))
|
||||||
|
}
|
||||||
|
_ => Ok(None),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn open_path<R, F>(&self, f: F) -> Result<R, Error>
|
||||||
|
where F: Fn() -> Result<R, &'static str>
|
||||||
|
{
|
||||||
|
f().map_err(Into::into)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Poll the device in maximum `max_polling_duration` if it doesn't succeed
|
||||||
|
pub fn try_connect_polling(trezor: &Manager, duration: &Duration, dir: DeviceDirection) -> bool {
|
||||||
let start_time = Instant::now();
|
let start_time = Instant::now();
|
||||||
while start_time.elapsed() <= duration {
|
while start_time.elapsed() <= *duration {
|
||||||
if let Ok(_) = trezor.update_devices() {
|
if let Ok(num_devices) = trezor.update_devices(dir) {
|
||||||
|
trace!(target: "hw", "{} Trezor devices {}", num_devices, dir);
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Trezor event handler
|
/// Check if the detected device is a Trezor device by checking both the product ID and the vendor ID
|
||||||
/// A separate thread is handeling incoming events
|
pub fn is_valid_trezor(vid: u16, pid: u16) -> bool {
|
||||||
///
|
vid == TREZOR_VID && TREZOR_PIDS.contains(&pid)
|
||||||
/// Note, that this run to completion and race-conditions can't occur but this can
|
|
||||||
/// therefore starve other events for being process with a spinlock or similar
|
|
||||||
pub struct EventHandler {
|
|
||||||
trezor: Weak<Manager>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl EventHandler {
|
|
||||||
/// Trezor event handler constructor
|
|
||||||
pub fn new(trezor: Weak<Manager>) -> Self {
|
|
||||||
Self { trezor: trezor }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl libusb::Hotplug for EventHandler {
|
|
||||||
fn device_arrived(&mut self, _device: libusb::Device) {
|
|
||||||
debug!(target: "hw", "Trezor V1 arrived");
|
|
||||||
if let Some(trezor) = self.trezor.upgrade() {
|
|
||||||
if try_connect_polling(trezor, Duration::from_millis(500)) != true {
|
|
||||||
debug!(target: "hw", "Ledger connect timeout");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn device_left(&mut self, _device: libusb::Device) {
|
|
||||||
debug!(target: "hw", "Trezor V1 left");
|
|
||||||
if let Some(trezor) = self.trezor.upgrade() {
|
|
||||||
if try_connect_polling(trezor, Duration::from_millis(500)) != true {
|
|
||||||
debug!(target: "hw", "Ledger disconnect timeout");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -452,29 +433,31 @@ impl libusb::Hotplug for EventHandler {
|
|||||||
/// This test can't be run without an actual trezor device connected
|
/// This test can't be run without an actual trezor device connected
|
||||||
/// (and unlocked) attached to the machine that's running the test
|
/// (and unlocked) attached to the machine that's running the test
|
||||||
fn test_signature() {
|
fn test_signature() {
|
||||||
use ethereum_types::{H160, H256, U256};
|
use ethereum_types::Address;
|
||||||
|
use MAX_POLLING_DURATION;
|
||||||
|
use super::HardwareWalletManager;
|
||||||
|
|
||||||
let hidapi = Arc::new(Mutex::new(hidapi::HidApi::new().unwrap()));
|
let manager = HardwareWalletManager::new().unwrap();
|
||||||
let manager = Manager::new(hidapi.clone());
|
|
||||||
let addr: Address = H160::from("some_addr");
|
|
||||||
|
|
||||||
manager.update_devices().unwrap();
|
assert_eq!(try_connect_polling(&manager.trezor, &MAX_POLLING_DURATION, DeviceDirection::Arrived), true);
|
||||||
|
|
||||||
|
let addr: Address = manager.list_wallets()
|
||||||
|
.iter()
|
||||||
|
.filter(|d| d.name == "TREZOR".to_string() && d.manufacturer == "SatoshiLabs".to_string())
|
||||||
|
.nth(0)
|
||||||
|
.map(|d| d.address)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
let t_info = TransactionInfo {
|
let t_info = TransactionInfo {
|
||||||
nonce: U256::from(1),
|
nonce: U256::from(1),
|
||||||
gas_price: U256::from(100),
|
gas_price: U256::from(100),
|
||||||
gas_limit: U256::from(21_000),
|
gas_limit: U256::from(21_000),
|
||||||
to: Some(H160::from("some_other_addr")),
|
to: Some(Address::from(1337)),
|
||||||
chain_id: Some(17),
|
chain_id: Some(1),
|
||||||
value: U256::from(1_000_000),
|
value: U256::from(1_000_000),
|
||||||
data: (&[1u8; 3000]).to_vec(),
|
data: (&[1u8; 3000]).to_vec(),
|
||||||
};
|
};
|
||||||
let signature = manager.sign_transaction(&addr, &t_info).unwrap();
|
|
||||||
let expected = Signature::from_rsv(
|
|
||||||
&H256::from("device_specific_r"),
|
|
||||||
&H256::from("device_specific_s"),
|
|
||||||
0x01
|
|
||||||
);
|
|
||||||
|
|
||||||
assert_eq!(signature, expected)
|
let signature = manager.trezor.sign_transaction(&addr, &t_info);
|
||||||
|
assert!(signature.is_ok());
|
||||||
}
|
}
|
||||||
@@ -1,9 +1,8 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "chainspec"
|
name = "chainspec"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
authors = ["debris <marek.kotewicz@gmail.com>"]
|
authors = ["Marek Kotewicz <marek@parity.io>"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
ethjson = { path = "../json" }
|
ethjson = { path = "../json" }
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
serde_ignored = "0.0.4"
|
|
||||||
|
|||||||
@@ -1,8 +1,22 @@
|
|||||||
|
// Copyright 2015-2019 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity Ethereum.
|
||||||
|
|
||||||
|
// Parity Ethereum is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity Ethereum is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
extern crate serde_json;
|
extern crate serde_json;
|
||||||
extern crate serde_ignored;
|
|
||||||
extern crate ethjson;
|
extern crate ethjson;
|
||||||
|
|
||||||
use std::collections::BTreeSet;
|
|
||||||
use std::{fs, env, process};
|
use std::{fs, env, process};
|
||||||
use ethjson::spec::Spec;
|
use ethjson::spec::Spec;
|
||||||
|
|
||||||
@@ -25,24 +39,11 @@ fn main() {
|
|||||||
Err(_) => quit(&format!("{} could not be opened", path)),
|
Err(_) => quit(&format!("{} could not be opened", path)),
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut unused = BTreeSet::new();
|
let spec: Result<Spec, _> = serde_json::from_reader(file);
|
||||||
let mut deserializer = serde_json::Deserializer::from_reader(file);
|
|
||||||
|
|
||||||
let spec: Result<Spec, _> = serde_ignored::deserialize(&mut deserializer, |field| {
|
|
||||||
unused.insert(field.to_string());
|
|
||||||
});
|
|
||||||
|
|
||||||
if let Err(err) = spec {
|
if let Err(err) = spec {
|
||||||
quit(&format!("{} {}", path, err.to_string()));
|
quit(&format!("{} {}", path, err.to_string()));
|
||||||
}
|
}
|
||||||
|
|
||||||
if !unused.is_empty() {
|
|
||||||
let err = unused.into_iter()
|
|
||||||
.map(|field| format!("{} unexpected field `{}`", path, field))
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
.join("\n");
|
|
||||||
quit(&err);
|
|
||||||
}
|
|
||||||
|
|
||||||
println!("{} is valid", path);
|
println!("{} is valid", path);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,12 +3,11 @@ authors = ["Parity <admin@parity.io>"]
|
|||||||
description = "Parity Cli Tool"
|
description = "Parity Cli Tool"
|
||||||
homepage = "http://parity.io"
|
homepage = "http://parity.io"
|
||||||
license = "GPL-3.0"
|
license = "GPL-3.0"
|
||||||
name = "rpc-cli"
|
name = "cli-signer"
|
||||||
version = "1.4.0"
|
version = "1.4.0"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
futures = "0.1"
|
futures = "0.1"
|
||||||
rpassword = "1.0"
|
rpassword = "1.0"
|
||||||
bigint = "4.0"
|
|
||||||
parity-rpc = { path = "../rpc" }
|
parity-rpc = { path = "../rpc" }
|
||||||
parity-rpc-client = { path = "../rpc_client" }
|
parity-rpc-client = { path = "rpc-client" }
|
||||||
@@ -8,13 +8,13 @@ version = "1.4.0"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
futures = "0.1"
|
futures = "0.1"
|
||||||
log = "0.3.6"
|
log = "0.4"
|
||||||
serde = "1.0"
|
serde = "1.0"
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
url = "1.2.0"
|
url = "1.2.0"
|
||||||
matches = "0.1"
|
matches = "0.1"
|
||||||
parking_lot = "0.5"
|
parking_lot = "0.7"
|
||||||
jsonrpc-core = { git = "https://github.com/paritytech/jsonrpc.git", branch = "parity-1.11" }
|
jsonrpc-core = { git = "https://github.com/paritytech/jsonrpc.git", branch = "parity-2.2" }
|
||||||
jsonrpc-ws-server = { git = "https://github.com/paritytech/jsonrpc.git", branch = "parity-1.11" }
|
jsonrpc-ws-server = { git = "https://github.com/paritytech/jsonrpc.git", branch = "parity-2.2" }
|
||||||
parity-rpc = { path = "../rpc" }
|
parity-rpc = { path = "../../rpc" }
|
||||||
keccak-hash = { path = "../util/hash" }
|
keccak-hash = "0.1"
|
||||||
@@ -1,3 +1,19 @@
|
|||||||
|
// Copyright 2015-2019 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity Ethereum.
|
||||||
|
|
||||||
|
// Parity Ethereum is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity Ethereum is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use std::fmt::{Debug, Formatter, Error as FmtError};
|
use std::fmt::{Debug, Formatter, Error as FmtError};
|
||||||
use std::io::{BufReader, BufRead};
|
use std::io::{BufReader, BufRead};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
@@ -258,7 +274,7 @@ impl Rpc {
|
|||||||
let request = MethodCall {
|
let request = MethodCall {
|
||||||
jsonrpc: Some(Version::V2),
|
jsonrpc: Some(Version::V2),
|
||||||
method: method.to_owned(),
|
method: method.to_owned(),
|
||||||
params: Some(Params::Array(params)),
|
params: Params::Array(params),
|
||||||
id: Id::Num(id as u64),
|
id: Id::Num(id as u64),
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1,3 +1,19 @@
|
|||||||
|
// Copyright 2015-2019 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity Ethereum.
|
||||||
|
|
||||||
|
// Parity Ethereum is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity Ethereum is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
pub mod client;
|
pub mod client;
|
||||||
pub mod signer_client;
|
pub mod signer_client;
|
||||||
|
|
||||||
@@ -1,3 +1,19 @@
|
|||||||
|
// Copyright 2015-2019 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity Ethereum.
|
||||||
|
|
||||||
|
// Parity Ethereum is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity Ethereum is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use client::{Rpc, RpcError};
|
use client::{Rpc, RpcError};
|
||||||
use rpc::signer::{ConfirmationRequest, TransactionModification, U256, TransactionCondition};
|
use rpc::signer::{ConfirmationRequest, TransactionModification, U256, TransactionCondition};
|
||||||
use serde;
|
use serde;
|
||||||
@@ -1,3 +1,19 @@
|
|||||||
|
// Copyright 2015-2019 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity Ethereum.
|
||||||
|
|
||||||
|
// Parity Ethereum is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity Ethereum is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
extern crate futures;
|
extern crate futures;
|
||||||
extern crate rpassword;
|
extern crate rpassword;
|
||||||
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
[package]
|
|
||||||
description = "Parity Dapps crate"
|
|
||||||
name = "parity-dapps"
|
|
||||||
version = "1.11.0"
|
|
||||||
license = "GPL-3.0"
|
|
||||||
authors = ["Parity Technologies <admin@parity.io>"]
|
|
||||||
|
|
||||||
[lib]
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
base32 = "0.3"
|
|
||||||
futures = "0.1"
|
|
||||||
futures-cpupool = "0.1"
|
|
||||||
linked-hash-map = "0.5"
|
|
||||||
log = "0.3"
|
|
||||||
parity-dapps-glue = "1.9"
|
|
||||||
parking_lot = "0.5"
|
|
||||||
mime_guess = "2.0.0-alpha.2"
|
|
||||||
rand = "0.4"
|
|
||||||
rustc-hex = "1.0"
|
|
||||||
serde = "1.0"
|
|
||||||
serde_derive = "1.0"
|
|
||||||
serde_json = "1.0"
|
|
||||||
unicase = "1.4"
|
|
||||||
zip = { version = "0.3", default-features = false, features = ["deflate"] }
|
|
||||||
itertools = "0.5"
|
|
||||||
|
|
||||||
jsonrpc-core = { git = "https://github.com/paritytech/jsonrpc.git", branch = "parity-1.11" }
|
|
||||||
jsonrpc-http-server = { git = "https://github.com/paritytech/jsonrpc.git", branch = "parity-1.11" }
|
|
||||||
|
|
||||||
ethcore-bytes = { path = "../util/bytes" }
|
|
||||||
ethereum-types = "0.3"
|
|
||||||
fetch = { path = "../util/fetch" }
|
|
||||||
node-health = { path = "./node-health" }
|
|
||||||
parity-hash-fetch = { path = "../hash-fetch" }
|
|
||||||
parity-reactor = { path = "../util/reactor" }
|
|
||||||
parity-ui = { path = "./ui" }
|
|
||||||
parity-ui-deprecation = { path = "./ui-deprecation" }
|
|
||||||
keccak-hash = { path = "../util/hash" }
|
|
||||||
parity-version = { path = "../util/version" }
|
|
||||||
registrar = { path = "../registrar" }
|
|
||||||
|
|
||||||
[dev-dependencies]
|
|
||||||
env_logger = "0.4"
|
|
||||||
ethcore-devtools = { path = "../devtools" }
|
|
||||||
|
|
||||||
[features]
|
|
||||||
ui = ["parity-ui/no-precompiled-js"]
|
|
||||||
ui-precompiled = ["parity-ui/use-precompiled-js"]
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
[package]
|
|
||||||
description = "Base Package for all Parity built-in dapps"
|
|
||||||
name = "parity-dapps-glue"
|
|
||||||
version = "1.9.1"
|
|
||||||
license = "GPL-3.0"
|
|
||||||
authors = ["Parity Technologies <admin@parity.io>"]
|
|
||||||
build = "build.rs"
|
|
||||||
|
|
||||||
[build-dependencies]
|
|
||||||
quasi_codegen = { version = "0.32", optional = true }
|
|
||||||
syntex = { version = "0.58", optional = true }
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
glob = { version = "0.2.11" }
|
|
||||||
mime_guess = { version = "2.0.0-alpha.2" }
|
|
||||||
aster = { version = "0.41", default-features = false }
|
|
||||||
quasi = { version = "0.32", default-features = false }
|
|
||||||
quasi_macros = { version = "0.32", optional = true }
|
|
||||||
syntex = { version = "0.58", optional = true }
|
|
||||||
syntex_syntax = { version = "0.58", optional = true }
|
|
||||||
|
|
||||||
[features]
|
|
||||||
default = ["with-syntex"]
|
|
||||||
nightly = ["quasi_macros"]
|
|
||||||
with-syntex = ["quasi/with-syntex", "quasi_codegen", "quasi_codegen/with-syntex", "syntex", "syntex_syntax"]
|
|
||||||
use-precompiled-js = []
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,65 +0,0 @@
|
|||||||
# Parity Dapps (JS-glue)
|
|
||||||
|
|
||||||
Code generator to simplify creating a built-in Parity Dapp
|
|
||||||
|
|
||||||
# How to create new builtin Dapp.
|
|
||||||
1. Clone this repository.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
$ git clone https://github.com/paritytech/parity.git
|
|
||||||
```
|
|
||||||
|
|
||||||
1. Create a new directory for your Dapp. (`./myapp`)
|
|
||||||
|
|
||||||
```bash
|
|
||||||
$ mkdir -p ./parity/dapps/myapp/src/web
|
|
||||||
```
|
|
||||||
|
|
||||||
1. Copy your frontend files to `./dapps/myapp/src/web` (bundled ones)
|
|
||||||
|
|
||||||
```bash
|
|
||||||
$ cp -r ./myapp-src/* ./parity/dapps/myapp/src/web
|
|
||||||
```
|
|
||||||
|
|
||||||
1. Instead of creating `web3` in your app. Load (as the first script tag in `head`):
|
|
||||||
|
|
||||||
```html
|
|
||||||
<script src="/parity-utils/inject.js"></script>
|
|
||||||
```
|
|
||||||
|
|
||||||
The `inject.js` script will create global `web3` instance with proper provider that should be used by your dapp.
|
|
||||||
|
|
||||||
1. Create `./parity/dapps/myapp/Cargo.toml` with you apps details. See example here: [parity-status Cargo.toml](https://github.com/paritytech/parity-ui/blob/master/status/Cargo.toml).
|
|
||||||
|
|
||||||
```bash
|
|
||||||
$ git clone https://github.com/paritytech/parity-ui.git
|
|
||||||
$ cd ./parity-ui/
|
|
||||||
$ cp ./home/Cargo.toml ../parity/dapps/myapp/Cargo.toml
|
|
||||||
$ cp ./home/build.rs ../parity/dapps/myapp/build.rs
|
|
||||||
$ cp ./home/src/lib.rs ../parity/dapps/myapp/src/lib.rs
|
|
||||||
$ cp ./home/src/lib.rs.in ../parity/dapps/myapp/src/lib.rs.in
|
|
||||||
# And edit the details of your app
|
|
||||||
$ vim ../parity/dapps/myapp/Cargo.toml # Edit the details
|
|
||||||
$ vim ./parity/dapps/myapp/src/lib.rs.in # Edit the details
|
|
||||||
```
|
|
||||||
# How to include your Dapp into `Parity`?
|
|
||||||
1. Edit `dapps/Cargo.toml` and add dependency to your application (it can be optional)
|
|
||||||
|
|
||||||
```toml
|
|
||||||
# Use git repo and version
|
|
||||||
parity-dapps-myapp = { path="./myapp" }
|
|
||||||
```
|
|
||||||
|
|
||||||
1. Edit `dapps/src/apps.rs` and add your application to `all_pages` (if it's optional you need to specify two functions - see `parity-dapps-wallet` example)
|
|
||||||
|
|
||||||
1. Compile parity.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
$ cargo build --release # While inside `parity`
|
|
||||||
```
|
|
||||||
|
|
||||||
1. Commit the results.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
$ git add myapp && git commit -am "My first Parity Dapp".
|
|
||||||
```
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of Parity.
|
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
|
|
||||||
#[cfg(feature = "with-syntex")]
|
|
||||||
mod inner {
|
|
||||||
extern crate syntex;
|
|
||||||
extern crate quasi_codegen;
|
|
||||||
|
|
||||||
use std::env;
|
|
||||||
use std::path::Path;
|
|
||||||
|
|
||||||
pub fn main() {
|
|
||||||
let out_dir = env::var_os("OUT_DIR").unwrap();
|
|
||||||
|
|
||||||
let src = Path::new("src/lib.rs.in");
|
|
||||||
let dst = Path::new(&out_dir).join("lib.rs");
|
|
||||||
|
|
||||||
quasi_codegen::expand(&src, &dst).unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(feature = "with-syntex"))]
|
|
||||||
mod inner {
|
|
||||||
pub fn main() {}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
inner::main();
|
|
||||||
}
|
|
||||||
@@ -1,65 +0,0 @@
|
|||||||
|
|
||||||
#[cfg(feature = "with-syntex")]
|
|
||||||
pub mod inner {
|
|
||||||
use syntex;
|
|
||||||
use codegen;
|
|
||||||
use syntax::{ast, fold};
|
|
||||||
use std::env;
|
|
||||||
use std::path::Path;
|
|
||||||
|
|
||||||
fn strip_attributes(krate: ast::Crate) -> ast::Crate {
|
|
||||||
/// Helper folder that strips the serde attributes after the extensions have been expanded.
|
|
||||||
struct StripAttributeFolder;
|
|
||||||
|
|
||||||
impl fold::Folder for StripAttributeFolder {
|
|
||||||
fn fold_attribute(&mut self, attr: ast::Attribute) -> Option<ast::Attribute> {
|
|
||||||
if &*attr.value.name.as_str() == "webapp" {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
Some(attr)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac {
|
|
||||||
fold::noop_fold_mac(mac, self)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fold::Folder::fold_crate(&mut StripAttributeFolder, krate)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn register(reg: &mut syntex::Registry) {
|
|
||||||
reg.add_attr("feature(custom_derive)");
|
|
||||||
reg.add_attr("feature(custom_attribute)");
|
|
||||||
|
|
||||||
reg.add_decorator("derive_WebAppFiles", codegen::expand_webapp_implementation);
|
|
||||||
reg.add_post_expansion_pass(strip_attributes);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn generate() {
|
|
||||||
let out_dir = env::var_os("OUT_DIR").unwrap();
|
|
||||||
let mut registry = syntex::Registry::new();
|
|
||||||
register(&mut registry);
|
|
||||||
|
|
||||||
let src = Path::new("src/lib.rs.in");
|
|
||||||
let dst = Path::new(&out_dir).join("lib.rs");
|
|
||||||
|
|
||||||
registry.expand("", &src, &dst).unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(feature = "with-syntex"))]
|
|
||||||
pub mod inner {
|
|
||||||
use codegen;
|
|
||||||
|
|
||||||
pub fn register(reg: &mut rustc_plugin::Registry) {
|
|
||||||
reg.register_syntax_extension(
|
|
||||||
syntax::parse::token::intern("derive_WebAppFiles"),
|
|
||||||
syntax::ext::base::MultiDecorator(
|
|
||||||
Box::new(codegen::expand_webapp_implementation)));
|
|
||||||
|
|
||||||
reg.register_attribute("webapp".to_owned(), AttributeType::Normal);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn generate() {}
|
|
||||||
}
|
|
||||||
@@ -1,194 +0,0 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of Parity.
|
|
||||||
|
|
||||||
// Parity is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
|
|
||||||
// Parity is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
extern crate aster;
|
|
||||||
extern crate glob;
|
|
||||||
extern crate mime_guess;
|
|
||||||
|
|
||||||
use self::mime_guess::guess_mime_type;
|
|
||||||
use std::path::{self, Path, PathBuf};
|
|
||||||
use std::ops::Deref;
|
|
||||||
|
|
||||||
use syntax::attr;
|
|
||||||
use syntax::ast::{self, MetaItem, Item};
|
|
||||||
use syntax::codemap::Span;
|
|
||||||
use syntax::ext::base::{Annotatable, ExtCtxt};
|
|
||||||
use syntax::print::pprust::lit_to_string;
|
|
||||||
use syntax::symbol::InternedString;
|
|
||||||
|
|
||||||
pub fn expand_webapp_implementation(
|
|
||||||
cx: &mut ExtCtxt,
|
|
||||||
span: Span,
|
|
||||||
meta_item: &MetaItem,
|
|
||||||
annotatable: &Annotatable,
|
|
||||||
push: &mut FnMut(Annotatable)
|
|
||||||
) {
|
|
||||||
let item = match *annotatable {
|
|
||||||
Annotatable::Item(ref item) => item,
|
|
||||||
_ => {
|
|
||||||
cx.span_err(meta_item.span, "`#[derive(WebAppFiles)]` may only be applied to struct implementations");
|
|
||||||
return;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
let builder = aster::AstBuilder::new().span(span);
|
|
||||||
implement_webapp(cx, &builder, item, push);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn implement_webapp(cx: &ExtCtxt, builder: &aster::AstBuilder, item: &Item, push: &mut FnMut(Annotatable)) {
|
|
||||||
let static_files_dir = extract_path(cx, item);
|
|
||||||
|
|
||||||
let src = Path::new("src");
|
|
||||||
let static_files = {
|
|
||||||
let mut buf = src.to_path_buf();
|
|
||||||
buf.push(static_files_dir.deref());
|
|
||||||
buf
|
|
||||||
};
|
|
||||||
|
|
||||||
let search_location = {
|
|
||||||
let mut buf = static_files.to_path_buf();
|
|
||||||
buf.push("**");
|
|
||||||
buf.push("*");
|
|
||||||
buf
|
|
||||||
};
|
|
||||||
|
|
||||||
let files = glob::glob(search_location.to_str().expect("Valid UTF8 path"))
|
|
||||||
.expect("The sources directory is missing.")
|
|
||||||
.collect::<Result<Vec<PathBuf>, glob::GlobError>>()
|
|
||||||
.expect("There should be no error when reading a list of files.");
|
|
||||||
|
|
||||||
let statements = files
|
|
||||||
.iter()
|
|
||||||
.filter(|path_buf| path_buf.is_file())
|
|
||||||
.map(|path_buf| {
|
|
||||||
let path = path_buf.as_path();
|
|
||||||
let filename = path.file_name().and_then(|s| s.to_str()).expect("Only UTF8 paths.");
|
|
||||||
let mime_type = guess_mime_type(filename).to_string();
|
|
||||||
let file_path = as_uri(path.strip_prefix(&static_files).ok().expect("Prefix is always there, cause it's absolute path;qed"));
|
|
||||||
let file_path_in_source = path.to_str().expect("Only UTF8 paths.");
|
|
||||||
|
|
||||||
let path_lit = builder.expr().str(file_path.as_str());
|
|
||||||
let mime_lit = builder.expr().str(mime_type.as_str());
|
|
||||||
let web_path_lit = builder.expr().str(file_path_in_source);
|
|
||||||
let separator_lit = builder.expr().str(path::MAIN_SEPARATOR.to_string().as_str());
|
|
||||||
let concat_id = builder.id("concat!");
|
|
||||||
let env_id = builder.id("env!");
|
|
||||||
let macro_id = builder.id("include_bytes!");
|
|
||||||
|
|
||||||
let content = quote_expr!(
|
|
||||||
cx,
|
|
||||||
$macro_id($concat_id($env_id("CARGO_MANIFEST_DIR"), $separator_lit, $web_path_lit))
|
|
||||||
);
|
|
||||||
quote_stmt!(
|
|
||||||
cx,
|
|
||||||
files.insert($path_lit, File { path: $path_lit, content_type: $mime_lit, content: $content });
|
|
||||||
).expect("The statement is always ok, because it just uses literals.")
|
|
||||||
}).collect::<Vec<ast::Stmt>>();
|
|
||||||
|
|
||||||
let type_name = item.ident;
|
|
||||||
|
|
||||||
let files_impl = quote_item!(cx,
|
|
||||||
impl $type_name {
|
|
||||||
#[allow(unused_mut)]
|
|
||||||
fn files() -> ::std::collections::HashMap<&'static str, File> {
|
|
||||||
let mut files = ::std::collections::HashMap::new();
|
|
||||||
$statements
|
|
||||||
files
|
|
||||||
}
|
|
||||||
}
|
|
||||||
).unwrap();
|
|
||||||
|
|
||||||
push(Annotatable::Item(files_impl));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn extract_path(cx: &ExtCtxt, item: &Item) -> String {
|
|
||||||
for meta_items in item.attrs.iter().filter_map(webapp_meta_items) {
|
|
||||||
for meta_item in meta_items {
|
|
||||||
let is_path = &*meta_item.name.as_str() == "path";
|
|
||||||
match meta_item.node {
|
|
||||||
ast::MetaItemKind::NameValue(ref lit) if is_path => {
|
|
||||||
if let Some(s) = get_str_from_lit(cx, lit) {
|
|
||||||
return s.deref().to_owned();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
_ => {},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// default
|
|
||||||
"web".to_owned()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn webapp_meta_items(attr: &ast::Attribute) -> Option<Vec<ast::MetaItem>> {
|
|
||||||
let is_webapp = &*attr.value.name.as_str() == "webapp";
|
|
||||||
match attr.value.node {
|
|
||||||
ast::MetaItemKind::List(ref items) if is_webapp => {
|
|
||||||
attr::mark_used(&attr);
|
|
||||||
Some(
|
|
||||||
items.iter()
|
|
||||||
.map(|item| item.node.clone())
|
|
||||||
.filter_map(|item| match item {
|
|
||||||
ast::NestedMetaItemKind::MetaItem(item) => Some(item),
|
|
||||||
_ => None,
|
|
||||||
})
|
|
||||||
.collect()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
_ => None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_str_from_lit(cx: &ExtCtxt, lit: &ast::Lit) -> Option<InternedString> {
|
|
||||||
match lit.node {
|
|
||||||
ast::LitKind::Str(ref s, _) => Some(s.clone().as_str()),
|
|
||||||
_ => {
|
|
||||||
cx.span_err(
|
|
||||||
lit.span,
|
|
||||||
&format!("webapp annotation path must be a string, not `{}`",
|
|
||||||
lit_to_string(lit)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn as_uri(path: &Path) -> String {
|
|
||||||
let mut s = String::new();
|
|
||||||
for component in path.iter() {
|
|
||||||
s.push_str(component.to_str().expect("Only UTF-8 filenames are supported."));
|
|
||||||
s.push('/');
|
|
||||||
}
|
|
||||||
s[0..s.len()-1].into()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn should_convert_path_separators_on_all_platforms() {
|
|
||||||
// given
|
|
||||||
let p = {
|
|
||||||
let mut p = PathBuf::new();
|
|
||||||
p.push("web");
|
|
||||||
p.push("src");
|
|
||||||
p.push("index.html");
|
|
||||||
p
|
|
||||||
};
|
|
||||||
|
|
||||||
// when
|
|
||||||
let path = as_uri(&p);
|
|
||||||
|
|
||||||
// then
|
|
||||||
assert_eq!(path, "web/src/index.html".to_owned());
|
|
||||||
}
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user