Compare commits
871 Commits
v1.3.1-bet
...
stale-peer
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
af34894fc3 | ||
|
|
7dcd01e9be | ||
|
|
3adcfabb41 | ||
|
|
b1f0a3c79b | ||
|
|
e988d1574e | ||
|
|
2cce9dd3de | ||
|
|
b7e678e93d | ||
|
|
b61128bd7b | ||
|
|
df16ab95ab | ||
|
|
9e343669b5 | ||
|
|
987b8c1504 | ||
|
|
7d907016ff | ||
|
|
00cac12542 | ||
|
|
27f618f434 | ||
|
|
46b88d11f9 | ||
|
|
f532da6ca0 | ||
|
|
c94fc290e7 | ||
|
|
7f3c5ce4cd | ||
|
|
313449404f | ||
|
|
99e4e950f8 | ||
|
|
cabd0f8a21 | ||
|
|
17e0e45a09 | ||
|
|
6260a26971 | ||
|
|
a44b6d8067 | ||
|
|
c6cb43b7ca | ||
|
|
222e10810e | ||
|
|
b844958a96 | ||
|
|
3cade73e40 | ||
|
|
4f38c78c6e | ||
|
|
7b8d28b425 | ||
|
|
74078e1dc4 | ||
|
|
26b236fb5f | ||
|
|
900cf26c65 | ||
|
|
21e6dcfc79 | ||
|
|
a262acfb00 | ||
|
|
87e622e51f | ||
|
|
13d454796f | ||
|
|
c6af48100d | ||
|
|
6d5b4ad64d | ||
|
|
d35b57ae36 | ||
|
|
21fc2d3ac4 | ||
|
|
c96fab04a3 | ||
|
|
27d86948fa | ||
|
|
a04e287cb6 | ||
|
|
c3d6155fff | ||
|
|
a00ffa762c | ||
|
|
863fdea026 | ||
|
|
90e67970ae | ||
|
|
e8456c2d08 | ||
|
|
bc970e5893 | ||
|
|
a5810fefc9 | ||
|
|
971c0fa380 | ||
|
|
88225c1a4b | ||
|
|
51e27f9e3b | ||
|
|
f1a85ec306 | ||
|
|
75d162983a | ||
|
|
727c07116d | ||
|
|
719412551a | ||
|
|
c2226a0c9f | ||
|
|
d52628aa82 | ||
|
|
f7de51f74e | ||
|
|
55cbf31f18 | ||
|
|
f0c7795542 | ||
|
|
1548452def | ||
|
|
f2e7f1dd24 | ||
|
|
27a3ec5d72 | ||
|
|
6094d7157e | ||
|
|
be0fbfb79e | ||
|
|
00f094c37e | ||
|
|
7b08a70a23 | ||
|
|
99d31aeb28 | ||
|
|
f467c6018b | ||
|
|
4566ac7659 | ||
|
|
aab4b8812a | ||
|
|
af7e9b95bd | ||
|
|
1047f0e59a | ||
|
|
9bb4fed1bf | ||
|
|
35e71a769b | ||
|
|
6b02ac7ac5 | ||
|
|
8b9558bb4d | ||
|
|
63e7eac394 | ||
|
|
05543e558d | ||
|
|
b0146261c7 | ||
|
|
d7b9866d3b | ||
|
|
f5ba30ed47 | ||
|
|
f190c49252 | ||
|
|
08769ead2b | ||
|
|
4d0f1e7117 | ||
|
|
c77bb1110d | ||
|
|
c856d21719 | ||
|
|
f45305b1ad | ||
|
|
d16532d678 | ||
|
|
5edd032cdb | ||
|
|
6b8cbbe172 | ||
|
|
5ea2ada0ee | ||
|
|
b230a02006 | ||
|
|
86e3a02490 | ||
|
|
0c0958ff87 | ||
|
|
c577ce3720 | ||
|
|
d436f9e2e8 | ||
|
|
97c3b9b267 | ||
|
|
0560685460 | ||
|
|
bf16a39876 | ||
|
|
2c8720016d | ||
|
|
f2ec3cc6a5 | ||
|
|
0a2e1282d2 | ||
|
|
adb5e8fe86 | ||
|
|
23f6194fad | ||
|
|
691d195526 | ||
|
|
b57c779759 | ||
|
|
4ab1c865b2 | ||
|
|
a7d5b02919 | ||
|
|
1ce9bb044d | ||
|
|
7948950f7a | ||
|
|
0c101e618a | ||
|
|
571ea2c4b9 | ||
|
|
7bc5a3353d | ||
|
|
901ea2e0d2 | ||
|
|
1d81f3316f | ||
|
|
43b2ffa63b | ||
|
|
0567715760 | ||
|
|
e32fcf5b93 | ||
|
|
e55028d788 | ||
|
|
9d8df917b8 | ||
|
|
9e170972f4 | ||
|
|
ba6726325a | ||
|
|
6573254a62 | ||
|
|
31d92c50ad | ||
|
|
7cab9c622c | ||
|
|
2a0e399c38 | ||
|
|
182c841374 | ||
|
|
14023fae6d | ||
|
|
d653cda82e | ||
|
|
4b54601d5c | ||
|
|
3b7f0e4279 | ||
|
|
fe1fff8c77 | ||
|
|
c0afdc9a98 | ||
|
|
fb435eb5f1 | ||
|
|
5cc253a2cd | ||
|
|
cbcd26c9a9 | ||
|
|
90eb5b33e8 | ||
|
|
837de88057 | ||
|
|
b4fb2f6ffc | ||
|
|
11503edeb2 | ||
|
|
3a6e3c67f2 | ||
|
|
335be39905 | ||
|
|
b7972bcd77 | ||
|
|
4bb1bd1a77 | ||
|
|
a05724588f | ||
|
|
009df5a121 | ||
|
|
d7836bfe98 | ||
|
|
f4bad20447 | ||
|
|
a75e82367d | ||
|
|
26f50099f4 | ||
|
|
060e5c6b34 | ||
|
|
4e9f699068 | ||
|
|
42a0236587 | ||
|
|
48f58a50bb | ||
|
|
e4688e4e7a | ||
|
|
75a03f420f | ||
|
|
46df9b4dcb | ||
|
|
7dbafe7453 | ||
|
|
f2c9141e4f | ||
|
|
c3623e9af7 | ||
|
|
32ac07f257 | ||
|
|
3b7ee60e14 | ||
|
|
438cdf0861 | ||
|
|
212b7a6972 | ||
|
|
7c7a9bc53b | ||
|
|
04a3b1f94f | ||
|
|
5d51873890 | ||
|
|
3e97f827b4 | ||
|
|
9ab8565128 | ||
|
|
7c89c65a97 | ||
|
|
e7c5ce2e94 | ||
|
|
eda56e22a9 | ||
|
|
dddf20e6e0 | ||
|
|
79cd5222e7 | ||
|
|
38db9bf4e2 | ||
|
|
e0b98ef9cb | ||
|
|
7f3f72ed41 | ||
|
|
76fb29504c | ||
|
|
84c36588cd | ||
|
|
22888c8725 | ||
|
|
e313d5b319 | ||
|
|
1208d07e94 | ||
|
|
fd284c74dd | ||
|
|
fdbe2e3cb0 | ||
|
|
9684ba3a83 | ||
|
|
1324884db7 | ||
|
|
ebe88c09a9 | ||
|
|
66ed85ef82 | ||
|
|
2893079aa4 | ||
|
|
3c81d559e7 | ||
|
|
c1496e7ced | ||
|
|
291ab99d4a | ||
|
|
e6e1d06687 | ||
|
|
c170814596 | ||
|
|
09b469f0bf | ||
|
|
6978f009ab | ||
|
|
74d20546c3 | ||
|
|
ccd7a44be0 | ||
|
|
10ae179a73 | ||
|
|
16b040e8c4 | ||
|
|
880f7ab865 | ||
|
|
58bc494fa7 | ||
|
|
d9b9b7f66b | ||
|
|
e4ddf5881b | ||
|
|
a4b436806e | ||
|
|
cbff31944b | ||
|
|
7169e2b864 | ||
|
|
d620407ff4 | ||
|
|
9e85b0f29f | ||
|
|
eb4465567e | ||
|
|
fd914c2330 | ||
|
|
4387eec4dc | ||
|
|
8ef781a41e | ||
|
|
1487e46f30 | ||
|
|
270793f13a | ||
|
|
31ace32e9e | ||
|
|
b7d3be0398 | ||
|
|
6386172b95 | ||
|
|
4051c34e18 | ||
|
|
16c6e462e0 | ||
|
|
def3512fd8 | ||
|
|
411d5c5001 | ||
|
|
89c4ab2a05 | ||
|
|
0dc4b1f119 | ||
|
|
b75720d270 | ||
|
|
a18ed24b9d | ||
|
|
38d592dfdd | ||
|
|
5ccaed162f | ||
|
|
72fcd3b394 | ||
|
|
b23dd6c9f7 | ||
|
|
c8cc91963f | ||
|
|
93d652bad3 | ||
|
|
c9b3417ce6 | ||
|
|
2bd6bd01d2 | ||
|
|
9038ba6942 | ||
|
|
51b479e564 | ||
|
|
ba58f5793f | ||
|
|
5a0f468f8c | ||
|
|
bd13416162 | ||
|
|
b7b64da564 | ||
|
|
45a272c7b9 | ||
|
|
63aaac8100 | ||
|
|
c1f59b98f6 | ||
|
|
821d70240d | ||
|
|
8bca93e82c | ||
|
|
edffacca8f | ||
|
|
26724fc2aa | ||
|
|
32d4d6e616 | ||
|
|
2ecffd3acd | ||
|
|
73f27a590f | ||
|
|
93c541ad56 | ||
|
|
b87b9b4533 | ||
|
|
e47a7c22c4 | ||
|
|
b590cae892 | ||
|
|
7f131dcbc9 | ||
|
|
3b4ede7444 | ||
|
|
b47cf8fe1d | ||
|
|
a501442a89 | ||
|
|
9ec1223f4d | ||
|
|
b9ca38b735 | ||
|
|
79e340fb12 | ||
|
|
bba3fa9af9 | ||
|
|
7f5e96dc6c | ||
|
|
5e74ea650d | ||
|
|
f4852b8ddc | ||
|
|
5378df3702 | ||
|
|
40cae45436 | ||
|
|
ac0ff04460 | ||
|
|
6fb0d0992b | ||
|
|
5d984796af | ||
|
|
361e8413e6 | ||
|
|
034bc4669f | ||
|
|
593e303485 | ||
|
|
95741b1844 | ||
|
|
3c30de219f | ||
|
|
a193bb0c73 | ||
|
|
1bdf8b9b2d | ||
|
|
0c412dcd1f | ||
|
|
286090689a | ||
|
|
886f0e72e5 | ||
|
|
9e3e46671e | ||
|
|
2a1d94bd1d | ||
|
|
efddedc16c | ||
|
|
9d537f5439 | ||
|
|
8321fe2fda | ||
|
|
55a46c3b10 | ||
|
|
36a283ef98 | ||
|
|
fe91d476ba | ||
|
|
4c15d58007 | ||
|
|
beb2954fa4 | ||
|
|
f1c27c286e | ||
|
|
1a79089193 | ||
|
|
f0c5b6765d | ||
|
|
89575aeb4b | ||
|
|
02eb36afc2 | ||
|
|
8facf44109 | ||
|
|
85938dda09 | ||
|
|
ac5aa672d3 | ||
|
|
2732fb10d2 | ||
|
|
8a76a814a2 | ||
|
|
ae3b7a0b65 | ||
|
|
2dc33d46b8 | ||
|
|
2ab365f6d8 | ||
|
|
69f5d5ba1f | ||
|
|
449d3f0d87 | ||
|
|
1f50aa7631 | ||
|
|
199e0c9ff5 | ||
|
|
16ce7bf50f | ||
|
|
0b5d8d2b58 | ||
|
|
99e9c0702b | ||
|
|
8fd43c8013 | ||
|
|
8ec638dc5e | ||
|
|
19af9008f1 | ||
|
|
253447a4f5 | ||
|
|
47d76c5f95 | ||
|
|
62affdc9c5 | ||
|
|
06a871136e | ||
|
|
a1c2491aab | ||
|
|
78d1cade19 | ||
|
|
5c67066a05 | ||
|
|
3adf1cecf2 | ||
|
|
82beb2c5f3 | ||
|
|
eaac53ec38 | ||
|
|
fc380f52ef | ||
|
|
3761bf0426 | ||
|
|
e2778cd59f | ||
|
|
db98cc485e | ||
|
|
29427c51fd | ||
|
|
2e947b7a00 | ||
|
|
220be95117 | ||
|
|
f0d9f61bf6 | ||
|
|
bc0b87ca19 | ||
|
|
d49da4348c | ||
|
|
fecd2bfafe | ||
|
|
cd0770ea68 | ||
|
|
8f7eb9ccd9 | ||
|
|
99dc3fe118 | ||
|
|
765f2904d8 | ||
|
|
a8a87586c1 | ||
|
|
6b0de79935 | ||
|
|
542c861b4f | ||
|
|
98eaa57e6f | ||
|
|
2dc74770a7 | ||
|
|
c89a3da7d9 | ||
|
|
4c8d92d303 | ||
|
|
a5a4fa7032 | ||
|
|
819a4977e8 | ||
|
|
19d9977641 | ||
|
|
ef13f3194d | ||
|
|
c6aeee2001 | ||
|
|
6a724b94db | ||
|
|
78a3c32ef4 | ||
|
|
58602e6b53 | ||
|
|
d10200175e | ||
|
|
a6a956263e | ||
|
|
ef462c2b47 | ||
|
|
4829027a54 | ||
|
|
bea8f8ecfc | ||
|
|
f55a10b64d | ||
|
|
1c488298c8 | ||
|
|
0e93da3197 | ||
|
|
04d62b53da | ||
|
|
d8b85839ee | ||
|
|
830f3c764c | ||
|
|
e5d5e09faa | ||
|
|
2e2e89c2fb | ||
|
|
e606461454 | ||
|
|
c66ca8bf7a | ||
|
|
d4f25b4dcf | ||
|
|
1c3d31c19f | ||
|
|
566754c74a | ||
|
|
9ee6809ff4 | ||
|
|
18e154eaa2 | ||
|
|
7596db5f48 | ||
|
|
0d5ecb5b90 | ||
|
|
1469bce18a | ||
|
|
89ccc680da | ||
|
|
a17fef4f15 | ||
|
|
1485814f89 | ||
|
|
29b73555ae | ||
|
|
407f779c8e | ||
|
|
1335ba5f28 | ||
|
|
a608c0ac84 | ||
|
|
43ba7d65a8 | ||
|
|
065f82a8cc | ||
|
|
7280a5b31a | ||
|
|
ae4ea047e3 | ||
|
|
fee8a25957 | ||
|
|
6e235c0833 | ||
|
|
ccb4d55a7c | ||
|
|
5c2de7fcbe | ||
|
|
2e8b1187aa | ||
|
|
bc0be1b106 | ||
|
|
a162091e8f | ||
|
|
daa2e5d6a6 | ||
|
|
dd938d103d | ||
|
|
4f825318ea | ||
|
|
2d08c99009 | ||
|
|
8ed5d24e1d | ||
|
|
9e018ce3a5 | ||
|
|
d0edc5af4a | ||
|
|
1010a79c7c | ||
|
|
cfff3cbbf1 | ||
|
|
f29520ffdf | ||
|
|
e7fa158086 | ||
|
|
07b17f991b | ||
|
|
5853329c63 | ||
|
|
69531d67a8 | ||
|
|
7b22894146 | ||
|
|
b2de32fb16 | ||
|
|
877d09443d | ||
|
|
e3eeb64c94 | ||
|
|
99eb49e601 | ||
|
|
73d19c00cd | ||
|
|
0b471c312a | ||
|
|
5fa1755329 | ||
|
|
23a8d00334 | ||
|
|
3349a24333 | ||
|
|
7f2ef5987f | ||
|
|
8d51cec12e | ||
|
|
de1a126ec5 | ||
|
|
124939aaa4 | ||
|
|
a25a2143ce | ||
|
|
2365d77968 | ||
|
|
33c94ef083 | ||
|
|
c053eb71b6 | ||
|
|
76a5474b32 | ||
|
|
09e0208029 | ||
|
|
b5b70033e2 | ||
|
|
7c8fa2b880 | ||
|
|
a6befb5078 | ||
|
|
8e56d6b875 | ||
|
|
0bdd0d20e5 | ||
|
|
267c5c028c | ||
|
|
d2e3cb894b | ||
|
|
c25594257d | ||
|
|
ad09930bdf | ||
|
|
eb4ea42196 | ||
|
|
0ba5816cc7 | ||
|
|
8d0391806f | ||
|
|
b20b4a7159 | ||
|
|
904a278054 | ||
|
|
f469470aff | ||
|
|
354c0d7180 | ||
|
|
cca94792a4 | ||
|
|
9badb15e80 | ||
|
|
577be37e0e | ||
|
|
8c2d455ccd | ||
|
|
d3452a22cc | ||
|
|
7124057bad | ||
|
|
9258a44b8f | ||
|
|
c3d9ca62c1 | ||
|
|
3fd568855f | ||
|
|
0cc192bd3a | ||
|
|
435bed5da0 | ||
|
|
5a9dda64ce | ||
|
|
952b343cb3 | ||
|
|
f28b98a994 | ||
|
|
01a4b00a2b | ||
|
|
474860ef77 | ||
|
|
4d2bd1253d | ||
|
|
ca058b7a69 | ||
|
|
f4b7cdfe38 | ||
|
|
f6fb2e9116 | ||
|
|
cd58897f18 | ||
|
|
54a400ee71 | ||
|
|
4410c1416a | ||
|
|
da6cdaf635 | ||
|
|
5ba3d578ee | ||
|
|
a18b845ecd | ||
|
|
c18c5c3d92 | ||
|
|
553bafc127 | ||
|
|
05bbc56677 | ||
|
|
02766d349a | ||
|
|
5b22a472d6 | ||
|
|
e44de3ab27 | ||
|
|
edc864f9ba | ||
|
|
07c46abcbe | ||
|
|
8a440e753f | ||
|
|
f1794ba278 | ||
|
|
5ee77bbe8b | ||
|
|
8205fdc525 | ||
|
|
0b632d97f3 | ||
|
|
84b268f6fb | ||
|
|
f628e32ba5 | ||
|
|
e4910b9540 | ||
|
|
2e69dcb342 | ||
|
|
64be7df9e2 | ||
|
|
0f74aad641 | ||
|
|
b2ced97ac4 | ||
|
|
1ebf2a4376 | ||
|
|
8ce9cdaae3 | ||
|
|
b3df096358 | ||
|
|
81fd1b3cf9 | ||
|
|
17c2b3c194 | ||
|
|
a3ca1b2818 | ||
|
|
4b107c5303 | ||
|
|
e206d3f897 | ||
|
|
d98d70f670 | ||
|
|
fff843cfaf | ||
|
|
1048e2d6a3 | ||
|
|
5a45e7a631 | ||
|
|
fe928d4778 | ||
|
|
a140a5a324 | ||
|
|
77c4bbcaa5 | ||
|
|
a113497dd7 | ||
|
|
e3ef62f3bd | ||
|
|
fa5d0cf287 | ||
|
|
6c788d7675 | ||
|
|
55b483d82a | ||
|
|
a30beeba59 | ||
|
|
69576df254 | ||
|
|
b8d44ed98b | ||
|
|
aa15df2814 | ||
|
|
195ae35130 | ||
|
|
3dc071e036 | ||
|
|
5db73c9837 | ||
|
|
3a5ec36c54 | ||
|
|
7891b210e0 | ||
|
|
3076ad2ab9 | ||
|
|
d9873bbf38 | ||
|
|
3e6c16afd3 | ||
|
|
1ddd337d1c | ||
|
|
a182557ac3 | ||
|
|
4b32d400ee | ||
|
|
7e6b43a5c7 | ||
|
|
5b78f5761a | ||
|
|
2e13b01046 | ||
|
|
70fd0b635e | ||
|
|
885de2c1ca | ||
|
|
afc3b42241 | ||
|
|
a2f9ac0c8b | ||
|
|
761563155c | ||
|
|
8b00720640 | ||
|
|
a8409158a5 | ||
|
|
a3507cc2c1 | ||
|
|
b494339e10 | ||
|
|
f7e9adc2c8 | ||
|
|
f04e5bde74 | ||
|
|
6e488c2449 | ||
|
|
5fb8ebc9ec | ||
|
|
dd0d0a2522 | ||
|
|
f2b509d8a1 | ||
|
|
fa0df76f3c | ||
|
|
70ccc3d1fe | ||
|
|
20dcaabfdc | ||
|
|
c409eb6ac6 | ||
|
|
cf80501de5 | ||
|
|
3ce568ff44 | ||
|
|
ab0eb46a84 | ||
|
|
28e7371701 | ||
|
|
8e19728ea7 | ||
|
|
61b844f2b2 | ||
|
|
e0c7ad01ab | ||
|
|
34dcd74935 | ||
|
|
bbc5db8405 | ||
|
|
248dc50ee8 | ||
|
|
63979bc9cc | ||
|
|
58297e339b | ||
|
|
71817f318e | ||
|
|
1edb34fd67 | ||
|
|
789442372d | ||
|
|
5b57727d6d | ||
|
|
1e28e0bb03 | ||
|
|
333dd956bf | ||
|
|
c92b6ce2ad | ||
|
|
2a2013014c | ||
|
|
bdf5e388ca | ||
|
|
d76efbb9be | ||
|
|
eec37e3b71 | ||
|
|
63127f5443 | ||
|
|
d468c333a7 | ||
|
|
5ff929c22f | ||
|
|
cd0356b106 | ||
|
|
3cfcd252db | ||
|
|
104dbf7821 | ||
|
|
d6cea4832a | ||
|
|
347fecd881 | ||
|
|
e9f59b5d5e | ||
|
|
6489a0dd1f | ||
|
|
146e8d999c | ||
|
|
525db7b2c5 | ||
|
|
ad16f11f84 | ||
|
|
661bd45188 | ||
|
|
0224d48df4 | ||
|
|
460cc1673e | ||
|
|
14a1e96b68 | ||
|
|
a73748258f | ||
|
|
77cb21da2c | ||
|
|
497fdf8358 | ||
|
|
c8a2202028 | ||
|
|
8b78d6a7a0 | ||
|
|
5bf8769fb0 | ||
|
|
a75a2d6db6 | ||
|
|
db7895d3b6 | ||
|
|
fcc7ae162d | ||
|
|
b9504e4966 | ||
|
|
2814ee0547 | ||
|
|
984f82629c | ||
|
|
c5b7cfa9c3 | ||
|
|
2391fbc676 | ||
|
|
24d46224c1 | ||
|
|
e803ef09ad | ||
|
|
8b94dd6b59 | ||
|
|
fa8d39807d | ||
|
|
916d6a441a | ||
|
|
4be9481558 | ||
|
|
3fc9f750d1 | ||
|
|
f265cc24b4 | ||
|
|
49b2c5f43c | ||
|
|
72ffb0cbed | ||
|
|
ce5a4809fd | ||
|
|
2f4833b828 | ||
|
|
326fa00759 | ||
|
|
e38b9f1830 | ||
|
|
f7dde2a96c | ||
|
|
b77a9b127c | ||
|
|
7ea860d665 | ||
|
|
470dba8fc1 | ||
|
|
4d9f3cd5d7 | ||
|
|
f20b334f21 | ||
|
|
97ae32441e | ||
|
|
51b5ad3da3 | ||
|
|
e91cdb49be | ||
|
|
b1cec853be | ||
|
|
a3be38127c | ||
|
|
f4ac548619 | ||
|
|
285202aae2 | ||
|
|
bc42e88415 | ||
|
|
447945e438 | ||
|
|
ea2e66a58e | ||
|
|
233db64cc1 | ||
|
|
2d7dba024d | ||
|
|
4cbca5178a | ||
|
|
abe3fca1de | ||
|
|
58ae1df684 | ||
|
|
d8c6ae054c | ||
|
|
f7b62e5506 | ||
|
|
96b75033c0 | ||
|
|
300df874d7 | ||
|
|
a8617c6d4d | ||
|
|
ab04aeb855 | ||
|
|
43e6a3c196 | ||
|
|
3853f50082 | ||
|
|
062598bb40 | ||
|
|
54f35c68be | ||
|
|
6c6982163b | ||
|
|
ffc6a0f36e | ||
|
|
a6a0ae45b6 | ||
|
|
c1d5a012ea | ||
|
|
cd29535672 | ||
|
|
4d3c0d41f4 | ||
|
|
ec1a0502bf | ||
|
|
d10a2f6ab7 | ||
|
|
da55b23d21 | ||
|
|
d782dc2341 | ||
|
|
20d5256e40 | ||
|
|
b85c86022e | ||
|
|
f62502e123 | ||
|
|
1f11d2d340 | ||
|
|
1b1611b8d0 | ||
|
|
aeb0abf80a | ||
|
|
3f907d6a6f | ||
|
|
667966c5c1 | ||
|
|
00c63830e4 | ||
|
|
8b99ad4602 | ||
|
|
a5544d35f6 | ||
|
|
2e478aab98 | ||
|
|
4632b7b31e | ||
|
|
509a64ffb9 | ||
|
|
425cb6f65d | ||
|
|
f62c58f8de | ||
|
|
31b566f7a8 | ||
|
|
ed5da55149 | ||
|
|
660cbe4117 | ||
|
|
78c8e1060c | ||
|
|
1f30cae4ad | ||
|
|
1cb3b6aee4 | ||
|
|
2f66d7c47c | ||
|
|
0d45d72d70 | ||
|
|
d2c0bed9d5 | ||
|
|
0004c6b229 | ||
|
|
eeb5dc3ccf | ||
|
|
13d1d425ac | ||
|
|
a6deb2d994 | ||
|
|
7776a3214a | ||
|
|
8976a0c97a | ||
|
|
2c007cfed7 | ||
|
|
5e43ed0d72 | ||
|
|
8afbcf4713 | ||
|
|
6505297456 | ||
|
|
6b1e4f4211 | ||
|
|
db9afae2ea | ||
|
|
fa6107c85e | ||
|
|
08326794e8 | ||
|
|
4e1e37323d | ||
|
|
052355f5e2 | ||
|
|
95b0555c84 | ||
|
|
a8a9c8e4b0 | ||
|
|
bc6d184872 | ||
|
|
7963c4e808 | ||
|
|
2091ebdf5e | ||
|
|
339a4cf056 | ||
|
|
07dec7a11c | ||
|
|
705a51e566 | ||
|
|
c39cbc1a78 | ||
|
|
7b6ff527d5 | ||
|
|
a408e37fa1 | ||
|
|
966e50bddb | ||
|
|
22dcb7a77b | ||
|
|
1f9d672df1 | ||
|
|
c5ff839fb2 | ||
|
|
0ded110b80 | ||
|
|
1f6e63900d | ||
|
|
f988b2332e | ||
|
|
b9450bfcca | ||
|
|
46c850a941 | ||
|
|
37a2d919b0 | ||
|
|
3dc45a3e1d | ||
|
|
dc34fe8291 | ||
|
|
73f5bcb75b | ||
|
|
a081130081 | ||
|
|
614804b33c | ||
|
|
b85c183ea7 | ||
|
|
adb9b319c9 | ||
|
|
2b7bc2c36b | ||
|
|
40219109b0 | ||
|
|
4de89e92e4 | ||
|
|
4985d83b8f | ||
|
|
f6f64cc43d | ||
|
|
3d297fc2d7 | ||
|
|
c3742a9ae0 | ||
|
|
1fa3362ea7 | ||
|
|
c2cfe35f12 | ||
|
|
d051ea5e89 | ||
|
|
323542af50 | ||
|
|
82ec555d70 | ||
|
|
f1b2ec0833 | ||
|
|
d135bafdcb | ||
|
|
83f3fc2e80 | ||
|
|
03c2176a1d | ||
|
|
4773dcbc81 | ||
|
|
545f4c5547 | ||
|
|
5b9cbe30f8 | ||
|
|
5c6f4b9f0d | ||
|
|
7ed5bc021a | ||
|
|
30d5d7c1b3 | ||
|
|
41a0ad9f03 | ||
|
|
4b748b7a27 | ||
|
|
ef76afad35 | ||
|
|
e9f78db79d | ||
|
|
90d5bd85bc | ||
|
|
3f40e65c48 | ||
|
|
c53b0fef2a | ||
|
|
d8a351b58f | ||
|
|
52234eb172 | ||
|
|
217719347d | ||
|
|
9a9db3d265 | ||
|
|
16cd1a7561 | ||
|
|
4fa3db49a1 | ||
|
|
48fdb79de5 | ||
|
|
65a17c00c7 | ||
|
|
909dd4a109 | ||
|
|
ee654626ad | ||
|
|
8514d665ee | ||
|
|
86bc2cdf33 | ||
|
|
636c64caa9 | ||
|
|
d9fbb71d63 | ||
|
|
b9b99a12e5 | ||
|
|
eb7438997b | ||
|
|
8b6cf128af | ||
|
|
8d38b1fe62 | ||
|
|
43df612268 | ||
|
|
766272ff8c | ||
|
|
7371b38171 | ||
|
|
12ef276a7d | ||
|
|
1efd12f695 | ||
|
|
5cf53f51ac | ||
|
|
83886e40b6 | ||
|
|
a7842c9cae | ||
|
|
a8d7201ec5 | ||
|
|
c60f7dd08d | ||
|
|
2e02c1ffd9 | ||
|
|
2f77299136 | ||
|
|
25733a4aad | ||
|
|
eff7c3bda0 | ||
|
|
f260a9edb9 | ||
|
|
28857080d7 | ||
|
|
0acc0a1f86 | ||
|
|
53f3c2ae65 | ||
|
|
5b159498bb | ||
|
|
41ee96fdfe | ||
|
|
b8adb4cb0c | ||
|
|
fe24d22a62 | ||
|
|
f174ddba7a | ||
|
|
d4e345c7d4 | ||
|
|
3a662d4735 | ||
|
|
3ff6b3c31e | ||
|
|
5ca7fb82d6 | ||
|
|
6aa88ccdd2 | ||
|
|
cde462c6bf | ||
|
|
9bbb9df185 | ||
|
|
6b98d18789 | ||
|
|
5e0eb62a8e | ||
|
|
6dc9cdf15b | ||
|
|
56d2366699 | ||
|
|
0ba2d3cfa4 | ||
|
|
1a2135044c | ||
|
|
45b198dd3a | ||
|
|
9b46986edc | ||
|
|
60ec41ce73 | ||
|
|
feb8f416ac | ||
|
|
d1f6735171 | ||
|
|
eb6cbe37e1 | ||
|
|
2f4dbb4f90 | ||
|
|
4abc412348 | ||
|
|
e3f3e01504 | ||
|
|
f0f8703bf2 | ||
|
|
5c7136adb4 | ||
|
|
52219ced8b | ||
|
|
76d4ac1acb | ||
|
|
4af98d4ee6 | ||
|
|
00fead91c4 | ||
|
|
bce5c46739 | ||
|
|
0c6bbeb423 | ||
|
|
ab3762b2d9 | ||
|
|
c31f9cf23a | ||
|
|
16946d218a | ||
|
|
4c7053baf1 | ||
|
|
8d2492982b | ||
|
|
b8d38e76ef | ||
|
|
0b4b299099 | ||
|
|
55c5f5964d | ||
|
|
bbee0e7e50 | ||
|
|
7c0d90c8c9 | ||
|
|
9f4a528793 | ||
|
|
f56ee7d9c5 | ||
|
|
b3024e8fe6 | ||
|
|
5976e58415 | ||
|
|
7dea9c10cd | ||
|
|
950ccddfc8 | ||
|
|
649deb69f3 | ||
|
|
1aa5520d75 | ||
|
|
32fde3f838 | ||
|
|
a3e35414b7 | ||
|
|
386cba15b5 | ||
|
|
a16d757cd4 | ||
|
|
e0b119884c | ||
|
|
ab28680e66 | ||
|
|
05a8b887a9 | ||
|
|
f1801a9fed | ||
|
|
509cd428e9 | ||
|
|
68855216c9 | ||
|
|
2a6beb6a39 | ||
|
|
68860063fb | ||
|
|
e91b21ce2b | ||
|
|
be65b47645 | ||
|
|
0ce331f56a | ||
|
|
80b76a9527 | ||
|
|
8f8ef2bc0c | ||
|
|
35f7f3d015 | ||
|
|
6ddb92cac3 | ||
|
|
e2507a17e8 | ||
|
|
503f1f7ada | ||
|
|
5e89ff4d6b | ||
|
|
86d7f5aeee | ||
|
|
8d1db1601d |
1
.github/CODEOWNERS
vendored
1
.github/CODEOWNERS
vendored
@@ -1,6 +1,5 @@
|
|||||||
# Lines starting with '#' are comments.
|
# Lines starting with '#' are comments.
|
||||||
# Each line is a file pattern followed by one or more owners.
|
# Each line is a file pattern followed by one or more owners.
|
||||||
|
|
||||||
accounts/usbwallet @karalabe
|
accounts/usbwallet @karalabe
|
||||||
accounts/scwallet @gballet
|
accounts/scwallet @gballet
|
||||||
accounts/abi @gballet @MariusVanDerWijden
|
accounts/abi @gballet @MariusVanDerWijden
|
||||||
|
|||||||
6
.github/workflows/build-test.yml
vendored
6
.github/workflows/build-test.yml
vendored
@@ -7,7 +7,7 @@ on:
|
|||||||
- develop
|
- develop
|
||||||
|
|
||||||
pull_request:
|
pull_request:
|
||||||
branches:
|
branches:
|
||||||
- master
|
- master
|
||||||
- develop
|
- develop
|
||||||
|
|
||||||
@@ -15,7 +15,7 @@ jobs:
|
|||||||
unit-test:
|
unit-test:
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
go-version: [1.20.x]
|
go-version: [1.21.x]
|
||||||
os: [ubuntu-latest]
|
os: [ubuntu-latest]
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
steps:
|
steps:
|
||||||
@@ -47,5 +47,3 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
go mod download
|
go mod download
|
||||||
make geth
|
make geth
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
2
.github/workflows/commit-lint.yml
vendored
2
.github/workflows/commit-lint.yml
vendored
@@ -7,7 +7,7 @@ on:
|
|||||||
- develop
|
- develop
|
||||||
|
|
||||||
pull_request:
|
pull_request:
|
||||||
branches:
|
branches:
|
||||||
- master
|
- master
|
||||||
- develop
|
- develop
|
||||||
|
|
||||||
|
|||||||
56
.github/workflows/evm-tests.yml
vendored
Normal file
56
.github/workflows/evm-tests.yml
vendored
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
name: EVM Test
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
- develop
|
||||||
|
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
- develop
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
evm-test:
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
go-version: [1.21.x]
|
||||||
|
os: [ubuntu-latest]
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
steps:
|
||||||
|
- name: Install Go
|
||||||
|
uses: actions/setup-go@v3
|
||||||
|
with:
|
||||||
|
go-version: ${{ matrix.go-version }}
|
||||||
|
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- uses: actions/cache@v3
|
||||||
|
with:
|
||||||
|
# In order:
|
||||||
|
# * Module download cache
|
||||||
|
# * Build cache (Linux)
|
||||||
|
# * Build cache (Mac)
|
||||||
|
# * Build cache (Windows)
|
||||||
|
path: |
|
||||||
|
~/go/pkg/mod
|
||||||
|
~/.cache/go-build
|
||||||
|
~/Library/Caches/go-build
|
||||||
|
~\AppData\Local\go-build
|
||||||
|
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
|
||||||
|
restore-keys: |
|
||||||
|
${{ runner.os }}-go-
|
||||||
|
|
||||||
|
- name: EVM Test
|
||||||
|
env:
|
||||||
|
CGO_CFLAGS: "-O -D__BLST_PORTABLE__"
|
||||||
|
CGO_CFLAGS_ALLOW: "-O -D__BLST_PORTABLE__"
|
||||||
|
ANDROID_HOME: "" # Skip android test
|
||||||
|
run: |
|
||||||
|
git submodule update --init --depth 1 --recursive
|
||||||
|
go mod download
|
||||||
|
cd tests
|
||||||
|
sed -i -e 's/\/\/ bt.skipLoad/bt.skipLoad/g' block_test.go
|
||||||
|
bash -x run-evm-tests.sh
|
||||||
2
.github/workflows/integration-test.yml
vendored
2
.github/workflows/integration-test.yml
vendored
@@ -7,7 +7,7 @@ on:
|
|||||||
- develop
|
- develop
|
||||||
|
|
||||||
pull_request:
|
pull_request:
|
||||||
branches:
|
branches:
|
||||||
- master
|
- master
|
||||||
- develop
|
- develop
|
||||||
|
|
||||||
|
|||||||
8
.github/workflows/lint.yml
vendored
8
.github/workflows/lint.yml
vendored
@@ -7,7 +7,7 @@ on:
|
|||||||
- develop
|
- develop
|
||||||
|
|
||||||
pull_request:
|
pull_request:
|
||||||
branches:
|
branches:
|
||||||
- master
|
- master
|
||||||
- develop
|
- develop
|
||||||
|
|
||||||
@@ -15,7 +15,7 @@ jobs:
|
|||||||
golang-lint:
|
golang-lint:
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
go-version: [1.20.x]
|
go-version: [1.21.x]
|
||||||
os: [ubuntu-latest]
|
os: [ubuntu-latest]
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
steps:
|
steps:
|
||||||
@@ -44,13 +44,13 @@ jobs:
|
|||||||
${{ runner.os }}-go-
|
${{ runner.os }}-go-
|
||||||
|
|
||||||
- run: |
|
- run: |
|
||||||
go mod download
|
go mod tidy
|
||||||
|
|
||||||
- name: golangci-lint
|
- name: golangci-lint
|
||||||
uses: golangci/golangci-lint-action@v3
|
uses: golangci/golangci-lint-action@v3
|
||||||
with:
|
with:
|
||||||
# Optional: version of golangci-lint to use in form of v1.2 or v1.2.3 or `latest` to use the latest version
|
# Optional: version of golangci-lint to use in form of v1.2 or v1.2.3 or `latest` to use the latest version
|
||||||
version: v1.52.2
|
version: v1.55.2
|
||||||
working-directory: ./
|
working-directory: ./
|
||||||
skip-pkg-cache: true
|
skip-pkg-cache: true
|
||||||
skip-cache: true
|
skip-cache: true
|
||||||
|
|||||||
37
.github/workflows/nancy.yml
vendored
Normal file
37
.github/workflows/nancy.yml
vendored
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
name: Go Nancy
|
||||||
|
|
||||||
|
on:
|
||||||
|
# Scan changed files in PRs (diff-aware scanning):
|
||||||
|
pull_request: {}
|
||||||
|
# Scan on-demand through GitHub Actions interface:
|
||||||
|
workflow_dispatch: {}
|
||||||
|
# Scan mainline branches and report all findings:
|
||||||
|
push:
|
||||||
|
branches: ["master", "develop"]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
go-version: [1.21.x]
|
||||||
|
os: [ubuntu-latest]
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
steps:
|
||||||
|
- name: Check out code into the Go module directory
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Set up Go 1.x in order to write go.list file
|
||||||
|
uses: actions/setup-go@v2
|
||||||
|
with:
|
||||||
|
go-version: ${{ matrix.go-version }}
|
||||||
|
|
||||||
|
- name: Go mod tidy
|
||||||
|
run: go mod tidy
|
||||||
|
|
||||||
|
- name: WriteGoList
|
||||||
|
run: go list -json -deps ./... > go.list
|
||||||
|
|
||||||
|
- name: Nancy
|
||||||
|
uses: sonatype-nexus-community/nancy-github-action@main
|
||||||
|
with:
|
||||||
|
nancyCommand: sleuth --loud
|
||||||
2
.github/workflows/pre-release.yml
vendored
2
.github/workflows/pre-release.yml
vendored
@@ -15,7 +15,7 @@ jobs:
|
|||||||
name: Build Release
|
name: Build Release
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
go-version: [1.20.x]
|
go-version: [1.21.x]
|
||||||
os: [ubuntu-latest, macos-latest, windows-latest]
|
os: [ubuntu-latest, macos-latest, windows-latest]
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
steps:
|
steps:
|
||||||
|
|||||||
2
.github/workflows/release.yml
vendored
2
.github/workflows/release.yml
vendored
@@ -14,7 +14,7 @@ jobs:
|
|||||||
name: Build Release
|
name: Build Release
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
go-version: [1.20.x]
|
go-version: [1.21.x]
|
||||||
os: [ubuntu-latest, macos-latest, windows-latest]
|
os: [ubuntu-latest, macos-latest, windows-latest]
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
steps:
|
steps:
|
||||||
|
|||||||
5
.github/workflows/unit-test.yml
vendored
5
.github/workflows/unit-test.yml
vendored
@@ -7,7 +7,7 @@ on:
|
|||||||
- develop
|
- develop
|
||||||
|
|
||||||
pull_request:
|
pull_request:
|
||||||
branches:
|
branches:
|
||||||
- master
|
- master
|
||||||
- develop
|
- develop
|
||||||
|
|
||||||
@@ -15,7 +15,7 @@ jobs:
|
|||||||
unit-test:
|
unit-test:
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
go-version: [1.20.x]
|
go-version: [1.21.x]
|
||||||
os: [ubuntu-latest]
|
os: [ubuntu-latest]
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
steps:
|
steps:
|
||||||
@@ -51,4 +51,3 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
go mod download
|
go mod download
|
||||||
make test
|
make test
|
||||||
|
|
||||||
|
|||||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -14,7 +14,6 @@
|
|||||||
*/**/*tx_database*
|
*/**/*tx_database*
|
||||||
*/**/*dapps*
|
*/**/*dapps*
|
||||||
build/_vendor/pkg
|
build/_vendor/pkg
|
||||||
/tests/truffle/storage
|
|
||||||
|
|
||||||
#*
|
#*
|
||||||
.#*
|
.#*
|
||||||
@@ -53,3 +52,5 @@ cmd/geth/__debug_bin
|
|||||||
cmd/bootnode/bootnode
|
cmd/bootnode/bootnode
|
||||||
graphql/__debug_bin
|
graphql/__debug_bin
|
||||||
logs/
|
logs/
|
||||||
|
|
||||||
|
tests/spec-tests/
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ output:
|
|||||||
linters:
|
linters:
|
||||||
disable-all: true
|
disable-all: true
|
||||||
enable:
|
enable:
|
||||||
- goconst
|
|
||||||
- goimports
|
- goimports
|
||||||
- gosimple
|
- gosimple
|
||||||
- govet
|
- govet
|
||||||
@@ -42,9 +41,6 @@ linters:
|
|||||||
linters-settings:
|
linters-settings:
|
||||||
gofmt:
|
gofmt:
|
||||||
simplify: true
|
simplify: true
|
||||||
goconst:
|
|
||||||
min-len: 3 # minimum length of string constant
|
|
||||||
min-occurrences: 6 # minimum number of occurrences
|
|
||||||
|
|
||||||
issues:
|
issues:
|
||||||
exclude-rules:
|
exclude-rules:
|
||||||
|
|||||||
2
.nancy-ignore
Normal file
2
.nancy-ignore
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
CVE-2024-34478 # "CWE-754: Improper Check for Unusual or Exceptional Conditions." This vulnerability is BTC only, BSC does not have the issue.
|
||||||
|
CVE-2024-6104 # "CWE-532: Information Exposure Through Log Files" This is caused by the vulnerabilities go-retryablehttp@v0.7.4, it is only used in cmd devp2p, impact is limited. will upgrade to v0.7.7 later
|
||||||
55
.travis.yml
55
.travis.yml
@@ -9,18 +9,6 @@ jobs:
|
|||||||
- azure-osx
|
- azure-osx
|
||||||
|
|
||||||
include:
|
include:
|
||||||
# This builder only tests code linters on latest version of Go
|
|
||||||
- stage: lint
|
|
||||||
os: linux
|
|
||||||
dist: bionic
|
|
||||||
go: 1.20.x
|
|
||||||
env:
|
|
||||||
- lint
|
|
||||||
git:
|
|
||||||
submodules: false # avoid cloning ethereum/tests
|
|
||||||
script:
|
|
||||||
- go run build/ci.go lint
|
|
||||||
|
|
||||||
# These builders create the Docker sub-images for multi-arch push and each
|
# These builders create the Docker sub-images for multi-arch push and each
|
||||||
# will attempt to push the multi-arch image if they are the last builder
|
# will attempt to push the multi-arch image if they are the last builder
|
||||||
- stage: build
|
- stage: build
|
||||||
@@ -28,7 +16,7 @@ jobs:
|
|||||||
os: linux
|
os: linux
|
||||||
arch: amd64
|
arch: amd64
|
||||||
dist: bionic
|
dist: bionic
|
||||||
go: 1.20.x
|
go: 1.21.x
|
||||||
env:
|
env:
|
||||||
- docker
|
- docker
|
||||||
services:
|
services:
|
||||||
@@ -45,7 +33,7 @@ jobs:
|
|||||||
os: linux
|
os: linux
|
||||||
arch: arm64
|
arch: arm64
|
||||||
dist: bionic
|
dist: bionic
|
||||||
go: 1.20.x
|
go: 1.21.x
|
||||||
env:
|
env:
|
||||||
- docker
|
- docker
|
||||||
services:
|
services:
|
||||||
@@ -63,10 +51,9 @@ jobs:
|
|||||||
os: linux
|
os: linux
|
||||||
dist: bionic
|
dist: bionic
|
||||||
sudo: required
|
sudo: required
|
||||||
go: 1.20.x
|
go: 1.21.x
|
||||||
env:
|
env:
|
||||||
- azure-linux
|
- azure-linux
|
||||||
- GO111MODULE=on
|
|
||||||
git:
|
git:
|
||||||
submodules: false # avoid cloning ethereum/tests
|
submodules: false # avoid cloning ethereum/tests
|
||||||
addons:
|
addons:
|
||||||
@@ -97,56 +84,51 @@ jobs:
|
|||||||
- stage: build
|
- stage: build
|
||||||
if: type = push
|
if: type = push
|
||||||
os: osx
|
os: osx
|
||||||
go: 1.20.x
|
osx_image: xcode14.2
|
||||||
|
go: 1.21.x
|
||||||
env:
|
env:
|
||||||
- azure-osx
|
- azure-osx
|
||||||
- GO111MODULE=on
|
|
||||||
git:
|
git:
|
||||||
submodules: false # avoid cloning ethereum/tests
|
submodules: false # avoid cloning ethereum/tests
|
||||||
script:
|
script:
|
||||||
- go run build/ci.go install -dlgo
|
- go run build/ci.go install -dlgo
|
||||||
- go run build/ci.go archive -type tar -signer OSX_SIGNING_KEY -signify SIGNIFY_KEY -upload gethstore/builds
|
- go run build/ci.go archive -type tar -signer OSX_SIGNING_KEY -signify SIGNIFY_KEY -upload gethstore/builds
|
||||||
|
- go run build/ci.go install -dlgo -arch arm64
|
||||||
|
- go run build/ci.go archive -arch arm64 -type tar -signer OSX_SIGNING_KEY -signify SIGNIFY_KEY -upload gethstore/builds
|
||||||
|
|
||||||
# These builders run the tests
|
# These builders run the tests
|
||||||
- stage: build
|
- stage: build
|
||||||
os: linux
|
os: linux
|
||||||
arch: amd64
|
arch: amd64
|
||||||
dist: bionic
|
dist: bionic
|
||||||
go: 1.20.x
|
go: 1.21.x
|
||||||
env:
|
|
||||||
- GO111MODULE=on
|
|
||||||
script:
|
script:
|
||||||
- go run build/ci.go test $TEST_PACKAGES
|
- travis_wait 30 go run build/ci.go test $TEST_PACKAGES
|
||||||
|
|
||||||
- stage: build
|
- stage: build
|
||||||
if: type = pull_request
|
if: type = pull_request
|
||||||
os: linux
|
os: linux
|
||||||
arch: arm64
|
arch: arm64
|
||||||
dist: bionic
|
dist: bionic
|
||||||
go: 1.19.x
|
go: 1.20.x
|
||||||
env:
|
|
||||||
- GO111MODULE=on
|
|
||||||
script:
|
script:
|
||||||
- go run build/ci.go test $TEST_PACKAGES
|
- travis_wait 30 go run build/ci.go test $TEST_PACKAGES
|
||||||
|
|
||||||
- stage: build
|
- stage: build
|
||||||
os: linux
|
os: linux
|
||||||
dist: bionic
|
dist: bionic
|
||||||
go: 1.19.x
|
go: 1.20.x
|
||||||
env:
|
|
||||||
- GO111MODULE=on
|
|
||||||
script:
|
script:
|
||||||
- go run build/ci.go test $TEST_PACKAGES
|
- travis_wait 30 go run build/ci.go test $TEST_PACKAGES
|
||||||
|
|
||||||
# This builder does the Ubuntu PPA nightly uploads
|
# This builder does the Ubuntu PPA nightly uploads
|
||||||
- stage: build
|
- stage: build
|
||||||
if: type = cron || (type = push && tag ~= /^v[0-9]/)
|
if: type = cron || (type = push && tag ~= /^v[0-9]/)
|
||||||
os: linux
|
os: linux
|
||||||
dist: bionic
|
dist: bionic
|
||||||
go: 1.20.x
|
go: 1.21.x
|
||||||
env:
|
env:
|
||||||
- ubuntu-ppa
|
- ubuntu-ppa
|
||||||
- GO111MODULE=on
|
|
||||||
git:
|
git:
|
||||||
submodules: false # avoid cloning ethereum/tests
|
submodules: false # avoid cloning ethereum/tests
|
||||||
addons:
|
addons:
|
||||||
@@ -167,10 +149,9 @@ jobs:
|
|||||||
if: type = cron
|
if: type = cron
|
||||||
os: linux
|
os: linux
|
||||||
dist: bionic
|
dist: bionic
|
||||||
go: 1.20.x
|
go: 1.21.x
|
||||||
env:
|
env:
|
||||||
- azure-purge
|
- azure-purge
|
||||||
- GO111MODULE=on
|
|
||||||
git:
|
git:
|
||||||
submodules: false # avoid cloning ethereum/tests
|
submodules: false # avoid cloning ethereum/tests
|
||||||
script:
|
script:
|
||||||
@@ -181,9 +162,7 @@ jobs:
|
|||||||
if: type = cron
|
if: type = cron
|
||||||
os: linux
|
os: linux
|
||||||
dist: bionic
|
dist: bionic
|
||||||
go: 1.20.x
|
go: 1.21.x
|
||||||
env:
|
|
||||||
- GO111MODULE=on
|
|
||||||
script:
|
script:
|
||||||
- go run build/ci.go test -race $TEST_PACKAGES
|
- travis_wait 30 go run build/ci.go test -race $TEST_PACKAGES
|
||||||
|
|
||||||
|
|||||||
454
CHANGELOG.md
454
CHANGELOG.md
@@ -1,4 +1,458 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
## v1.4.13
|
||||||
|
|
||||||
|
### BUGFIX
|
||||||
|
* [\#2602](https://github.com/bnb-chain/bsc/pull/2602) fix: prune-state when specify --triesInMemory 32
|
||||||
|
* [\#2579](https://github.com/bnb-chain/bsc/pull/00025790) fix: only take non-mempool tx to calculate bid price
|
||||||
|
|
||||||
|
### FEATURE
|
||||||
|
* [\#2634](https://github.com/bnb-chain/bsc/pull/2634) config: setup Testnet Bohr hardfork date
|
||||||
|
* [\#2482](https://github.com/bnb-chain/bsc/pull/2482) BEP-341: Validators can produce consecutive blocks
|
||||||
|
* [\#2502](https://github.com/bnb-chain/bsc/pull/2502) BEP-402: Complete Missing Fields in Block Header to Generate Signature
|
||||||
|
* [\#2558](https://github.com/bnb-chain/bsc/pull/2558) BEP-404: Clear Miner History when Switching Validators Set
|
||||||
|
* [\#2605](https://github.com/bnb-chain/bsc/pull/2605) feat: add bohr upgrade contracts bytecode
|
||||||
|
* [\#2614](https://github.com/bnb-chain/bsc/pull/2614) fix: update stakehub bytecode after zero address agent issue fixed
|
||||||
|
* [\#2608](https://github.com/bnb-chain/bsc/pull/2608) consensus/parlia: modify mining time for last block in one turn
|
||||||
|
* [\#2618](https://github.com/bnb-chain/bsc/pull/2618) consensus/parlia: exclude inturn validator when calculate backoffTime
|
||||||
|
* [\#2621](https://github.com/bnb-chain/bsc/pull/2621) core: not record zero hash beacon block root with Parlia engine
|
||||||
|
|
||||||
|
### IMPROVEMENT
|
||||||
|
* [\#2589](https://github.com/bnb-chain/bsc/pull/2589) core/vote: vote before committing state and writing block
|
||||||
|
* [\#2596](https://github.com/bnb-chain/bsc/pull/2596) core: improve the network stability when double sign happens
|
||||||
|
* [\#2600](https://github.com/bnb-chain/bsc/pull/2600) core: cache block after wroten into db
|
||||||
|
* [\#2629](https://github.com/bnb-chain/bsc/pull/2629) utils: add GetTopAddr to analyse large traffic
|
||||||
|
* [\#2591](https://github.com/bnb-chain/bsc/pull/2591) consensus/parlia: add GetJustifiedNumber and GetFinalizedNumber
|
||||||
|
* [\#2611](https://github.com/bnb-chain/bsc/pull/2611) cmd/utils: add new flag OverridePassedForkTime
|
||||||
|
* [\#2603](https://github.com/bnb-chain/bsc/pull/2603) faucet: rate limit initial implementation
|
||||||
|
* [\#2622](https://github.com/bnb-chain/bsc/pull/2622) tests: fix evm-test CI
|
||||||
|
* [\#2628](https://github.com/bnb-chain/bsc/pull/2628) Makefile: use docker compose v2 instead of v1
|
||||||
|
|
||||||
|
## v1.4.12
|
||||||
|
|
||||||
|
### BUGFIX
|
||||||
|
* [\#2557](https://github.com/bnb-chain/bsc/pull/2557) fix: fix state inspect error after pruned state
|
||||||
|
* [\#2562](https://github.com/bnb-chain/bsc/pull/2562) fix: delete unexpected block
|
||||||
|
* [\#2566](https://github.com/bnb-chain/bsc/pull/2566) core: avoid to cache block before wroten into db
|
||||||
|
* [\#2567](https://github.com/bnb-chain/bsc/pull/2567) fix: fix statedb copy
|
||||||
|
* [\#2574](https://github.com/bnb-chain/bsc/pull/2574) core: adapt highestVerifiedHeader to FastFinality
|
||||||
|
* [\#2542](https://github.com/bnb-chain/bsc/pull/2542) fix: pruneancient freeze from the previous position when the first time
|
||||||
|
* [\#2564](https://github.com/bnb-chain/bsc/pull/2564) fix: the bug of blobsidecars and downloader with multi-database
|
||||||
|
* [\#2582](https://github.com/bnb-chain/bsc/pull/2582) fix: remove delete and dangling side chains in prunefreezer
|
||||||
|
|
||||||
|
### FEATURE
|
||||||
|
* [\#2513](https://github.com/bnb-chain/bsc/pull/2513) cmd/jsutils: add a tool to get performance between a range of blocks
|
||||||
|
* [\#2569](https://github.com/bnb-chain/bsc/pull/2569) cmd/jsutils: add a tool to get slash count
|
||||||
|
* [\#2583](https://github.com/bnb-chain/bsc/pull/2583) cmd/jsutill: add log about validator name
|
||||||
|
|
||||||
|
### IMPROVEMENT
|
||||||
|
* [\#2546](https://github.com/bnb-chain/bsc/pull/2546) go.mod: update missing dependency
|
||||||
|
* [\#2559](https://github.com/bnb-chain/bsc/pull/2559) nancy: ignore go-retryablehttp@v0.7.4 in .nancy-ignore
|
||||||
|
* [\#2556](https://github.com/bnb-chain/bsc/pull/2556) chore: update greenfield cometbft version
|
||||||
|
* [\#2561](https://github.com/bnb-chain/bsc/pull/2561) tests: fix unstable test
|
||||||
|
* [\#2572](https://github.com/bnb-chain/bsc/pull/2572) core: clearup testflag for Cancun and Haber
|
||||||
|
* [\#2573](https://github.com/bnb-chain/bsc/pull/2573) cmd/utils: support use NetworkId to distinguish chapel when do syncing
|
||||||
|
* [\#2538](https://github.com/bnb-chain/bsc/pull/2538) feat: enhance bid comparison and reply bidding results && detail logs
|
||||||
|
* [\#2568](https://github.com/bnb-chain/bsc/pull/2568) core/vote: not vote if too late for next in turn validator
|
||||||
|
* [\#2576](https://github.com/bnb-chain/bsc/pull/2576) miner/worker: broadcast block immediately once sealed
|
||||||
|
* [\#2580](https://github.com/bnb-chain/bsc/pull/2580) freezer: Opt freezer env checking
|
||||||
|
|
||||||
|
## v1.4.11
|
||||||
|
|
||||||
|
### BUGFIX
|
||||||
|
* [\#2534](https://github.com/bnb-chain/bsc/pull/2534) fix: nil pointer when clear simulating bid
|
||||||
|
* [\#2535](https://github.com/bnb-chain/bsc/pull/2535) upgrade: add HaberFix hardfork
|
||||||
|
|
||||||
|
## v1.4.10
|
||||||
|
### FEATURE
|
||||||
|
NA
|
||||||
|
|
||||||
|
### IMPROVEMENT
|
||||||
|
* [\#2512](https://github.com/bnb-chain/bsc/pull/2512) feat: add mev helper params and func
|
||||||
|
* [\#2508](https://github.com/bnb-chain/bsc/pull/2508) perf: speedup pbss trienode read
|
||||||
|
* [\#2509](https://github.com/bnb-chain/bsc/pull/2509) perf: optimize chain commit performance for multi-database
|
||||||
|
* [\#2451](https://github.com/bnb-chain/bsc/pull/2451) core/forkchoice: improve stability when inturn block not generate
|
||||||
|
|
||||||
|
### BUGFIX
|
||||||
|
* [\#2518](https://github.com/bnb-chain/bsc/pull/2518) fix: remove zero gasprice check for BSC
|
||||||
|
* [\#2519](https://github.com/bnb-chain/bsc/pull/2519) UT: random failure of TestSnapSyncWithBlobs
|
||||||
|
* [\#2515](https://github.com/bnb-chain/bsc/pull/2515) fix getBlobSidecars by ethclient
|
||||||
|
* [\#2525](https://github.com/bnb-chain/bsc/pull/2525) fix: ensure empty withdrawals after cancun before broadcast
|
||||||
|
|
||||||
|
## v1.4.9
|
||||||
|
### FEATURE
|
||||||
|
* [\#2463](https://github.com/bnb-chain/bsc/pull/2463) utils: add check_blobtx.js
|
||||||
|
* [\#2470](https://github.com/bnb-chain/bsc/pull/2470) jsutils: faucet successful requests within blocks
|
||||||
|
* [\#2467](https://github.com/bnb-chain/bsc/pull/2467) internal/ethapi: add optional parameter for blobSidecars
|
||||||
|
|
||||||
|
### IMPROVEMENT
|
||||||
|
* [\#2462](https://github.com/bnb-chain/bsc/pull/2462) cmd/utils: add a flag to change breathe block interval for testing
|
||||||
|
* [\#2497](https://github.com/bnb-chain/bsc/pull/2497) params/config: add Bohr hardfork
|
||||||
|
* [\#2479](https://github.com/bnb-chain/bsc/pull/2479) dev: ensure consistency in BPS bundle result
|
||||||
|
|
||||||
|
### BUGFIX
|
||||||
|
* [\#2461](https://github.com/bnb-chain/bsc/pull/2461) eth/handler: check lists in body before broadcast blocks
|
||||||
|
* [\#2455](https://github.com/bnb-chain/bsc/pull/2455) cmd: fix memory leak when big dataset
|
||||||
|
* [\#2466](https://github.com/bnb-chain/bsc/pull/2466) sync: fix some sync issues caused by prune-block.
|
||||||
|
* [\#2475](https://github.com/bnb-chain/bsc/pull/2475) fix: move mev op to MinerAPI & add command to console
|
||||||
|
* [\#2473](https://github.com/bnb-chain/bsc/pull/2473) fix: limit the gas price of the mev bid
|
||||||
|
* [\#2484](https://github.com/bnb-chain/bsc/pull/2484) fix: fix inspect database error
|
||||||
|
* [\#2481](https://github.com/bnb-chain/bsc/pull/2481) fix: keep 9W blocks in ancient db when prune block
|
||||||
|
* [\#2495](https://github.com/bnb-chain/bsc/pull/2495) fix: add an empty freeze db
|
||||||
|
* [\#2507](https://github.com/bnb-chain/bsc/pull/2507) fix: waiting for the last simulation before pick best bid
|
||||||
|
|
||||||
|
## v1.4.8
|
||||||
|
### FEATURE
|
||||||
|
* [\#2483](https://github.com/bnb-chain/bsc/pull/2483) core/vm: add secp256r1 into PrecompiledContractsHaber
|
||||||
|
* [\#2400](https://github.com/bnb-chain/bsc/pull/2400) RIP-7212: Precompile for secp256r1 Curve Support
|
||||||
|
|
||||||
|
### IMPROVEMENT
|
||||||
|
NA
|
||||||
|
|
||||||
|
### BUGFIX
|
||||||
|
NA
|
||||||
|
|
||||||
|
## v1.4.7
|
||||||
|
### FEATURE
|
||||||
|
* [\#2439](https://github.com/bnb-chain/bsc/pull/2439) config: setup Mainnet Tycho(Cancun) hardfork date
|
||||||
|
|
||||||
|
### IMPROVEMENT
|
||||||
|
* [\#2396](https://github.com/bnb-chain/bsc/pull/2396) metrics: add blockInsertMgaspsGauge to trace mgasps
|
||||||
|
* [\#2411](https://github.com/bnb-chain/bsc/pull/2411) build(deps): bump golang.org/x/net from 0.19.0 to 0.23.0
|
||||||
|
* [\#2435](https://github.com/bnb-chain/bsc/pull/2435) txpool: limit max gas when mining is enabled
|
||||||
|
* [\#2438](https://github.com/bnb-chain/bsc/pull/2438) fix: performance issue when load journal
|
||||||
|
* [\#2440](https://github.com/bnb-chain/bsc/pull/2440) nancy: add files .nancy-ignore
|
||||||
|
|
||||||
|
### BUGFIX
|
||||||
|
NA
|
||||||
|
|
||||||
|
## v1.4.6
|
||||||
|
### FEATURE
|
||||||
|
* [\#2227](https://github.com/bnb-chain/bsc/pull/2227) core: separated databases for block data
|
||||||
|
* [\#2404](https://github.com/bnb-chain/bsc/pull/2404) cmd, p2p: filter peers by regex on name
|
||||||
|
|
||||||
|
### IMPROVEMENT
|
||||||
|
* [\#2201](https://github.com/bnb-chain/bsc/pull/2201) chore: render system bytecode by go:embed
|
||||||
|
* [\#2363](https://github.com/bnb-chain/bsc/pull/2363) feat: greedy merge tx in bid
|
||||||
|
* [\#2389](https://github.com/bnb-chain/bsc/pull/2389) deps: update prsym to solve warning about quic-go version
|
||||||
|
* [\#2341](https://github.com/bnb-chain/bsc/pull/2341) core/trie: persist TrieJournal to journal file instead of kv database
|
||||||
|
* [\#2395](https://github.com/bnb-chain/bsc/pull/2395) fix: trieJournal format compatible old db format
|
||||||
|
* [\#2406](https://github.com/bnb-chain/bsc/pull/2406) feat: adaptive for loading journal file or journal kv during loadJournal
|
||||||
|
* [\#2390](https://github.com/bnb-chain/bsc/pull/2390) chore: fix function names in comment
|
||||||
|
* [\#2399](https://github.com/bnb-chain/bsc/pull/2399) chore: fix some typos in comments
|
||||||
|
* [\#2408](https://github.com/bnb-chain/bsc/pull/2408) chore: fix some typos in comments
|
||||||
|
* [\#2416](https://github.com/bnb-chain/bsc/pull/2416) fix: fix function names
|
||||||
|
* [\#2424](https://github.com/bnb-chain/bsc/pull/2424) feat: recommit bid when newBidCh is empty to maximize mev reward
|
||||||
|
* [\#2430](https://github.com/bnb-chain/bsc/pull/2430) fix: oom caused by non-discarded mev simulation env
|
||||||
|
* [\#2428](https://github.com/bnb-chain/bsc/pull/2428) chore: add metric & log for blobTx
|
||||||
|
* [\#2419](https://github.com/bnb-chain/bsc/pull/2419) metrics: add doublesign counter
|
||||||
|
|
||||||
|
### BUGFIX
|
||||||
|
* [\#2244](https://github.com/bnb-chain/bsc/pull/2244) cmd/geth: fix importBlock
|
||||||
|
* [\#2391](https://github.com/bnb-chain/bsc/pull/2391) fix: print value instead of pointer in ConfigCompatError
|
||||||
|
* [\#2398](https://github.com/bnb-chain/bsc/pull/2398) fix: no import blocks before or equal to the finalized height
|
||||||
|
* [\#2401](https://github.com/bnb-chain/bsc/pull/2401) fix: allow fast node to rewind after abnormal shutdown
|
||||||
|
* [\#2403](https://github.com/bnb-chain/bsc/pull/2403) fix: NPE
|
||||||
|
* [\#2423](https://github.com/bnb-chain/bsc/pull/2423) eth/gasprice: add query limit to defend DDOS attack
|
||||||
|
* [\#2425](https://github.com/bnb-chain/bsc/pull/2425) fix: adapt journal for cmd
|
||||||
|
|
||||||
|
## v1.4.5
|
||||||
|
### FEATURE
|
||||||
|
* [\#2378](https://github.com/bnb-chain/bsc/pull/2378) config: setup Testnet Tycho(Cancun) hardfork date
|
||||||
|
|
||||||
|
### IMPROVEMENT
|
||||||
|
* [\#2333](https://github.com/bnb-chain/bsc/pull/2333) remove code that will not be executed
|
||||||
|
* [\#2369](https://github.com/bnb-chain/bsc/pull/2369) core: stateDb has no trie and no snap return err
|
||||||
|
|
||||||
|
### BUGFIX
|
||||||
|
* [\#2359](https://github.com/bnb-chain/bsc/pull/2359) triedb: do not open state freezer under notries
|
||||||
|
|
||||||
|
## v1.4.4
|
||||||
|
### FEATURE
|
||||||
|
* [\#2279](https://github.com/bnb-chain/bsc/pull/2279) BlobTx: implement EIP-4844 on BSC
|
||||||
|
* [\#2337](https://github.com/bnb-chain/bsc/pull/2337) 4844: bugfix and improve
|
||||||
|
* [\#2339](https://github.com/bnb-chain/bsc/pull/2339) fix: missing block asigment WithSidecars
|
||||||
|
* [\#2350](https://github.com/bnb-chain/bsc/pull/2350) cancun: change empty withdrawHash value of header
|
||||||
|
* [\#2335](https://github.com/bnb-chain/bsc/pull/2335) upgrade: update system contracts bytes code and hardfork time of Feynman upgrade
|
||||||
|
* [\#2323](https://github.com/bnb-chain/bsc/pull/2323) feat: export GasCeil in mev_params
|
||||||
|
* [\#2357](https://github.com/bnb-chain/bsc/pull/2357) feat: add bid fee ceil in mev_params
|
||||||
|
|
||||||
|
### IMPROVEMENT
|
||||||
|
* [\#2321](https://github.com/bnb-chain/bsc/pull/2321) test: use full syncmode to run rpc node
|
||||||
|
* [\#2338](https://github.com/bnb-chain/bsc/pull/2338) cmd: include more node info in metrics
|
||||||
|
* [\#2342](https://github.com/bnb-chain/bsc/pull/2342) p2p: add metrics for inbound/outbound peers
|
||||||
|
* [\#2334](https://github.com/bnb-chain/bsc/pull/2334) core: improve chain rewinding mechanism
|
||||||
|
* [\#2352](https://github.com/bnb-chain/bsc/pull/2352) core: fix block report when chain is not setHead
|
||||||
|
|
||||||
|
### BUGFIX
|
||||||
|
NA
|
||||||
|
|
||||||
|
## v1.4.3
|
||||||
|
### FEATURE
|
||||||
|
* [\#2241](https://github.com/bnb-chain/bsc/pull/2241) cmd/utils, core/rawdb, triedb/pathdb: flip hash to path scheme
|
||||||
|
* [\#2312](https://github.com/bnb-chain/bsc/pull/2312) cmd/utils, node: switch to Pebble as the default db if none exists
|
||||||
|
|
||||||
|
### IMPROVEMENT
|
||||||
|
* [\#2228](https://github.com/bnb-chain/bsc/pull/2228) core: rephrase TriesInMemory log
|
||||||
|
* [\#2234](https://github.com/bnb-chain/bsc/pull/2234) cmd/utils: disable snap protocol for fast node
|
||||||
|
* [\#2236](https://github.com/bnb-chain/bsc/pull/2236) build(deps): bump github.com/quic-go/quic-go from 0.39.3 to 0.39.4
|
||||||
|
* [\#2240](https://github.com/bnb-chain/bsc/pull/2240) core/state: fix taskResult typo
|
||||||
|
|
||||||
|
* [\#2280](https://github.com/bnb-chain/bsc/pull/2280) cmd/utils, core: only full sync for fast nodes
|
||||||
|
* [\#2298](https://github.com/bnb-chain/bsc/pull/2298) cmd, node: initialize ports with --instance
|
||||||
|
* [\#2302](https://github.com/bnb-chain/bsc/pull/2302) cmd/geth, core/rawdb: add dbDeleteTrieState
|
||||||
|
* [\#2304](https://github.com/bnb-chain/bsc/pull/2304) eth/ethconfig: remove overridekepler and overrideshanghai
|
||||||
|
* [\#2307](https://github.com/bnb-chain/bsc/pull/2307) internal/ethapi: add net_nodeInfo
|
||||||
|
* [\#2311](https://github.com/bnb-chain/bsc/pull/2311) Port cancun related changes from unreleased v1.14.0
|
||||||
|
* [\#2313](https://github.com/bnb-chain/bsc/pull/2313) tests/truffle: use hbss to run test
|
||||||
|
* [\#2314](https://github.com/bnb-chain/bsc/pull/2314) cmd/jsutil: dump MinGasPrice for validator
|
||||||
|
* [\#2317](https://github.com/bnb-chain/bsc/pull/2317) feat: add mev metrics
|
||||||
|
|
||||||
|
### BUGFIX
|
||||||
|
* [\#2272](https://github.com/bnb-chain/bsc/pull/2272) parlia: add state prepare for internal SC transaction
|
||||||
|
* [\#2277](https://github.com/bnb-chain/bsc/pull/2277) fix: systemTx should be always at the end of block
|
||||||
|
* [\#2299](https://github.com/bnb-chain/bsc/pull/2299) fix: add FeynmanFix upgrade for a testnet issue
|
||||||
|
* [\#2310](https://github.com/bnb-chain/bsc/pull/2310) core/vm: fix PrecompiledContractsCancun
|
||||||
|
|
||||||
|
## v1.4.2
|
||||||
|
### FEATURE
|
||||||
|
* [\#2021](https://github.com/bnb-chain/bsc/pull/2021) feat: support separate trie database
|
||||||
|
* [\#2224](https://github.com/bnb-chain/bsc/pull/2224) feat: support MEV
|
||||||
|
|
||||||
|
### BUGFIX
|
||||||
|
* [\#2268](https://github.com/bnb-chain/bsc/pull/2268) fix: ensure EIP-4788 not supported with Parlia Engine
|
||||||
|
|
||||||
|
### Cancun Code Merge
|
||||||
|
#### 4844 related
|
||||||
|
[internal/ethapi: add support for blobs in eth_fillTransaction (#28839)](https://github.com/bnb-chain/bsc/commit/ac5aa672d3b85a1f74667a65a15398f072aa0b2a)
|
||||||
|
[internal/ethapi: fix defaults for blob fields (#29037)](https://github.com/bnb-chain/bsc/commit/b47cf8fe1de4f97ce38417d8136a58812734a7a9)
|
||||||
|
[ethereum, ethclient: add blob transaction fields in CallMsg (#28989)](https://github.com/bnb-chain/bsc/commit/9d537f543990d9013d73433dc58fd0e985d9b2b6)
|
||||||
|
[core/txpool/blobpool: post-crash cleanup and addition/removal metrics(#28914)](https://github.com/bnb-chain/bsc/commit/62affdc9c5ea6f1a73fde42ac5ee5c9795877f88)
|
||||||
|
[core/txpool/blobpool: update the blob db with corruption handling (#29001)](https://github.com/bnb-chain/bsc/commit/3c30de219f92120248b7b7aeeb2bef82305e9627)
|
||||||
|
[core/txpool, eth, miner: pre-filter dynamic fees during pending tx retrieval (#29005)](https://github.com/bnb-chain/bsc/commit/593e303485473d9b9194792e4556a451c44dcc6c)
|
||||||
|
[core/txpool, miner: speed up blob pool pending retrievals (#29008)](https://github.com/bnb-chain/bsc/commit/6fb0d0992bd4eb91faf1e081b3c4aa46adb0ef7d)
|
||||||
|
[core/txpool, eth, miner: retrieve plain and blob txs separately (#29026)](https://github.com/bnb-chain/bsc/commit/f4852b8ddc8bef962d34210a4f7774b95767e421)
|
||||||
|
[core/txpool: reject blob txs with blob fee cap below the minimum (#29081)](https://github.com/bnb-chain/bsc/commit/32d4d6e6160432be1cb9780a43253deda7708ced)
|
||||||
|
[core/txpool/blobpool: reduce default database cap for rollout (#29090)](https://github.com/bnb-chain/bsc/commit/63aaac81007ad46b208570c17cae78b7f60931d4)
|
||||||
|
#### Clean Ups
|
||||||
|
[cmd/devp2p, eth: drop support for eth/67 (#28956)](https://github.com/bnb-chain/bsc/commit/8a76a814a2b9e5b4c1a4c6de44cd702536104507)
|
||||||
|
[all: remove the dependency from trie to triedb (#28824)](https://github.com/bnb-chain/bsc/commit/fe91d476ba3e29316b6dc99b6efd4a571481d888)
|
||||||
|
#### Others
|
||||||
|
[eth, miner: fix enforcing the minimum miner tip (#28933)](https://github.com/bnb-chain/bsc/commit/16ce7bf50fa71c907d1dc6504ed32a9161e71351)
|
||||||
|
[cmd,internal/era: implement export-history subcommand(#26621)](https://github.com/bnb-chain/bsc/commit/1f50aa76318689c6e74d0c3b4f31421bf7382fc7)
|
||||||
|
[node, rpc: add configurable HTTP request limit (#28948)](https://github.com/bnb-chain/bsc/commit/69f5d5ba1fe355ff7e3dee5a0c7e662cd82f1071)
|
||||||
|
[tests: fix goroutine leak related to state snapshot generation (#28974)](https://github.com/bnb-chain/bsc/commit/8321fe2fda0b44d6df3750bcee28b8627525173b)
|
||||||
|
[internal/ethapi:fix zero rpc gas cap in eth_createAccessList (#28846)](https://github.com/bnb-chain/bsc/commit/b87b9b45331f87fb1da379c5f17a81ebc3738c6e)
|
||||||
|
[eth/tracers: Fix callTracer logs on onlyTopCall == true (#29068)](https://github.com/bnb-chain/bsc/commit/5a0f468f8cb15b939bd85445d33c614a36942a8e)
|
||||||
|
|
||||||
|
## v1.4.1
|
||||||
|
FEATURE
|
||||||
|
NA
|
||||||
|
|
||||||
|
BUGFIX
|
||||||
|
* [\#2258](https://github.com/bnb-chain/bsc/pull/2258) core: skip checking state root existence when do snapsync by fast node
|
||||||
|
* [\#2252](https://github.com/bnb-chain/bsc/pull/2252) fix: add missing args of `bls account generate-proof` cmd (#2252)
|
||||||
|
|
||||||
|
IMPROVEMENT
|
||||||
|
NA
|
||||||
|
|
||||||
|
## v1.4.0
|
||||||
|
#### RPC
|
||||||
|
[internal/ethapi: implement eth_getBlockReceipts (#27702)](https://github.com/bnb-chain/bsc/commit/f1801a9feda8f81532c92077d2c9a8b785fd699b)
|
||||||
|
[eth, rpc: add configurable option for wsMessageSizeLimit (#27801)](https://github.com/bnb-chain/bsc/commit/705a51e566bc9215975d08f27d23ddab7baa9dd7)
|
||||||
|
[api/bind: add CallOpts.BlockHash to allow calling contracts at a specific block hash (#28084)](https://github.com/bnb-chain/bsc/commit/b85c86022e130a76eeb588a5b36e97149b342188)
|
||||||
|
[internal/ethapi: eth_call block parameter is optional (#28165)](https://github.com/bnb-chain/bsc/commit/adb9b319c9c61f092755000bf0fc4b3349f5cbbc)
|
||||||
|
[internal/ethapi: ethSendTransaction check baseFee (#27834)](https://github.com/bnb-chain/bsc/commit/54a400ee717caf44603fac390314747c5592ee1b)
|
||||||
|
#### Command
|
||||||
|
[cmd/utils: fix a startup issue on deleted chaindata but dangling ancients(#27989)](https://github.com/bnb-chain/bsc/commit/00fead91c4f58bc7f56f81512280d3120860989c)
|
||||||
|
[cmd/geth, internal/flags, go.mod: colorize cli help, support env vars(#28103)](https://github.com/bnb-chain/bsc/commit/d9fbb71d631d1ad0fb1846042e4c50ab893a6fbf)
|
||||||
|
[cmd/rlpdump: add -pos flag, displaying byte positions (#28785)](https://github.com/bnb-chain/bsc/commit/1485814f89d8206bb4a1c8e10a4a2893920f683a)
|
||||||
|
[cmd/geth: make it possible to autopilot removedb (#28725)](https://github.com/bnb-chain/bsc/commit/1010a79c7cbcdb4741e9f30e8cdc19c679ad7377)
|
||||||
|
#### Flag
|
||||||
|
[cmd/utils: restore support for txlookuplimit flag (#27917)](https://github.com/bnb-chain/bsc/commit/68855216c903eea9f952a1a7a56e69ea285f284b)
|
||||||
|
[cmd/utils, eth: disallow invalid snap sync / snapshot flag combos (#28657)](https://github.com/bnb-chain/bsc/commit/d98d70f670297a4bfa86db1a67a9c024f7186f43)
|
||||||
|
#### Client
|
||||||
|
[ethclient: use 'input', not 'data' as field for transaction input (#28078)](https://github.com/bnb-chain/bsc/commit/5cf53f51ac556cfff2aee9d405efd336298a3aca)
|
||||||
|
[ethclient: fix forwarding 1559 gas fields (#28462)](https://github.com/bnb-chain/bsc/commit/e91cdb49beb4b2a3872b5f2548bf2d6559e4f561)
|
||||||
|
[ethclient/simulated: implement new sim backend (#28202)](https://github.com/bnb-chain/bsc/commit/2d08c9900996b5e798f40a3cc6b47f4e51dc487d)
|
||||||
|
[ethclient: apply accessList field in toCallArg (#28832)](https://github.com/bnb-chain/bsc/commit/1c488298c807f4daa3cbe260efb88b81902a903d)
|
||||||
|
#### Tracer
|
||||||
|
[eth/tracers: add position field for callTracer logs (#28389)](https://github.com/bnb-chain/bsc/commit/b1cec853bef98acc750298b1c9b8165f2ac6ce5a)
|
||||||
|
[eth/tracers: tx-level state in debug_traceCall (#28460)](https://github.com/bnb-chain/bsc/commit/5fb8ebc9ecb226b84181420b9871c5f61cf4f77d)
|
||||||
|
#### Txpool
|
||||||
|
[eth/fetcher: allow underpriced transactions in after timeout (#28097)](https://github.com/bnb-chain/bsc/commit/2b7bc2c36b0d0efc83e62ba8e13723b943c4fa6e)
|
||||||
|
#### Sync
|
||||||
|
[eth/downloader: prevent pivot moves after state commit (#28126)](https://github.com/bnb-chain/bsc/commit/4fa3db49a1e485b8d110c87de6a44f460b45bb9a)
|
||||||
|
[core, eth/downloader: fix genesis state missing due to state sync (#28124)](https://github.com/bnb-chain/bsc/commit/c53b0fef2ab8e2a00257b898cad5174e6b73f5fc)
|
||||||
|
[core, accounts, eth, trie: handle genesis state missing (#28171)](https://github.com/bnb-chain/bsc/commit/73f5bcb75b562fcb3c109dd9c51f21956bc1f1f4)
|
||||||
|
[eth/protocols/snap: fix snap sync failure on empty storage range (#28306)](https://github.com/bnb-chain/bsc/commit/1cb3b6aee4a16ab8e684da63f3cfcd9b961c43af)
|
||||||
|
[core, eth, trie: filter out boundary nodes and remove dangling nodes in stacktrie (#28327)](https://github.com/bnb-chain/bsc/commit/ab04aeb855605de51dd1e933f45eb84ad877e715)
|
||||||
|
[core, core/rawdb, eth/sync: no tx indexing during snap sync (#28703)](https://github.com/bnb-chain/bsc/commit/78a3c32ef4deb7755e3367e183639b66242654f7)
|
||||||
|
#### PBSS Related
|
||||||
|
[core/rawdb: skip pathdb state inspection in hashdb mode (#28108)](https://github.com/bnb-chain/bsc/commit/8d38b1fe62950e8675795abf63b7c978415ab7ba)
|
||||||
|
[eth: abort on api operations not available in pbss-mode (#28104)](https://github.com/bnb-chain/bsc/commit/b9b99a12e5159c746ef04b7c8febc4db66817b72)
|
||||||
|
[trie: remove internal nodes between shortNode and child in path mode (#28163)](https://github.com/bnb-chain/bsc/commit/4773dcbc81aac9d330df29446283361f5a7062c7)
|
||||||
|
[trie/triedb/pathdb: improve dirty node flushing trigger (#28426)](https://github.com/bnb-chain/bsc/commit/ea2e66a58e48ef63566d5274c4a875e817a1cd39)
|
||||||
|
[core/rawdb: fsync the index file after each freezer write (#28483)](https://github.com/bnb-chain/bsc/commit/326fa00759d959061035becc9514660c24897053)
|
||||||
|
[trie: remove inconsistent trie nodes during sync in path mode (#28595)](https://github.com/bnb-chain/bsc/commit/e206d3f8975bd98cc86d14055dca40f996bacc60)
|
||||||
|
[core, cmd, trie: fix the condition of pathdb initialization (#28718)](https://github.com/bnb-chain/bsc/commit/cca94792a4112687ce23e7041b95ccc7f4bf6123)
|
||||||
|
#### GraphQL
|
||||||
|
[graphql: validate block params (#27876](https://github.com/bnb-chain/bsc/commit/5e89ff4d6b0df4bd54d20d90bee5a16abef6b9bc)
|
||||||
|
[graphql: always set content-type to application/json (#28417)](https://github.com/bnb-chain/bsc/commit/2d7dba024d76603398907a595da98ad4df81b858)
|
||||||
|
#### Cancun
|
||||||
|
[core/types: support for optional blob sidecar in BlobTx (#27841)](https://github.com/bnb-chain/bsc/commit/2a6beb6a39d7cb3c5906dd4465d65da6efcc73cd)
|
||||||
|
[core, params, beacon/engine: implement EIP 4788 BeaconRoot (#27849)](https://github.com/bnb-chain/bsc/commit/b8d38e76ef07c99d338c7bcd485881850382a58f)
|
||||||
|
[miner: add to build block with EIP-4844 blobs (#27875)](https://github.com/bnb-chain/bsc/commit/feb8f416acc3f067ecc8cbdabb8e70679547737a)
|
||||||
|
[core: implement BLOBBASEFEE opcode (0x4a) (#28098)](https://github.com/bnb-chain/bsc/commit/c39cbc1a78aa275523c1b0ff9d21b16ba7bfa486)
|
||||||
|
[core, eth, miner: start propagating and consuming blob txs (#28243)](https://github.com/bnb-chain/bsc/commit/a8a9c8e4b00c5b9f84242181839234b8e9fd54e3)
|
||||||
|
[eth/fetcher: throttle tx fetches to 128KB responses (#28304)](https://github.com/bnb-chain/bsc/commit/a6deb2d994e644300bac43455b1c954976e7382e)
|
||||||
|
[crypto/kzg4844: use the new trusted setup file and format (#28383)](https://github.com/bnb-chain/bsc/commit/a6a0ae45b69a95b38b7cb2d085e7833c88b72164)
|
||||||
|
[internal/ethapi: handle blobs in API methods (#28786)](https://github.com/bnb-chain/bsc/commit/e5d5e09faae48dac3723634e2b1813e4f2e89535)
|
||||||
|
#### P2P
|
||||||
|
[cmd/devp2p, eth: drop eth/66 (#28239)](https://github.com/bnb-chain/bsc/commit/bc6d184872889224480cf9df58b0539b210ffa9e)
|
||||||
|
[cmd/devp2p: use bootnodes as crawl input (#28139)](https://github.com/bnb-chain/bsc/commit/41a0ad9f03ae8e8389fbe40131f4e6930b5beac5)
|
||||||
|
[p2p/discover: add liveness check in collectTableNodes (#28686)](https://github.com/bnb-chain/bsc/commit/5b22a472d6aaaa17daf0543b5914ca1f2f5518a7)
|
||||||
|
#### Test
|
||||||
|
[build, tests: add execution-spec-tests (#26985)](https://github.com/bnb-chain/bsc/commit/f174ddba7af5c150ecad37430c167194d66d75f1)
|
||||||
|
[tests/fuzzers: update fuzzers to be based on go-native fuzzing (#28352)](https://github.com/bnb-chain/bsc/commit/d10a2f6ab727f79a0acff29c8147d54c5e4689ec)
|
||||||
|
[tests/fuzzers: move fuzzers into native packages (#28467)](https://github.com/bnb-chain/bsc/commit/2391fbc676d7464bd42e248155558a2bcd6ecf64)
|
||||||
|
#### Clear Up
|
||||||
|
[eth/downloader: remove header rollback mechanism (#28147)](https://github.com/bnb-chain/bsc/commit/b85c183ea7417e973dbbccd27b3fb7d7097b87dd)
|
||||||
|
#### Others
|
||||||
|
[core/forkid: correctly compute forkid when timestamp fork is activated in genesis (#27895)](https://github.com/bnb-chain/bsc/commit/32fde3f838d604fdeb7a3ada4f8e02d78301b83d)
|
||||||
|
[core/vm/runtime: Add Random field to config (#28001)](https://github.com/bnb-chain/bsc/commit/0ba2d3cfa4e4a0a76cd457b8dc0f49bf1a79b723)
|
||||||
|
[core/rawdb: no need to run truncateFile for readonly mode (#28145)](https://github.com/bnb-chain/bsc/commit/545f4c5547178bc8bde6af08b3ccaf68ca27f2c0)
|
||||||
|
[core/bloombits: fix deadlock when matcher session hits an error (#28184)](https://github.com/bnb-chain/bsc/commit/c2cfe35f121cb88650b4d90c958bcc4214d0ce7f)
|
||||||
|
[core/state, tests: fix memory leak via fastcache (#28387)](https://github.com/bnb-chain/bsc/commit/c1d5a012ea4b824e902db14e47bf147d727c2657)
|
||||||
|
[internal/ethapi: compact db missing key starts with 0xff (#28207)](https://github.com/bnb-chain/bsc/commit/46c850a9411d7ff15c1a0342fe29f359e6c390ae)
|
||||||
|
[internal/ethapi: fix codehash lookup in eth_getProof (#28357)](https://github.com/bnb-chain/bsc/commit/8b99ad46027a455971ccf9bd1f425b9c58ec5855)
|
||||||
|
[eth: set networkID to chainID by default (#28250)](https://github.com/bnb-chain/bsc/commit/4d9f3cd5d751efccd501b08ab6cf38a83b5e2858)
|
||||||
|
[eth: fix potential hang in waitSnapExtension (#28744)](https://github.com/bnb-chain/bsc/commit/18e154eaa24d5f7a8b3c48983ad591e6c10963ca)
|
||||||
|
[metrics, cmd/geth: informational metrics (prometheus, influxdb, opentsb (#24877)](https://github.com/bnb-chain/bsc/commit/53f3c2ae656cd860a700751b6c5f81ca9c66503d)
|
||||||
|
[ethdb/pebble: don't double-close iterator inside pebbleIterator (#28566)](https://github.com/bnb-chain/bsc/commit/6489a0dd1f98e9ce1c64c2eae93c8a88df7ae674)
|
||||||
|
[trie/triedb/hashdb: take lock around access to dirties cache (#28542)](https://github.com/bnb-chain/bsc/commit/fa0df76f3cfd186a1f06f2b80aa5dbb89555b009)
|
||||||
|
[accounts: properly close managed wallets when closing manager (#28710)](https://github.com/bnb-chain/bsc/commit/d3452a22cc871306c62de52d19295914141863c0)
|
||||||
|
[event: fix Resubscribe deadlock when unsubscribing after inner sub ends (#28359)](https://github.com/bnb-chain/bsc/commit/ffc6a0f36edda396a8421cf7a3c0feb88be20d0b)
|
||||||
|
[all: replace log15 with slog (#28187)](https://github.com/bnb-chain/bsc/commit/28e73717016cdc9ebdb5fdb3474cfbd3bd2d2524)
|
||||||
|
|
||||||
|
## v1.3.11
|
||||||
|
BUGFIX
|
||||||
|
* [\#2288](https://github.com/bnb-chain/bsc/pull/2288) fix: add FeynmanFix upgrade for a testnet issue
|
||||||
|
|
||||||
|
## v1.3.10
|
||||||
|
FEATURE
|
||||||
|
* [\#2047](https://github.com/bnb-chain/bsc/pull/2047) feat: add new fork block and precompile contract for BEP294 and BEP299
|
||||||
|
|
||||||
|
## v1.3.9
|
||||||
|
FEATURE
|
||||||
|
* [\#2186](https://github.com/bnb-chain/bsc/pull/2186) log: support maxBackups in config.toml
|
||||||
|
|
||||||
|
BUGFIX
|
||||||
|
* [\#2160](https://github.com/bnb-chain/bsc/pull/2160) cmd: fix dump cli cannot work in path mode
|
||||||
|
* [\#2183](https://github.com/bnb-chain/bsc/pull/2183) p2p: resolved deadlock on p2p server shutdown
|
||||||
|
|
||||||
|
IMPROVEMENT
|
||||||
|
* [\#2177](https://github.com/bnb-chain/bsc/pull/0000) build(deps): bump github.com/quic-go/quic-go from 0.39.3 to 0.39.4
|
||||||
|
* [\#2185](https://github.com/bnb-chain/bsc/pull/2185) consensus/parlia: set nonce before evm run
|
||||||
|
* [\#2190](https://github.com/bnb-chain/bsc/pull/2190) fix(legacypool): deprecate already known error
|
||||||
|
* [\#2195](https://github.com/bnb-chain/bsc/pull/2195) eth/fetcher: downgrade state tx log
|
||||||
|
|
||||||
|
## v1.3.8
|
||||||
|
FEATURE
|
||||||
|
* [\#2074](https://github.com/bnb-chain/bsc/pull/2074) faucet: new faucet client
|
||||||
|
* [\#2082](https://github.com/bnb-chain/bsc/pull/2082) cmd/dbcmd: add inspect trie tool
|
||||||
|
* [\#2140](https://github.com/bnb-chain/bsc/pull/2140) eth/fetcher: allow underpriced transactions in after timeout
|
||||||
|
* [\#2115](https://github.com/bnb-chain/bsc/pull/2115) p2p: no peer reconnect if explicitly disconnected
|
||||||
|
* [\#2128](https://github.com/bnb-chain/bsc/pull/2128) go.mod: upgrade prysm to support built with go@v1.21
|
||||||
|
* [\#2151](https://github.com/bnb-chain/bsc/pull/2151) feat: enable NoDial should still dial static nodes
|
||||||
|
* [\#2144](https://github.com/bnb-chain/bsc/pull/2144) p2p: reset disconnect set with magic enode ID
|
||||||
|
|
||||||
|
BUGFIX
|
||||||
|
* [\#2095](https://github.com/bnb-chain/bsc/pull/2095) rpc: fix ns/µs mismatch in metrics
|
||||||
|
* [\#2083](https://github.com/bnb-chain/bsc/pull/2083) triedb/pathdb: fix async node buffer diskroot mismatches when journaling
|
||||||
|
* [\#2120](https://github.com/bnb-chain/bsc/pull/2120) ethdb/pebble: cap memory table size as maxMemTableSize-1
|
||||||
|
* [\#2107](https://github.com/bnb-chain/bsc/pull/2107) cmd/geth: fix parse state scheme
|
||||||
|
* [\#2121](https://github.com/bnb-chain/bsc/pull/2121) parlia: fix verifyVoteAttestation when verify a batch of headers
|
||||||
|
* [\#2132](https://github.com/bnb-chain/bsc/pull/2132) core: fix systemcontracts.GenesisHash when run bsc firstly without init
|
||||||
|
* [\#2155](https://github.com/bnb-chain/bsc/pull/2155) cmd, core: resolve scheme from a read-write database and refactor resolveChainFreezerDir func
|
||||||
|
|
||||||
|
IMPROVEMENT
|
||||||
|
* [\#2099](https://github.com/bnb-chain/bsc/pull/2099) params/config: remove useless toml tag for hardforks
|
||||||
|
* [\#2100](https://github.com/bnb-chain/bsc/pull/2100) core/genesis: support chapel to run without geth init
|
||||||
|
* [\#2101](https://github.com/bnb-chain/bsc/pull/2101) core: add metrics for bad block
|
||||||
|
* [\#2109](https://github.com/bnb-chain/bsc/pull/2109) cmd/geth: tidy flags for geth command
|
||||||
|
* [\#1953](https://github.com/bnb-chain/bsc/pull/1953) build(deps): bump github.com/docker/docker
|
||||||
|
* [\#2086](https://github.com/bnb-chain/bsc/pull/2086) build(deps): bump golang.org/x/crypto from 0.12.0 to 0.17.0
|
||||||
|
* [\#2106](https://github.com/bnb-chain/bsc/pull/2106) params: use rialto to test builtin network logic
|
||||||
|
* [\#2098](https://github.com/bnb-chain/bsc/pull/2098) cmd, les, tests: remove light client code
|
||||||
|
* [\#2114](https://github.com/bnb-chain/bsc/pull/2114) p2p: add serve metrics
|
||||||
|
* [\#2123](https://github.com/bnb-chain/bsc/pull/2123) p2p, eth: improve logs
|
||||||
|
* [\#2116](https://github.com/bnb-chain/bsc/pull/2116) tests: revive evm test cases
|
||||||
|
* [\#2161](https://github.com/bnb-chain/bsc/pull/2161) code: remove IsEuler check from worker.go
|
||||||
|
* [\#2167](https://github.com/bnb-chain/bsc/pull/2167) improve: increase SystemTxsGas from 1,500,000 to 5,000,000
|
||||||
|
* [\#2172](https://github.com/bnb-chain/bsc/pull/2172) improve: remove sharedpool from miner
|
||||||
|
* [\#1332](https://github.com/bnb-chain/bsc/pull/1332) core/state: no need to prune block if the same
|
||||||
|
|
||||||
|
## v1.3.7
|
||||||
|
FEATURE
|
||||||
|
* [\#2067](https://github.com/bnb-chain/bsc/pull/2067) cmd/geth: add check func to validate state scheme
|
||||||
|
* [\#2068](https://github.com/bnb-chain/bsc/pull/2068) internal/ethapi: implement eth_getBlockReceipts
|
||||||
|
|
||||||
|
BUGFIX
|
||||||
|
* [\#2035](https://github.com/bnb-chain/bsc/pull/2035) all: pull snap sync PRs from upstream v1.13.5
|
||||||
|
* [\#2072](https://github.com/bnb-chain/bsc/pull/2072) fix: fix the pebble config of level option
|
||||||
|
* [\#2078](https://github.com/bnb-chain/bsc/pull/2078) core: LoadChainConfig return the predefined config for built-in networks firstly
|
||||||
|
|
||||||
|
## v1.3.6
|
||||||
|
FEATURE
|
||||||
|
* [\#2012](https://github.com/bnb-chain/bsc/pull/2012) cmd, core, ethdb: enable Pebble on 32 bits and OpenBSD
|
||||||
|
* [\#2063](https://github.com/bnb-chain/bsc/pull/2063) log: support to disable log rotate by hours
|
||||||
|
* [\#2064](https://github.com/bnb-chain/bsc/pull/2064) log: limit rotateHours in range [0,23]
|
||||||
|
|
||||||
|
BUGFIX
|
||||||
|
* [\#2058](https://github.com/bnb-chain/bsc/pull/2058) params: set default hardfork times
|
||||||
|
|
||||||
|
IMPROVEMENT
|
||||||
|
* [\#2015](https://github.com/bnb-chain/bsc/pull/2015) cmd, core, eth: change default network from ETH to BSC
|
||||||
|
* [\#2036](https://github.com/bnb-chain/bsc/pull/2036) cmd/jsutils: add 2 tools get validator version and block txs number
|
||||||
|
* [\#2037](https://github.com/bnb-chain/bsc/pull/2037) core/txpool/legacypool: respect nolocals-setting
|
||||||
|
* [\#2042](https://github.com/bnb-chain/bsc/pull/2042) core/systemcontracts: update CommitUrl for keplerUpgrade
|
||||||
|
* [\#2043](https://github.com/bnb-chain/bsc/pull/2043) tests/truffle: adapt changes in bsc-genesis-contracts
|
||||||
|
* [\#2051](https://github.com/bnb-chain/bsc/pull/2051) core/vote: wait some blocks before voting since mining begin
|
||||||
|
* [\#2060](https://github.com/bnb-chain/bsc/pull/2060) cmd/utils: allow HTTPHost and WSHost flags precede
|
||||||
|
|
||||||
|
## v1.3.5
|
||||||
|
FEATURE
|
||||||
|
* [\#1970](https://github.com/bnb-chain/bsc/pull/1970) core: enable Shanghai EIPs
|
||||||
|
* [\#1973](https://github.com/bnb-chain/bsc/pull/1973) core/systemcontracts: include BEP-319 on kepler hardfork
|
||||||
|
|
||||||
|
BUGFIX
|
||||||
|
* [\#1964](https://github.com/bnb-chain/bsc/pull/1964) consensus/parlia: hardfork block can be epoch block
|
||||||
|
* [\#1979](https://github.com/bnb-chain/bsc/pull/1979) fix: upgrade pebble and improve config
|
||||||
|
* [\#1980](https://github.com/bnb-chain/bsc/pull/1980) internal/ethapi: fix null effectiveGasPrice in GetTransactionReceipt
|
||||||
|
|
||||||
|
IMPROVEMENT
|
||||||
|
* [\#1977](https://github.com/bnb-chain/bsc/pull/1977) doc: add instructions for starting fullnode with pbss
|
||||||
|
|
||||||
|
## v1.3.4
|
||||||
|
BUGFIX
|
||||||
|
* fix: remove pipecommit in miner
|
||||||
|
* add a hard fork: Hertzfix
|
||||||
|
|
||||||
|
## v1.3.3
|
||||||
|
BUGFIX
|
||||||
|
* [\#1986](https://github.com/bnb-chain/bsc/pull/1986) fix(cmd): check pruneancient when creating db
|
||||||
|
|
||||||
|
IMPROVEMENT
|
||||||
|
* [\#2000](https://github.com/bnb-chain/bsc/pull/2000) cmd/utils: exit process if txlookuplimit flag is set
|
||||||
|
|
||||||
|
## v1.3.2
|
||||||
|
BUGFIX
|
||||||
|
* fix: remove sharedPool
|
||||||
|
|
||||||
|
IMPROVEMENT
|
||||||
|
* [\#2007](https://github.com/bnb-chain/bsc/pull/2007) consensus/parlia: increase size of snapshot cache in parlia
|
||||||
|
* [\#2008](https://github.com/bnb-chain/bsc/pull/2008) consensus/parlia: recover faster when snapshot of parlia is gone in disk
|
||||||
|
|
||||||
## v1.3.1
|
## v1.3.1
|
||||||
FEATURE
|
FEATURE
|
||||||
* [\#1881](https://github.com/bnb-chain/bsc/pull/1881) feat: active pbss
|
* [\#1881](https://github.com/bnb-chain/bsc/pull/1881) feat: active pbss
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ ARG VERSION=""
|
|||||||
ARG BUILDNUM=""
|
ARG BUILDNUM=""
|
||||||
|
|
||||||
# Build Geth in a stock Go builder container
|
# Build Geth in a stock Go builder container
|
||||||
FROM golang:1.20-alpine as builder
|
FROM golang:1.21-alpine as builder
|
||||||
|
|
||||||
RUN apk add --no-cache make cmake gcc musl-dev linux-headers git bash build-base libc-dev
|
RUN apk add --no-cache make cmake gcc musl-dev linux-headers git bash build-base libc-dev
|
||||||
# Get dependencies - will also be cached if we won't change go.mod/go.sum
|
# Get dependencies - will also be cached if we won't change go.mod/go.sum
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ ARG VERSION=""
|
|||||||
ARG BUILDNUM=""
|
ARG BUILDNUM=""
|
||||||
|
|
||||||
# Build Geth in a stock Go builder container
|
# Build Geth in a stock Go builder container
|
||||||
FROM golang:1.20-alpine as builder
|
FROM golang:1.21-alpine as builder
|
||||||
|
|
||||||
RUN apk add --no-cache gcc musl-dev linux-headers git
|
RUN apk add --no-cache gcc musl-dev linux-headers git
|
||||||
# Get dependencies - will also be cached if we won't change go.mod/go.sum
|
# Get dependencies - will also be cached if we won't change go.mod/go.sum
|
||||||
@@ -26,7 +26,7 @@ COPY --from=builder /go-ethereum/build/bin/* /usr/local/bin/
|
|||||||
|
|
||||||
EXPOSE 8545 8546 30303 30303/udp
|
EXPOSE 8545 8546 30303 30303/udp
|
||||||
|
|
||||||
# Add some metadata labels to help programatic image consumption
|
# Add some metadata labels to help programmatic image consumption
|
||||||
ARG COMMIT=""
|
ARG COMMIT=""
|
||||||
ARG VERSION=""
|
ARG VERSION=""
|
||||||
ARG BUILDNUM=""
|
ARG BUILDNUM=""
|
||||||
|
|||||||
25
Makefile
25
Makefile
@@ -7,18 +7,21 @@
|
|||||||
|
|
||||||
GOBIN = ./build/bin
|
GOBIN = ./build/bin
|
||||||
GO ?= latest
|
GO ?= latest
|
||||||
GORUN = env GO111MODULE=on go run
|
GORUN = go run
|
||||||
GIT_COMMIT=$(shell git rev-parse HEAD)
|
GIT_COMMIT=$(shell git rev-parse HEAD)
|
||||||
GIT_COMMIT_DATE=$(shell git log -n1 --pretty='format:%cd' --date=format:'%Y%m%d')
|
GIT_COMMIT_DATE=$(shell git log -n1 --pretty='format:%cd' --date=format:'%Y%m%d')
|
||||||
|
|
||||||
|
#? geth: Build geth
|
||||||
geth:
|
geth:
|
||||||
$(GORUN) build/ci.go install ./cmd/geth
|
$(GORUN) build/ci.go install ./cmd/geth
|
||||||
@echo "Done building."
|
@echo "Done building."
|
||||||
@echo "Run \"$(GOBIN)/geth\" to launch geth."
|
@echo "Run \"$(GOBIN)/geth\" to launch geth."
|
||||||
|
|
||||||
|
#? all: Build all packages and executables
|
||||||
all:
|
all:
|
||||||
$(GORUN) build/ci.go install
|
$(GORUN) build/ci.go install
|
||||||
|
|
||||||
|
#? test: Run the tests
|
||||||
test: all
|
test: all
|
||||||
$(GORUN) build/ci.go test -timeout 1h
|
$(GORUN) build/ci.go test -timeout 1h
|
||||||
|
|
||||||
@@ -26,22 +29,25 @@ truffle-test:
|
|||||||
docker build . -f ./docker/Dockerfile --target bsc-genesis -t bsc-genesis
|
docker build . -f ./docker/Dockerfile --target bsc-genesis -t bsc-genesis
|
||||||
docker build . -f ./docker/Dockerfile --target bsc -t bsc
|
docker build . -f ./docker/Dockerfile --target bsc -t bsc
|
||||||
docker build . -f ./docker/Dockerfile.truffle -t truffle-test
|
docker build . -f ./docker/Dockerfile.truffle -t truffle-test
|
||||||
docker-compose -f ./tests/truffle/docker-compose.yml up genesis
|
docker compose -f ./tests/truffle/docker-compose.yml up genesis
|
||||||
docker-compose -f ./tests/truffle/docker-compose.yml up -d bsc-rpc bsc-validator1
|
docker compose -f ./tests/truffle/docker-compose.yml up -d bsc-rpc bsc-validator1
|
||||||
sleep 30
|
sleep 30
|
||||||
docker-compose -f ./tests/truffle/docker-compose.yml up --exit-code-from truffle-test truffle-test
|
docker compose -f ./tests/truffle/docker-compose.yml up --exit-code-from truffle-test truffle-test
|
||||||
docker-compose -f ./tests/truffle/docker-compose.yml down
|
docker compose -f ./tests/truffle/docker-compose.yml down
|
||||||
|
|
||||||
|
#? lint: Run certain pre-selected linters
|
||||||
lint: ## Run linters.
|
lint: ## Run linters.
|
||||||
$(GORUN) build/ci.go lint
|
$(GORUN) build/ci.go lint
|
||||||
|
|
||||||
|
#? clean: Clean go cache, built executables, and the auto generated folder
|
||||||
clean:
|
clean:
|
||||||
env GO111MODULE=on go clean -cache
|
go clean -cache
|
||||||
rm -fr build/_workspace/pkg/ $(GOBIN)/*
|
rm -fr build/_workspace/pkg/ $(GOBIN)/*
|
||||||
|
|
||||||
# The devtools target installs tools required for 'go generate'.
|
# The devtools target installs tools required for 'go generate'.
|
||||||
# You need to put $GOBIN (or $GOPATH/bin) in your PATH to use 'go generate'.
|
# You need to put $GOBIN (or $GOPATH/bin) in your PATH to use 'go generate'.
|
||||||
|
|
||||||
|
#? devtools: Install recommended developer tools
|
||||||
devtools:
|
devtools:
|
||||||
env GOBIN= go install golang.org/x/tools/cmd/stringer@latest
|
env GOBIN= go install golang.org/x/tools/cmd/stringer@latest
|
||||||
env GOBIN= go install github.com/fjl/gencodec@latest
|
env GOBIN= go install github.com/fjl/gencodec@latest
|
||||||
@@ -50,5 +56,12 @@ devtools:
|
|||||||
@type "solc" 2> /dev/null || echo 'Please install solc'
|
@type "solc" 2> /dev/null || echo 'Please install solc'
|
||||||
@type "protoc" 2> /dev/null || echo 'Please install protoc'
|
@type "protoc" 2> /dev/null || echo 'Please install protoc'
|
||||||
|
|
||||||
|
#? help: Build docker image
|
||||||
docker:
|
docker:
|
||||||
docker build --pull -t bnb-chain/bsc:latest -f Dockerfile .
|
docker build --pull -t bnb-chain/bsc:latest -f Dockerfile .
|
||||||
|
|
||||||
|
#? help: Get more info on make commands.
|
||||||
|
help: Makefile
|
||||||
|
@echo " Choose a command run in go-ethereum:"
|
||||||
|
@sed -n 's/^#?//p' $< | column -t -s ':' | sort | sed -e 's/^/ /'
|
||||||
|
.PHONY: help
|
||||||
|
|||||||
27
README.md
27
README.md
@@ -5,7 +5,7 @@ The goal of BNB Smart Chain is to bring programmability and interoperability to
|
|||||||
BNB Smart Chain starts its development based on go-ethereum fork. So you may see many toolings, binaries and also docs are based on Ethereum ones, such as the name “geth”.
|
BNB Smart Chain starts its development based on go-ethereum fork. So you may see many toolings, binaries and also docs are based on Ethereum ones, such as the name “geth”.
|
||||||
|
|
||||||
[](https://pkg.go.dev/github.com/ethereum/go-ethereum?tab=doc)
|
)](https://pkg.go.dev/github.com/ethereum/go-ethereum?tab=doc)
|
||||||
[](https://discord.gg/z2VpC455eU)
|
[](https://discord.gg/z2VpC455eU)
|
||||||
|
|
||||||
@@ -36,7 +36,7 @@ To combine DPoS and PoA for consensus, BNB Smart Chain implement a novel consens
|
|||||||
2. Validators take turns to produce blocks in a PoA manner, similar to Ethereum's Clique consensus engine.
|
2. Validators take turns to produce blocks in a PoA manner, similar to Ethereum's Clique consensus engine.
|
||||||
3. Validator set are elected in and out based on a staking based governance on BNB Beacon Chain.
|
3. Validator set are elected in and out based on a staking based governance on BNB Beacon Chain.
|
||||||
4. The validator set change is relayed via a cross-chain communication mechanism.
|
4. The validator set change is relayed via a cross-chain communication mechanism.
|
||||||
5. Parlia consensus engine will interact with a set of [system contracts](https://docs.bnbchain.org/docs/learn/system-contract) to achieve liveness slash, revenue distributing and validator set renewing func.
|
5. Parlia consensus engine will interact with a set of [system contracts](https://docs.bnbchain.org/bnb-smart-chain/staking/overview/#system-contracts) to achieve liveness slash, revenue distributing and validator set renewing func.
|
||||||
|
|
||||||
|
|
||||||
### Light Client of BNB Beacon Chain
|
### Light Client of BNB Beacon Chain
|
||||||
@@ -61,7 +61,7 @@ Many of the below are the same as or similar to go-ethereum.
|
|||||||
|
|
||||||
For prerequisites and detailed build instructions please read the [Installation Instructions](https://geth.ethereum.org/docs/getting-started/installing-geth).
|
For prerequisites and detailed build instructions please read the [Installation Instructions](https://geth.ethereum.org/docs/getting-started/installing-geth).
|
||||||
|
|
||||||
Building `geth` requires both a Go (version 1.20 or later) and a C compiler (GCC 5 or higher). You can install
|
Building `geth` requires both a Go (version 1.21 or later) and a C compiler (GCC 5 or higher). You can install
|
||||||
them using your favourite package manager. Once the dependencies are installed, run
|
them using your favourite package manager. Once the dependencies are installed, run
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
@@ -110,15 +110,15 @@ on how you can run your own `geth` instance.
|
|||||||
|
|
||||||
The hardware must meet certain requirements to run a full node on mainnet:
|
The hardware must meet certain requirements to run a full node on mainnet:
|
||||||
- VPS running recent versions of Mac OS X, Linux, or Windows.
|
- VPS running recent versions of Mac OS X, Linux, or Windows.
|
||||||
- IMPORTANT 2.5 TB(May 2023) of free disk space, solid-state drive(SSD), gp3, 8k IOPS, 250 MB/S throughput, read latency <1ms. (if node is started with snap sync, it will need NVMe SSD)
|
- IMPORTANT 3 TB(Dec 2023) of free disk space, solid-state drive(SSD), gp3, 8k IOPS, 500 MB/S throughput, read latency <1ms. (if node is started with snap sync, it will need NVMe SSD)
|
||||||
- 16 cores of CPU and 64 GB of memory (RAM)
|
- 16 cores of CPU and 64 GB of memory (RAM)
|
||||||
- Suggest m5zn.3xlarge instance type on AWS, c2-standard-16 on Google cloud.
|
- Suggest m5zn.6xlarge or r7iz.4xlarge instance type on AWS, c2-standard-16 on Google cloud.
|
||||||
- A broadband Internet connection with upload/download speeds of 5 MB/S
|
- A broadband Internet connection with upload/download speeds of 5 MB/S
|
||||||
|
|
||||||
The requirement for testnet:
|
The requirement for testnet:
|
||||||
- VPS running recent versions of Mac OS X, Linux, or Windows.
|
- VPS running recent versions of Mac OS X, Linux, or Windows.
|
||||||
- 500G of storage for testnet.
|
- 500G of storage for testnet.
|
||||||
- 4 cores of CPU and 8 gigabytes of memory (RAM).
|
- 4 cores of CPU and 16 gigabytes of memory (RAM).
|
||||||
|
|
||||||
### Steps to Run a Fullnode
|
### Steps to Run a Fullnode
|
||||||
|
|
||||||
@@ -149,14 +149,17 @@ unzip testnet.zip
|
|||||||
#### 3. Download snapshot
|
#### 3. Download snapshot
|
||||||
Download latest chaindata snapshot from [here](https://github.com/bnb-chain/bsc-snapshots). Follow the guide to structure your files.
|
Download latest chaindata snapshot from [here](https://github.com/bnb-chain/bsc-snapshots). Follow the guide to structure your files.
|
||||||
|
|
||||||
Note: if you can not download the chaindata snapshot and want to sync from genesis, you have to generate the genesis block first, you have already get the genesis.json in Step 2.
|
|
||||||
So just run: `geth --datadir <datadir> init ./genesis.json`
|
|
||||||
#### 4. Start a full node
|
#### 4. Start a full node
|
||||||
```shell
|
```shell
|
||||||
./geth --config ./config.toml --datadir ./node --cache 8000 --rpc.allow-unprotected-txs --txlookuplimit 0
|
./geth --config ./config.toml --datadir ./node --cache 8000 --rpc.allow-unprotected-txs --history.transactions 0
|
||||||
|
|
||||||
## It is recommand to run fullnode with `--tries-verify-mode none` if you want high performance and care little about state consistency
|
## It is recommend to run fullnode with `--tries-verify-mode none` if you want high performance and care little about state consistency
|
||||||
./geth --config ./config.toml --datadir ./node --cache 8000 --rpc.allow-unprotected-txs --txlookuplimit 0 --tries-verify-mode none
|
## It will run with Hash-Base Storage Scheme by default
|
||||||
|
./geth --config ./config.toml --datadir ./node --cache 8000 --rpc.allow-unprotected-txs --history.transactions 0 --tries-verify-mode none
|
||||||
|
|
||||||
|
## It runs fullnode with Path-Base Storage Scheme.
|
||||||
|
## It will enable inline state prune, keeping the latest 90000 blocks' history state by default.
|
||||||
|
./geth --config ./config.toml --datadir ./node --cache 8000 --rpc.allow-unprotected-txs --history.transactions 0 --tries-verify-mode none --state.scheme path
|
||||||
```
|
```
|
||||||
|
|
||||||
#### 5. Monitor node status
|
#### 5. Monitor node status
|
||||||
@@ -178,7 +181,7 @@ This tool is optional and if you leave it out you can always attach to an alread
|
|||||||
|
|
||||||
#### 7. More
|
#### 7. More
|
||||||
|
|
||||||
More details about [running a node](https://docs.bnbchain.org/docs/validator/fullnode) and [becoming a validator](https://docs.bnbchain.org/docs/validator/create-val)
|
More details about [running a node](https://docs.bnbchain.org/bnb-smart-chain/developers/node_operators/full_node/) and [becoming a validator](https://docs.bnbchain.org/bnb-smart-chain/validator/create-val/)
|
||||||
|
|
||||||
*Note: Although some internal protective measures prevent transactions from
|
*Note: Although some internal protective measures prevent transactions from
|
||||||
crossing over between the main network and test network, you should always
|
crossing over between the main network and test network, you should always
|
||||||
|
|||||||
@@ -22,13 +22,14 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"math/big"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
)
|
)
|
||||||
|
|
||||||
// The ABI holds information about a contract's context and available
|
// The ABI holds information about a contract's context and available
|
||||||
// invokable methods. It will allow you to type check function calls and
|
// invocable methods. It will allow you to type check function calls and
|
||||||
// packs data accordingly.
|
// packs data accordingly.
|
||||||
type ABI struct {
|
type ABI struct {
|
||||||
Constructor Method
|
Constructor Method
|
||||||
@@ -246,24 +247,65 @@ func (abi *ABI) HasReceive() bool {
|
|||||||
// revertSelector is a special function selector for revert reason unpacking.
|
// revertSelector is a special function selector for revert reason unpacking.
|
||||||
var revertSelector = crypto.Keccak256([]byte("Error(string)"))[:4]
|
var revertSelector = crypto.Keccak256([]byte("Error(string)"))[:4]
|
||||||
|
|
||||||
|
// panicSelector is a special function selector for panic reason unpacking.
|
||||||
|
var panicSelector = crypto.Keccak256([]byte("Panic(uint256)"))[:4]
|
||||||
|
|
||||||
|
// panicReasons map is for readable panic codes
|
||||||
|
// see this linkage for the details
|
||||||
|
// https://docs.soliditylang.org/en/v0.8.21/control-structures.html#panic-via-assert-and-error-via-require
|
||||||
|
// the reason string list is copied from ether.js
|
||||||
|
// https://github.com/ethers-io/ethers.js/blob/fa3a883ff7c88611ce766f58bdd4b8ac90814470/src.ts/abi/interface.ts#L207-L218
|
||||||
|
var panicReasons = map[uint64]string{
|
||||||
|
0x00: "generic panic",
|
||||||
|
0x01: "assert(false)",
|
||||||
|
0x11: "arithmetic underflow or overflow",
|
||||||
|
0x12: "division or modulo by zero",
|
||||||
|
0x21: "enum overflow",
|
||||||
|
0x22: "invalid encoded storage byte array accessed",
|
||||||
|
0x31: "out-of-bounds array access; popping on an empty array",
|
||||||
|
0x32: "out-of-bounds access of an array or bytesN",
|
||||||
|
0x41: "out of memory",
|
||||||
|
0x51: "uninitialized function",
|
||||||
|
}
|
||||||
|
|
||||||
// UnpackRevert resolves the abi-encoded revert reason. According to the solidity
|
// UnpackRevert resolves the abi-encoded revert reason. According to the solidity
|
||||||
// spec https://solidity.readthedocs.io/en/latest/control-structures.html#revert,
|
// spec https://solidity.readthedocs.io/en/latest/control-structures.html#revert,
|
||||||
// the provided revert reason is abi-encoded as if it were a call to a function
|
// the provided revert reason is abi-encoded as if it were a call to function
|
||||||
// `Error(string)`. So it's a special tool for it.
|
// `Error(string)` or `Panic(uint256)`. So it's a special tool for it.
|
||||||
func UnpackRevert(data []byte) (string, error) {
|
func UnpackRevert(data []byte) (string, error) {
|
||||||
if len(data) < 4 {
|
if len(data) < 4 {
|
||||||
return "", errors.New("invalid data for unpacking")
|
return "", errors.New("invalid data for unpacking")
|
||||||
}
|
}
|
||||||
if !bytes.Equal(data[:4], revertSelector) {
|
switch {
|
||||||
|
case bytes.Equal(data[:4], revertSelector):
|
||||||
|
typ, err := NewType("string", "", nil)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
unpacked, err := (Arguments{{Type: typ}}).Unpack(data[4:])
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return unpacked[0].(string), nil
|
||||||
|
case bytes.Equal(data[:4], panicSelector):
|
||||||
|
typ, err := NewType("uint256", "", nil)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
unpacked, err := (Arguments{{Type: typ}}).Unpack(data[4:])
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
pCode := unpacked[0].(*big.Int)
|
||||||
|
// uint64 safety check for future
|
||||||
|
// but the code is not bigger than MAX(uint64) now
|
||||||
|
if pCode.IsUint64() {
|
||||||
|
if reason, ok := panicReasons[pCode.Uint64()]; ok {
|
||||||
|
return reason, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("unknown panic code: %#x", pCode), nil
|
||||||
|
default:
|
||||||
return "", errors.New("invalid data for unpacking")
|
return "", errors.New("invalid data for unpacking")
|
||||||
}
|
}
|
||||||
typ, err := NewType("string", "", nil)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
unpacked, err := (Arguments{{Type: typ}}).Unpack(data[4:])
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
return unpacked[0].(string), nil
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -120,6 +120,7 @@ var methods = map[string]Method{
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestReader(t *testing.T) {
|
func TestReader(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
abi := ABI{
|
abi := ABI{
|
||||||
Methods: methods,
|
Methods: methods,
|
||||||
}
|
}
|
||||||
@@ -151,6 +152,7 @@ func TestReader(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestInvalidABI(t *testing.T) {
|
func TestInvalidABI(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
json := `[{ "type" : "function", "name" : "", "constant" : fals }]`
|
json := `[{ "type" : "function", "name" : "", "constant" : fals }]`
|
||||||
_, err := JSON(strings.NewReader(json))
|
_, err := JSON(strings.NewReader(json))
|
||||||
if err == nil {
|
if err == nil {
|
||||||
@@ -170,6 +172,7 @@ func TestInvalidABI(t *testing.T) {
|
|||||||
// constructor(uint256 a, uint256 b) public{}
|
// constructor(uint256 a, uint256 b) public{}
|
||||||
// }
|
// }
|
||||||
func TestConstructor(t *testing.T) {
|
func TestConstructor(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
json := `[{ "inputs": [{"internalType": "uint256","name": "a","type": "uint256" },{ "internalType": "uint256","name": "b","type": "uint256"}],"stateMutability": "nonpayable","type": "constructor"}]`
|
json := `[{ "inputs": [{"internalType": "uint256","name": "a","type": "uint256" },{ "internalType": "uint256","name": "b","type": "uint256"}],"stateMutability": "nonpayable","type": "constructor"}]`
|
||||||
method := NewMethod("", "", Constructor, "nonpayable", false, false, []Argument{{"a", Uint256, false}, {"b", Uint256, false}}, nil)
|
method := NewMethod("", "", Constructor, "nonpayable", false, false, []Argument{{"a", Uint256, false}, {"b", Uint256, false}}, nil)
|
||||||
// Test from JSON
|
// Test from JSON
|
||||||
@@ -199,6 +202,7 @@ func TestConstructor(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestTestNumbers(t *testing.T) {
|
func TestTestNumbers(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
abi, err := JSON(strings.NewReader(jsondata))
|
abi, err := JSON(strings.NewReader(jsondata))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@@ -236,6 +240,7 @@ func TestTestNumbers(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestMethodSignature(t *testing.T) {
|
func TestMethodSignature(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
m := NewMethod("foo", "foo", Function, "", false, false, []Argument{{"bar", String, false}, {"baz", String, false}}, nil)
|
m := NewMethod("foo", "foo", Function, "", false, false, []Argument{{"bar", String, false}, {"baz", String, false}}, nil)
|
||||||
exp := "foo(string,string)"
|
exp := "foo(string,string)"
|
||||||
if m.Sig != exp {
|
if m.Sig != exp {
|
||||||
@@ -274,6 +279,7 @@ func TestMethodSignature(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestOverloadedMethodSignature(t *testing.T) {
|
func TestOverloadedMethodSignature(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
json := `[{"constant":true,"inputs":[{"name":"i","type":"uint256"},{"name":"j","type":"uint256"}],"name":"foo","outputs":[],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"name":"i","type":"uint256"}],"name":"foo","outputs":[],"payable":false,"stateMutability":"pure","type":"function"},{"anonymous":false,"inputs":[{"indexed":false,"name":"i","type":"uint256"}],"name":"bar","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"i","type":"uint256"},{"indexed":false,"name":"j","type":"uint256"}],"name":"bar","type":"event"}]`
|
json := `[{"constant":true,"inputs":[{"name":"i","type":"uint256"},{"name":"j","type":"uint256"}],"name":"foo","outputs":[],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"name":"i","type":"uint256"}],"name":"foo","outputs":[],"payable":false,"stateMutability":"pure","type":"function"},{"anonymous":false,"inputs":[{"indexed":false,"name":"i","type":"uint256"}],"name":"bar","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"i","type":"uint256"},{"indexed":false,"name":"j","type":"uint256"}],"name":"bar","type":"event"}]`
|
||||||
abi, err := JSON(strings.NewReader(json))
|
abi, err := JSON(strings.NewReader(json))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -297,6 +303,7 @@ func TestOverloadedMethodSignature(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestCustomErrors(t *testing.T) {
|
func TestCustomErrors(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
json := `[{ "inputs": [ { "internalType": "uint256", "name": "", "type": "uint256" } ],"name": "MyError", "type": "error"} ]`
|
json := `[{ "inputs": [ { "internalType": "uint256", "name": "", "type": "uint256" } ],"name": "MyError", "type": "error"} ]`
|
||||||
abi, err := JSON(strings.NewReader(json))
|
abi, err := JSON(strings.NewReader(json))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -311,6 +318,7 @@ func TestCustomErrors(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestMultiPack(t *testing.T) {
|
func TestMultiPack(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
abi, err := JSON(strings.NewReader(jsondata))
|
abi, err := JSON(strings.NewReader(jsondata))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@@ -348,6 +356,7 @@ func ExampleJSON() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestInputVariableInputLength(t *testing.T) {
|
func TestInputVariableInputLength(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
const definition = `[
|
const definition = `[
|
||||||
{ "type" : "function", "name" : "strOne", "constant" : true, "inputs" : [ { "name" : "str", "type" : "string" } ] },
|
{ "type" : "function", "name" : "strOne", "constant" : true, "inputs" : [ { "name" : "str", "type" : "string" } ] },
|
||||||
{ "type" : "function", "name" : "bytesOne", "constant" : true, "inputs" : [ { "name" : "str", "type" : "bytes" } ] },
|
{ "type" : "function", "name" : "bytesOne", "constant" : true, "inputs" : [ { "name" : "str", "type" : "bytes" } ] },
|
||||||
@@ -476,6 +485,7 @@ func TestInputVariableInputLength(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestInputFixedArrayAndVariableInputLength(t *testing.T) {
|
func TestInputFixedArrayAndVariableInputLength(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
abi, err := JSON(strings.NewReader(jsondata))
|
abi, err := JSON(strings.NewReader(jsondata))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
@@ -650,6 +660,7 @@ func TestInputFixedArrayAndVariableInputLength(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestDefaultFunctionParsing(t *testing.T) {
|
func TestDefaultFunctionParsing(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
const definition = `[{ "name" : "balance", "type" : "function" }]`
|
const definition = `[{ "name" : "balance", "type" : "function" }]`
|
||||||
|
|
||||||
abi, err := JSON(strings.NewReader(definition))
|
abi, err := JSON(strings.NewReader(definition))
|
||||||
@@ -663,6 +674,7 @@ func TestDefaultFunctionParsing(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestBareEvents(t *testing.T) {
|
func TestBareEvents(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
const definition = `[
|
const definition = `[
|
||||||
{ "type" : "event", "name" : "balance" },
|
{ "type" : "event", "name" : "balance" },
|
||||||
{ "type" : "event", "name" : "anon", "anonymous" : true},
|
{ "type" : "event", "name" : "anon", "anonymous" : true},
|
||||||
@@ -739,6 +751,7 @@ func TestBareEvents(t *testing.T) {
|
|||||||
//
|
//
|
||||||
// receipt{status=1 cgas=23949 bloom=00000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000040200000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 logs=[log: b6818c8064f645cd82d99b59a1a267d6d61117ef [75fd880d39c1daf53b6547ab6cb59451fc6452d27caa90e5b6649dd8293b9eed] 000000000000000000000000376c47978271565f56deb45495afa69e59c16ab200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000158 9ae378b6d4409eada347a5dc0c180f186cb62dc68fcc0f043425eb917335aa28 0 95d429d309bb9d753954195fe2d69bd140b4ae731b9b5b605c34323de162cf00 0]}
|
// receipt{status=1 cgas=23949 bloom=00000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000040200000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 logs=[log: b6818c8064f645cd82d99b59a1a267d6d61117ef [75fd880d39c1daf53b6547ab6cb59451fc6452d27caa90e5b6649dd8293b9eed] 000000000000000000000000376c47978271565f56deb45495afa69e59c16ab200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000158 9ae378b6d4409eada347a5dc0c180f186cb62dc68fcc0f043425eb917335aa28 0 95d429d309bb9d753954195fe2d69bd140b4ae731b9b5b605c34323de162cf00 0]}
|
||||||
func TestUnpackEvent(t *testing.T) {
|
func TestUnpackEvent(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
const abiJSON = `[{"constant":false,"inputs":[{"name":"memo","type":"bytes"}],"name":"receive","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"anonymous":false,"inputs":[{"indexed":false,"name":"sender","type":"address"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"memo","type":"bytes"}],"name":"received","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"sender","type":"address"}],"name":"receivedAddr","type":"event"}]`
|
const abiJSON = `[{"constant":false,"inputs":[{"name":"memo","type":"bytes"}],"name":"receive","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"anonymous":false,"inputs":[{"indexed":false,"name":"sender","type":"address"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"memo","type":"bytes"}],"name":"received","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"sender","type":"address"}],"name":"receivedAddr","type":"event"}]`
|
||||||
abi, err := JSON(strings.NewReader(abiJSON))
|
abi, err := JSON(strings.NewReader(abiJSON))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -777,6 +790,7 @@ func TestUnpackEvent(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestUnpackEventIntoMap(t *testing.T) {
|
func TestUnpackEventIntoMap(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
const abiJSON = `[{"constant":false,"inputs":[{"name":"memo","type":"bytes"}],"name":"receive","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"anonymous":false,"inputs":[{"indexed":false,"name":"sender","type":"address"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"memo","type":"bytes"}],"name":"received","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"sender","type":"address"}],"name":"receivedAddr","type":"event"}]`
|
const abiJSON = `[{"constant":false,"inputs":[{"name":"memo","type":"bytes"}],"name":"receive","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"anonymous":false,"inputs":[{"indexed":false,"name":"sender","type":"address"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"memo","type":"bytes"}],"name":"received","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"sender","type":"address"}],"name":"receivedAddr","type":"event"}]`
|
||||||
abi, err := JSON(strings.NewReader(abiJSON))
|
abi, err := JSON(strings.NewReader(abiJSON))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -827,6 +841,7 @@ func TestUnpackEventIntoMap(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestUnpackMethodIntoMap(t *testing.T) {
|
func TestUnpackMethodIntoMap(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
const abiJSON = `[{"constant":false,"inputs":[{"name":"memo","type":"bytes"}],"name":"receive","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[],"name":"send","outputs":[{"name":"amount","type":"uint256"}],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"name":"addr","type":"address"}],"name":"get","outputs":[{"name":"hash","type":"bytes"}],"payable":true,"stateMutability":"payable","type":"function"}]`
|
const abiJSON = `[{"constant":false,"inputs":[{"name":"memo","type":"bytes"}],"name":"receive","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[],"name":"send","outputs":[{"name":"amount","type":"uint256"}],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"name":"addr","type":"address"}],"name":"get","outputs":[{"name":"hash","type":"bytes"}],"payable":true,"stateMutability":"payable","type":"function"}]`
|
||||||
abi, err := JSON(strings.NewReader(abiJSON))
|
abi, err := JSON(strings.NewReader(abiJSON))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -877,6 +892,7 @@ func TestUnpackMethodIntoMap(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestUnpackIntoMapNamingConflict(t *testing.T) {
|
func TestUnpackIntoMapNamingConflict(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
// Two methods have the same name
|
// Two methods have the same name
|
||||||
var abiJSON = `[{"constant":false,"inputs":[{"name":"memo","type":"bytes"}],"name":"get","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[],"name":"send","outputs":[{"name":"amount","type":"uint256"}],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"name":"addr","type":"address"}],"name":"get","outputs":[{"name":"hash","type":"bytes"}],"payable":true,"stateMutability":"payable","type":"function"}]`
|
var abiJSON = `[{"constant":false,"inputs":[{"name":"memo","type":"bytes"}],"name":"get","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[],"name":"send","outputs":[{"name":"amount","type":"uint256"}],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"name":"addr","type":"address"}],"name":"get","outputs":[{"name":"hash","type":"bytes"}],"payable":true,"stateMutability":"payable","type":"function"}]`
|
||||||
abi, err := JSON(strings.NewReader(abiJSON))
|
abi, err := JSON(strings.NewReader(abiJSON))
|
||||||
@@ -960,6 +976,7 @@ func TestUnpackIntoMapNamingConflict(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestABI_MethodById(t *testing.T) {
|
func TestABI_MethodById(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
abi, err := JSON(strings.NewReader(jsondata))
|
abi, err := JSON(strings.NewReader(jsondata))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@@ -992,6 +1009,7 @@ func TestABI_MethodById(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestABI_EventById(t *testing.T) {
|
func TestABI_EventById(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
json string
|
json string
|
||||||
@@ -1058,6 +1076,7 @@ func TestABI_EventById(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestABI_ErrorByID(t *testing.T) {
|
func TestABI_ErrorByID(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
abi, err := JSON(strings.NewReader(`[
|
abi, err := JSON(strings.NewReader(`[
|
||||||
{"inputs":[{"internalType":"uint256","name":"x","type":"uint256"}],"name":"MyError1","type":"error"},
|
{"inputs":[{"internalType":"uint256","name":"x","type":"uint256"}],"name":"MyError1","type":"error"},
|
||||||
{"inputs":[{"components":[{"internalType":"uint256","name":"a","type":"uint256"},{"internalType":"string","name":"b","type":"string"},{"internalType":"address","name":"c","type":"address"}],"internalType":"struct MyError.MyStruct","name":"x","type":"tuple"},{"internalType":"address","name":"y","type":"address"},{"components":[{"internalType":"uint256","name":"a","type":"uint256"},{"internalType":"string","name":"b","type":"string"},{"internalType":"address","name":"c","type":"address"}],"internalType":"struct MyError.MyStruct","name":"z","type":"tuple"}],"name":"MyError2","type":"error"},
|
{"inputs":[{"components":[{"internalType":"uint256","name":"a","type":"uint256"},{"internalType":"string","name":"b","type":"string"},{"internalType":"address","name":"c","type":"address"}],"internalType":"struct MyError.MyStruct","name":"x","type":"tuple"},{"internalType":"address","name":"y","type":"address"},{"components":[{"internalType":"uint256","name":"a","type":"uint256"},{"internalType":"string","name":"b","type":"string"},{"internalType":"address","name":"c","type":"address"}],"internalType":"struct MyError.MyStruct","name":"z","type":"tuple"}],"name":"MyError2","type":"error"},
|
||||||
@@ -1088,6 +1107,7 @@ func TestABI_ErrorByID(t *testing.T) {
|
|||||||
// TestDoubleDuplicateMethodNames checks that if transfer0 already exists, there won't be a name
|
// TestDoubleDuplicateMethodNames checks that if transfer0 already exists, there won't be a name
|
||||||
// conflict and that the second transfer method will be renamed transfer1.
|
// conflict and that the second transfer method will be renamed transfer1.
|
||||||
func TestDoubleDuplicateMethodNames(t *testing.T) {
|
func TestDoubleDuplicateMethodNames(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
abiJSON := `[{"constant":false,"inputs":[{"name":"to","type":"address"},{"name":"value","type":"uint256"}],"name":"transfer","outputs":[{"name":"ok","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"to","type":"address"},{"name":"value","type":"uint256"},{"name":"data","type":"bytes"}],"name":"transfer0","outputs":[{"name":"ok","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"to","type":"address"},{"name":"value","type":"uint256"},{"name":"data","type":"bytes"},{"name":"customFallback","type":"string"}],"name":"transfer","outputs":[{"name":"ok","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"}]`
|
abiJSON := `[{"constant":false,"inputs":[{"name":"to","type":"address"},{"name":"value","type":"uint256"}],"name":"transfer","outputs":[{"name":"ok","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"to","type":"address"},{"name":"value","type":"uint256"},{"name":"data","type":"bytes"}],"name":"transfer0","outputs":[{"name":"ok","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"to","type":"address"},{"name":"value","type":"uint256"},{"name":"data","type":"bytes"},{"name":"customFallback","type":"string"}],"name":"transfer","outputs":[{"name":"ok","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"}]`
|
||||||
contractAbi, err := JSON(strings.NewReader(abiJSON))
|
contractAbi, err := JSON(strings.NewReader(abiJSON))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -1117,6 +1137,7 @@ func TestDoubleDuplicateMethodNames(t *testing.T) {
|
|||||||
// event send();
|
// event send();
|
||||||
// }
|
// }
|
||||||
func TestDoubleDuplicateEventNames(t *testing.T) {
|
func TestDoubleDuplicateEventNames(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
abiJSON := `[{"anonymous": false,"inputs": [{"indexed": false,"internalType": "uint256","name": "a","type": "uint256"}],"name": "send","type": "event"},{"anonymous": false,"inputs": [],"name": "send0","type": "event"},{ "anonymous": false, "inputs": [],"name": "send","type": "event"}]`
|
abiJSON := `[{"anonymous": false,"inputs": [{"indexed": false,"internalType": "uint256","name": "a","type": "uint256"}],"name": "send","type": "event"},{"anonymous": false,"inputs": [],"name": "send0","type": "event"},{ "anonymous": false, "inputs": [],"name": "send","type": "event"}]`
|
||||||
contractAbi, err := JSON(strings.NewReader(abiJSON))
|
contractAbi, err := JSON(strings.NewReader(abiJSON))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -1144,6 +1165,7 @@ func TestDoubleDuplicateEventNames(t *testing.T) {
|
|||||||
// event send(uint256, uint256);
|
// event send(uint256, uint256);
|
||||||
// }
|
// }
|
||||||
func TestUnnamedEventParam(t *testing.T) {
|
func TestUnnamedEventParam(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
abiJSON := `[{ "anonymous": false, "inputs": [{ "indexed": false,"internalType": "uint256", "name": "","type": "uint256"},{"indexed": false,"internalType": "uint256","name": "","type": "uint256"}],"name": "send","type": "event"}]`
|
abiJSON := `[{ "anonymous": false, "inputs": [{ "indexed": false,"internalType": "uint256", "name": "","type": "uint256"},{"indexed": false,"internalType": "uint256","name": "","type": "uint256"}],"name": "send","type": "event"}]`
|
||||||
contractAbi, err := JSON(strings.NewReader(abiJSON))
|
contractAbi, err := JSON(strings.NewReader(abiJSON))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -1173,9 +1195,13 @@ func TestUnpackRevert(t *testing.T) {
|
|||||||
{"", "", errors.New("invalid data for unpacking")},
|
{"", "", errors.New("invalid data for unpacking")},
|
||||||
{"08c379a1", "", errors.New("invalid data for unpacking")},
|
{"08c379a1", "", errors.New("invalid data for unpacking")},
|
||||||
{"08c379a00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000d72657665727420726561736f6e00000000000000000000000000000000000000", "revert reason", nil},
|
{"08c379a00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000d72657665727420726561736f6e00000000000000000000000000000000000000", "revert reason", nil},
|
||||||
|
{"4e487b710000000000000000000000000000000000000000000000000000000000000000", "generic panic", nil},
|
||||||
|
{"4e487b7100000000000000000000000000000000000000000000000000000000000000ff", "unknown panic code: 0xff", nil},
|
||||||
}
|
}
|
||||||
for index, c := range cases {
|
for index, c := range cases {
|
||||||
|
index, c := index, c
|
||||||
t.Run(fmt.Sprintf("case %d", index), func(t *testing.T) {
|
t.Run(fmt.Sprintf("case %d", index), func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
got, err := UnpackRevert(common.Hex2Bytes(c.input))
|
got, err := UnpackRevert(common.Hex2Bytes(c.input))
|
||||||
if c.expectErr != nil {
|
if c.expectErr != nil {
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
|||||||
@@ -20,20 +20,34 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi"
|
|
||||||
fuzz "github.com/google/gofuzz"
|
fuzz "github.com/google/gofuzz"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// TestReplicate can be used to replicate crashers from the fuzzing tests.
|
||||||
|
// Just replace testString with the data in .quoted
|
||||||
|
func TestReplicate(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
//t.Skip("Test only useful for reproducing issues")
|
||||||
|
fuzzAbi([]byte("\x20\x20\x20\x20\x20\x20\x20\x20\x80\x00\x00\x00\x20\x20\x20\x20\x00"))
|
||||||
|
//fuzzAbi([]byte("asdfasdfkadsf;lasdf;lasd;lfk"))
|
||||||
|
}
|
||||||
|
|
||||||
|
// FuzzABI is the main entrypoint for fuzzing
|
||||||
|
func FuzzABI(f *testing.F) {
|
||||||
|
f.Fuzz(func(t *testing.T, data []byte) {
|
||||||
|
fuzzAbi(data)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
names = []string{"_name", "name", "NAME", "name_", "__", "_name_", "n"}
|
names = []string{"_name", "name", "NAME", "name_", "__", "_name_", "n"}
|
||||||
stateMut = []string{"", "pure", "view", "payable"}
|
stateMut = []string{"pure", "view", "payable"}
|
||||||
stateMutabilites = []*string{&stateMut[0], &stateMut[1], &stateMut[2], &stateMut[3]}
|
pays = []string{"true", "false"}
|
||||||
pays = []string{"", "true", "false"}
|
vNames = []string{"a", "b", "c", "d", "e", "f", "g"}
|
||||||
payables = []*string{&pays[0], &pays[1]}
|
varNames = append(vNames, names...)
|
||||||
vNames = []string{"a", "b", "c", "d", "e", "f", "g"}
|
varTypes = []string{"bool", "address", "bytes", "string",
|
||||||
varNames = append(vNames, names...)
|
|
||||||
varTypes = []string{"bool", "address", "bytes", "string",
|
|
||||||
"uint8", "int8", "uint8", "int8", "uint16", "int16",
|
"uint8", "int8", "uint8", "int8", "uint16", "int16",
|
||||||
"uint24", "int24", "uint32", "int32", "uint40", "int40", "uint48", "int48", "uint56", "int56",
|
"uint24", "int24", "uint32", "int32", "uint40", "int40", "uint48", "int48", "uint56", "int56",
|
||||||
"uint64", "int64", "uint72", "int72", "uint80", "int80", "uint88", "int88", "uint96", "int96",
|
"uint64", "int64", "uint72", "int72", "uint80", "int80", "uint88", "int88", "uint96", "int96",
|
||||||
@@ -47,7 +61,7 @@ var (
|
|||||||
"bytes32", "bytes"}
|
"bytes32", "bytes"}
|
||||||
)
|
)
|
||||||
|
|
||||||
func unpackPack(abi abi.ABI, method string, input []byte) ([]interface{}, bool) {
|
func unpackPack(abi ABI, method string, input []byte) ([]interface{}, bool) {
|
||||||
if out, err := abi.Unpack(method, input); err == nil {
|
if out, err := abi.Unpack(method, input); err == nil {
|
||||||
_, err := abi.Pack(method, out...)
|
_, err := abi.Pack(method, out...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -63,7 +77,7 @@ func unpackPack(abi abi.ABI, method string, input []byte) ([]interface{}, bool)
|
|||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
|
|
||||||
func packUnpack(abi abi.ABI, method string, input *[]interface{}) bool {
|
func packUnpack(abi ABI, method string, input *[]interface{}) bool {
|
||||||
if packed, err := abi.Pack(method, input); err == nil {
|
if packed, err := abi.Pack(method, input); err == nil {
|
||||||
outptr := reflect.New(reflect.TypeOf(input))
|
outptr := reflect.New(reflect.TypeOf(input))
|
||||||
err := abi.UnpackIntoInterface(outptr.Interface(), method, packed)
|
err := abi.UnpackIntoInterface(outptr.Interface(), method, packed)
|
||||||
@@ -79,12 +93,12 @@ func packUnpack(abi abi.ABI, method string, input *[]interface{}) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
type args struct {
|
type arg struct {
|
||||||
name string
|
name string
|
||||||
typ string
|
typ string
|
||||||
}
|
}
|
||||||
|
|
||||||
func createABI(name string, stateMutability, payable *string, inputs []args) (abi.ABI, error) {
|
func createABI(name string, stateMutability, payable *string, inputs []arg) (ABI, error) {
|
||||||
sig := fmt.Sprintf(`[{ "type" : "function", "name" : "%v" `, name)
|
sig := fmt.Sprintf(`[{ "type" : "function", "name" : "%v" `, name)
|
||||||
if stateMutability != nil {
|
if stateMutability != nil {
|
||||||
sig += fmt.Sprintf(`, "stateMutability": "%v" `, *stateMutability)
|
sig += fmt.Sprintf(`, "stateMutability": "%v" `, *stateMutability)
|
||||||
@@ -111,60 +125,55 @@ func createABI(name string, stateMutability, payable *string, inputs []args) (ab
|
|||||||
sig += "} ]"
|
sig += "} ]"
|
||||||
}
|
}
|
||||||
sig += `}]`
|
sig += `}]`
|
||||||
|
//fmt.Printf("sig: %s\n", sig)
|
||||||
return abi.JSON(strings.NewReader(sig))
|
return JSON(strings.NewReader(sig))
|
||||||
}
|
}
|
||||||
|
|
||||||
func runFuzzer(input []byte) int {
|
func fuzzAbi(input []byte) {
|
||||||
good := false
|
var (
|
||||||
fuzzer := fuzz.NewFromGoFuzz(input)
|
fuzzer = fuzz.NewFromGoFuzz(input)
|
||||||
|
name = oneOf(fuzzer, names)
|
||||||
name := names[getUInt(fuzzer)%len(names)]
|
stateM = oneOfOrNil(fuzzer, stateMut)
|
||||||
stateM := stateMutabilites[getUInt(fuzzer)%len(stateMutabilites)]
|
payable = oneOfOrNil(fuzzer, pays)
|
||||||
payable := payables[getUInt(fuzzer)%len(payables)]
|
arguments []arg
|
||||||
maxLen := 5
|
)
|
||||||
for k := 1; k < maxLen; k++ {
|
for i := 0; i < upTo(fuzzer, 10); i++ {
|
||||||
var arg []args
|
argName := oneOf(fuzzer, varNames)
|
||||||
for i := k; i > 0; i-- {
|
argTyp := oneOf(fuzzer, varTypes)
|
||||||
argName := varNames[i]
|
switch upTo(fuzzer, 10) {
|
||||||
argTyp := varTypes[getUInt(fuzzer)%len(varTypes)]
|
case 0: // 10% chance to make it a slice
|
||||||
if getUInt(fuzzer)%10 == 0 {
|
argTyp += "[]"
|
||||||
argTyp += "[]"
|
case 1: // 10% chance to make it an array
|
||||||
} else if getUInt(fuzzer)%10 == 0 {
|
argTyp += fmt.Sprintf("[%d]", 1+upTo(fuzzer, 30))
|
||||||
arrayArgs := getUInt(fuzzer)%30 + 1
|
default:
|
||||||
argTyp += fmt.Sprintf("[%d]", arrayArgs)
|
|
||||||
}
|
|
||||||
arg = append(arg, args{
|
|
||||||
name: argName,
|
|
||||||
typ: argTyp,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
abi, err := createABI(name, stateM, payable, arg)
|
arguments = append(arguments, arg{name: argName, typ: argTyp})
|
||||||
if err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
structs, b := unpackPack(abi, name, input)
|
|
||||||
c := packUnpack(abi, name, &structs)
|
|
||||||
good = good || b || c
|
|
||||||
}
|
}
|
||||||
if good {
|
abi, err := createABI(name, stateM, payable, arguments)
|
||||||
return 1
|
if err != nil {
|
||||||
|
//fmt.Printf("err: %v\n", err)
|
||||||
|
panic(err)
|
||||||
}
|
}
|
||||||
return 0
|
structs, _ := unpackPack(abi, name, input)
|
||||||
|
_ = packUnpack(abi, name, &structs)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Fuzz(input []byte) int {
|
func upTo(fuzzer *fuzz.Fuzzer, max int) int {
|
||||||
return runFuzzer(input)
|
|
||||||
}
|
|
||||||
|
|
||||||
func getUInt(fuzzer *fuzz.Fuzzer) int {
|
|
||||||
var i int
|
var i int
|
||||||
fuzzer.Fuzz(&i)
|
fuzzer.Fuzz(&i)
|
||||||
if i < 0 {
|
if i < 0 {
|
||||||
i = -i
|
return (-1 - i) % max
|
||||||
if i < 0 {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return i
|
return i % max
|
||||||
|
}
|
||||||
|
|
||||||
|
func oneOf(fuzzer *fuzz.Fuzzer, options []string) string {
|
||||||
|
return options[upTo(fuzzer, len(options))]
|
||||||
|
}
|
||||||
|
|
||||||
|
func oneOfOrNil(fuzzer *fuzz.Fuzzer, options []string) *string {
|
||||||
|
if i := upTo(fuzzer, len(options)+1); i < len(options) {
|
||||||
|
return &options[i]
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
@@ -80,7 +80,7 @@ func (arguments Arguments) isTuple() bool {
|
|||||||
func (arguments Arguments) Unpack(data []byte) ([]interface{}, error) {
|
func (arguments Arguments) Unpack(data []byte) ([]interface{}, error) {
|
||||||
if len(data) == 0 {
|
if len(data) == 0 {
|
||||||
if len(arguments.NonIndexed()) != 0 {
|
if len(arguments.NonIndexed()) != 0 {
|
||||||
return nil, errors.New("abi: attempting to unmarshall an empty string while arguments are expected")
|
return nil, errors.New("abi: attempting to unmarshal an empty string while arguments are expected")
|
||||||
}
|
}
|
||||||
return make([]interface{}, 0), nil
|
return make([]interface{}, 0), nil
|
||||||
}
|
}
|
||||||
@@ -95,7 +95,7 @@ func (arguments Arguments) UnpackIntoMap(v map[string]interface{}, data []byte)
|
|||||||
}
|
}
|
||||||
if len(data) == 0 {
|
if len(data) == 0 {
|
||||||
if len(arguments.NonIndexed()) != 0 {
|
if len(arguments.NonIndexed()) != 0 {
|
||||||
return errors.New("abi: attempting to unmarshall an empty string while arguments are expected")
|
return errors.New("abi: attempting to unmarshal an empty string while arguments are expected")
|
||||||
}
|
}
|
||||||
return nil // Nothing to unmarshal, return
|
return nil // Nothing to unmarshal, return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ func NewTransactor(keyin io.Reader, passphrase string) (*TransactOpts, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewKeyStoreTransactor is a utility method to easily create a transaction signer from
|
// NewKeyStoreTransactor is a utility method to easily create a transaction signer from
|
||||||
// an decrypted key from a keystore.
|
// a decrypted key from a keystore.
|
||||||
//
|
//
|
||||||
// Deprecated: Use NewKeyStoreTransactorWithChainID instead.
|
// Deprecated: Use NewKeyStoreTransactorWithChainID instead.
|
||||||
func NewKeyStoreTransactor(keystore *keystore.KeyStore, account accounts.Account) (*TransactOpts, error) {
|
func NewKeyStoreTransactor(keystore *keystore.KeyStore, account accounts.Account) (*TransactOpts, error) {
|
||||||
@@ -117,7 +117,7 @@ func NewTransactorWithChainID(keyin io.Reader, passphrase string, chainID *big.I
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewKeyStoreTransactorWithChainID is a utility method to easily create a transaction signer from
|
// NewKeyStoreTransactorWithChainID is a utility method to easily create a transaction signer from
|
||||||
// an decrypted key from a keystore.
|
// a decrypted key from a keystore.
|
||||||
func NewKeyStoreTransactorWithChainID(keystore *keystore.KeyStore, account accounts.Account, chainID *big.Int) (*TransactOpts, error) {
|
func NewKeyStoreTransactorWithChainID(keystore *keystore.KeyStore, account accounts.Account, chainID *big.Int) (*TransactOpts, error) {
|
||||||
if chainID == nil {
|
if chainID == nil {
|
||||||
return nil, ErrNoChainID
|
return nil, ErrNoChainID
|
||||||
|
|||||||
@@ -37,6 +37,10 @@ var (
|
|||||||
// on a backend that doesn't implement PendingContractCaller.
|
// on a backend that doesn't implement PendingContractCaller.
|
||||||
ErrNoPendingState = errors.New("backend does not support pending state")
|
ErrNoPendingState = errors.New("backend does not support pending state")
|
||||||
|
|
||||||
|
// ErrNoBlockHashState is raised when attempting to perform a block hash action
|
||||||
|
// on a backend that doesn't implement BlockHashContractCaller.
|
||||||
|
ErrNoBlockHashState = errors.New("backend does not support block hash state")
|
||||||
|
|
||||||
// ErrNoCodeAfterDeploy is returned by WaitDeployed if contract creation leaves
|
// ErrNoCodeAfterDeploy is returned by WaitDeployed if contract creation leaves
|
||||||
// an empty contract behind.
|
// an empty contract behind.
|
||||||
ErrNoCodeAfterDeploy = errors.New("no contract code after deployment")
|
ErrNoCodeAfterDeploy = errors.New("no contract code after deployment")
|
||||||
@@ -65,11 +69,27 @@ type PendingContractCaller interface {
|
|||||||
PendingCallContract(ctx context.Context, call ethereum.CallMsg) ([]byte, error)
|
PendingCallContract(ctx context.Context, call ethereum.CallMsg) ([]byte, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// BlockHashContractCaller defines methods to perform contract calls on a specific block hash.
|
||||||
|
// Call will try to discover this interface when access to a block by hash is requested.
|
||||||
|
// If the backend does not support the block hash state, Call returns ErrNoBlockHashState.
|
||||||
|
type BlockHashContractCaller interface {
|
||||||
|
// CodeAtHash returns the code of the given account in the state at the specified block hash.
|
||||||
|
CodeAtHash(ctx context.Context, contract common.Address, blockHash common.Hash) ([]byte, error)
|
||||||
|
|
||||||
|
// CallContractAtHash executes an Ethereum contract call against the state at the specified block hash.
|
||||||
|
CallContractAtHash(ctx context.Context, call ethereum.CallMsg, blockHash common.Hash) ([]byte, error)
|
||||||
|
}
|
||||||
|
|
||||||
// ContractTransactor defines the methods needed to allow operating with a contract
|
// ContractTransactor defines the methods needed to allow operating with a contract
|
||||||
// on a write only basis. Besides the transacting method, the remainder are helpers
|
// on a write only basis. Besides the transacting method, the remainder are helpers
|
||||||
// used when the user does not provide some needed values, but rather leaves it up
|
// used when the user does not provide some needed values, but rather leaves it up
|
||||||
// to the transactor to decide.
|
// to the transactor to decide.
|
||||||
type ContractTransactor interface {
|
type ContractTransactor interface {
|
||||||
|
ethereum.GasEstimator
|
||||||
|
ethereum.GasPricer
|
||||||
|
ethereum.GasPricer1559
|
||||||
|
ethereum.TransactionSender
|
||||||
|
|
||||||
// HeaderByNumber returns a block header from the current canonical chain. If
|
// HeaderByNumber returns a block header from the current canonical chain. If
|
||||||
// number is nil, the latest known header is returned.
|
// number is nil, the latest known header is returned.
|
||||||
HeaderByNumber(ctx context.Context, number *big.Int) (*types.Header, error)
|
HeaderByNumber(ctx context.Context, number *big.Int) (*types.Header, error)
|
||||||
@@ -80,48 +100,22 @@ type ContractTransactor interface {
|
|||||||
// PendingNonceAt retrieves the current pending nonce associated with an account.
|
// PendingNonceAt retrieves the current pending nonce associated with an account.
|
||||||
PendingNonceAt(ctx context.Context, account common.Address) (uint64, error)
|
PendingNonceAt(ctx context.Context, account common.Address) (uint64, error)
|
||||||
|
|
||||||
// SuggestGasPrice retrieves the currently suggested gas price to allow a timely
|
|
||||||
// execution of a transaction.
|
|
||||||
SuggestGasPrice(ctx context.Context) (*big.Int, error)
|
|
||||||
|
|
||||||
// SuggestGasTipCap retrieves the currently suggested 1559 priority fee to allow
|
|
||||||
// a timely execution of a transaction.
|
|
||||||
SuggestGasTipCap(ctx context.Context) (*big.Int, error)
|
|
||||||
|
|
||||||
// EstimateGas tries to estimate the gas needed to execute a specific
|
|
||||||
// transaction based on the current pending state of the backend blockchain.
|
|
||||||
// There is no guarantee that this is the true gas limit requirement as other
|
|
||||||
// transactions may be added or removed by miners, but it should provide a basis
|
|
||||||
// for setting a reasonable default.
|
|
||||||
EstimateGas(ctx context.Context, call ethereum.CallMsg) (gas uint64, err error)
|
|
||||||
|
|
||||||
// SendTransaction injects the transaction into the pending pool for execution.
|
|
||||||
SendTransaction(ctx context.Context, tx *types.Transaction) error
|
|
||||||
|
|
||||||
// SendTransactionConditional injects the conditional transaction into the pending pool for execution after verification.
|
// SendTransactionConditional injects the conditional transaction into the pending pool for execution after verification.
|
||||||
SendTransactionConditional(ctx context.Context, tx *types.Transaction, opts ethapi.TransactionOpts) error
|
SendTransactionConditional(ctx context.Context, tx *types.Transaction, opts ethapi.TransactionOpts) error
|
||||||
}
|
}
|
||||||
|
|
||||||
// ContractFilterer defines the methods needed to access log events using one-off
|
|
||||||
// queries or continuous event subscriptions.
|
|
||||||
type ContractFilterer interface {
|
|
||||||
// FilterLogs executes a log filter operation, blocking during execution and
|
|
||||||
// returning all the results in one batch.
|
|
||||||
//
|
|
||||||
// TODO(karalabe): Deprecate when the subscription one can return past data too.
|
|
||||||
FilterLogs(ctx context.Context, query ethereum.FilterQuery) ([]types.Log, error)
|
|
||||||
|
|
||||||
// SubscribeFilterLogs creates a background log filtering operation, returning
|
|
||||||
// a subscription immediately, which can be used to stream the found events.
|
|
||||||
SubscribeFilterLogs(ctx context.Context, query ethereum.FilterQuery, ch chan<- types.Log) (ethereum.Subscription, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeployBackend wraps the operations needed by WaitMined and WaitDeployed.
|
// DeployBackend wraps the operations needed by WaitMined and WaitDeployed.
|
||||||
type DeployBackend interface {
|
type DeployBackend interface {
|
||||||
TransactionReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error)
|
TransactionReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error)
|
||||||
CodeAt(ctx context.Context, account common.Address, blockNumber *big.Int) ([]byte, error)
|
CodeAt(ctx context.Context, account common.Address, blockNumber *big.Int) ([]byte, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ContractFilterer defines the methods needed to access log events using one-off
|
||||||
|
// queries or continuous event subscriptions.
|
||||||
|
type ContractFilterer interface {
|
||||||
|
ethereum.LogFilterer
|
||||||
|
}
|
||||||
|
|
||||||
// ContractBackend defines the methods needed to work with contracts on a read-write basis.
|
// ContractBackend defines the methods needed to work with contracts on a read-write basis.
|
||||||
type ContractBackend interface {
|
type ContractBackend interface {
|
||||||
ContractCaller
|
ContractCaller
|
||||||
|
|||||||
@@ -18,942 +18,35 @@ package backends
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"math/big"
|
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum"
|
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi"
|
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
|
||||||
"github.com/ethereum/go-ethereum/common/math"
|
|
||||||
"github.com/ethereum/go-ethereum/consensus/ethash"
|
|
||||||
"github.com/ethereum/go-ethereum/core"
|
|
||||||
"github.com/ethereum/go-ethereum/core/bloombits"
|
|
||||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
|
||||||
"github.com/ethereum/go-ethereum/core/state"
|
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/ethclient/simulated"
|
||||||
"github.com/ethereum/go-ethereum/eth/filters"
|
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
|
||||||
"github.com/ethereum/go-ethereum/event"
|
|
||||||
"github.com/ethereum/go-ethereum/internal/ethapi"
|
|
||||||
"github.com/ethereum/go-ethereum/log"
|
|
||||||
"github.com/ethereum/go-ethereum/params"
|
|
||||||
"github.com/ethereum/go-ethereum/rpc"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// This nil assignment ensures at compile time that SimulatedBackend implements bind.ContractBackend.
|
// SimulatedBackend is a simulated blockchain.
|
||||||
var _ bind.ContractBackend = (*SimulatedBackend)(nil)
|
// Deprecated: use package github.com/ethereum/go-ethereum/ethclient/simulated instead.
|
||||||
|
|
||||||
var (
|
|
||||||
errBlockNumberUnsupported = errors.New("simulatedBackend cannot access blocks other than the latest block")
|
|
||||||
errBlockDoesNotExist = errors.New("block does not exist in blockchain")
|
|
||||||
errTransactionDoesNotExist = errors.New("transaction does not exist")
|
|
||||||
)
|
|
||||||
|
|
||||||
// SimulatedBackend implements bind.ContractBackend, simulating a blockchain in
|
|
||||||
// the background. Its main purpose is to allow for easy testing of contract bindings.
|
|
||||||
// Simulated backend implements the following interfaces:
|
|
||||||
// ChainReader, ChainStateReader, ContractBackend, ContractCaller, ContractFilterer, ContractTransactor,
|
|
||||||
// DeployBackend, GasEstimator, GasPricer, LogFilterer, PendingContractCaller, TransactionReader, and TransactionSender
|
|
||||||
type SimulatedBackend struct {
|
type SimulatedBackend struct {
|
||||||
database ethdb.Database // In memory database to store our testing data
|
*simulated.Backend
|
||||||
blockchain *core.BlockChain // Ethereum blockchain to handle the consensus
|
simulated.Client
|
||||||
|
|
||||||
mu sync.Mutex
|
|
||||||
pendingBlock *types.Block // Currently pending block that will be imported on request
|
|
||||||
pendingState *state.StateDB // Currently pending state that will be the active on request
|
|
||||||
pendingReceipts types.Receipts // Currently receipts for the pending block
|
|
||||||
|
|
||||||
events *filters.EventSystem // for filtering log events live
|
|
||||||
filterSystem *filters.FilterSystem // for filtering database logs
|
|
||||||
|
|
||||||
config *params.ChainConfig
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewSimulatedBackendWithDatabase creates a new binding backend based on the given database
|
// Fork sets the head to a new block, which is based on the provided parentHash.
|
||||||
// and uses a simulated blockchain for testing purposes.
|
func (b *SimulatedBackend) Fork(ctx context.Context, parentHash common.Hash) error {
|
||||||
// A simulated backend always uses chainID 1337.
|
return b.Backend.Fork(parentHash)
|
||||||
func NewSimulatedBackendWithDatabase(database ethdb.Database, alloc core.GenesisAlloc, gasLimit uint64) *SimulatedBackend {
|
|
||||||
genesis := core.Genesis{
|
|
||||||
Config: params.AllEthashProtocolChanges,
|
|
||||||
GasLimit: gasLimit,
|
|
||||||
Alloc: alloc,
|
|
||||||
}
|
|
||||||
blockchain, _ := core.NewBlockChain(database, nil, &genesis, nil, ethash.NewFaker(), vm.Config{}, nil, nil)
|
|
||||||
|
|
||||||
backend := &SimulatedBackend{
|
|
||||||
database: database,
|
|
||||||
blockchain: blockchain,
|
|
||||||
config: genesis.Config,
|
|
||||||
}
|
|
||||||
|
|
||||||
filterBackend := &filterBackend{database, blockchain, backend}
|
|
||||||
backend.filterSystem = filters.NewFilterSystem(filterBackend, filters.Config{})
|
|
||||||
backend.events = filters.NewEventSystem(backend.filterSystem, false)
|
|
||||||
|
|
||||||
header := backend.blockchain.CurrentBlock()
|
|
||||||
block := backend.blockchain.GetBlock(header.Hash(), header.Number.Uint64())
|
|
||||||
|
|
||||||
backend.rollback(block)
|
|
||||||
return backend
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewSimulatedBackend creates a new binding backend using a simulated blockchain
|
// NewSimulatedBackend creates a new binding backend using a simulated blockchain
|
||||||
// for testing purposes.
|
// for testing purposes.
|
||||||
|
//
|
||||||
// A simulated backend always uses chainID 1337.
|
// A simulated backend always uses chainID 1337.
|
||||||
func NewSimulatedBackend(alloc core.GenesisAlloc, gasLimit uint64) *SimulatedBackend {
|
|
||||||
return NewSimulatedBackendWithDatabase(rawdb.NewMemoryDatabase(), alloc, gasLimit)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Close terminates the underlying blockchain's update loop.
|
|
||||||
func (b *SimulatedBackend) Close() error {
|
|
||||||
b.blockchain.Stop()
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Commit imports all the pending transactions as a single block and starts a
|
|
||||||
// fresh new state.
|
|
||||||
func (b *SimulatedBackend) Commit() common.Hash {
|
|
||||||
b.mu.Lock()
|
|
||||||
defer b.mu.Unlock()
|
|
||||||
|
|
||||||
if _, err := b.blockchain.InsertChain([]*types.Block{b.pendingBlock}); err != nil {
|
|
||||||
panic(err) // This cannot happen unless the simulator is wrong, fail in that case
|
|
||||||
}
|
|
||||||
blockHash := b.pendingBlock.Hash()
|
|
||||||
|
|
||||||
// Using the last inserted block here makes it possible to build on a side
|
|
||||||
// chain after a fork.
|
|
||||||
b.rollback(b.pendingBlock)
|
|
||||||
|
|
||||||
return blockHash
|
|
||||||
}
|
|
||||||
|
|
||||||
// Rollback aborts all pending transactions, reverting to the last committed state.
|
|
||||||
func (b *SimulatedBackend) Rollback() {
|
|
||||||
b.mu.Lock()
|
|
||||||
defer b.mu.Unlock()
|
|
||||||
|
|
||||||
header := b.blockchain.CurrentBlock()
|
|
||||||
block := b.blockchain.GetBlock(header.Hash(), header.Number.Uint64())
|
|
||||||
|
|
||||||
b.rollback(block)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *SimulatedBackend) rollback(parent *types.Block) {
|
|
||||||
blocks, _ := core.GenerateChain(b.config, parent, ethash.NewFaker(), b.database, 1, func(int, *core.BlockGen) {})
|
|
||||||
|
|
||||||
b.pendingBlock = blocks[0]
|
|
||||||
b.pendingState, _ = state.New(b.pendingBlock.Root(), b.blockchain.StateCache(), nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fork creates a side-chain that can be used to simulate reorgs.
|
|
||||||
//
|
//
|
||||||
// This function should be called with the ancestor block where the new side
|
// Deprecated: please use simulated.Backend from package
|
||||||
// chain should be started. Transactions (old and new) can then be applied on
|
// github.com/ethereum/go-ethereum/ethclient/simulated instead.
|
||||||
// top and Commit-ed.
|
func NewSimulatedBackend(alloc types.GenesisAlloc, gasLimit uint64) *SimulatedBackend {
|
||||||
//
|
b := simulated.NewBackend(alloc, simulated.WithBlockGasLimit(gasLimit))
|
||||||
// Note, the side-chain will only become canonical (and trigger the events) when
|
return &SimulatedBackend{
|
||||||
// it becomes longer. Until then CallContract will still operate on the current
|
Backend: b,
|
||||||
// canonical chain.
|
Client: b.Client(),
|
||||||
//
|
|
||||||
// There is a % chance that the side chain becomes canonical at the same length
|
|
||||||
// to simulate live network behavior.
|
|
||||||
func (b *SimulatedBackend) Fork(ctx context.Context, parent common.Hash) error {
|
|
||||||
b.mu.Lock()
|
|
||||||
defer b.mu.Unlock()
|
|
||||||
|
|
||||||
if len(b.pendingBlock.Transactions()) != 0 {
|
|
||||||
return errors.New("pending block dirty")
|
|
||||||
}
|
|
||||||
block, err := b.blockByHash(ctx, parent)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
b.rollback(block)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// stateByBlockNumber retrieves a state by a given blocknumber.
|
|
||||||
func (b *SimulatedBackend) stateByBlockNumber(ctx context.Context, blockNumber *big.Int) (*state.StateDB, error) {
|
|
||||||
if blockNumber == nil || blockNumber.Cmp(b.blockchain.CurrentBlock().Number) == 0 {
|
|
||||||
return b.blockchain.State()
|
|
||||||
}
|
|
||||||
block, err := b.blockByNumber(ctx, blockNumber)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return b.blockchain.StateAt(block.Root())
|
|
||||||
}
|
|
||||||
|
|
||||||
// CodeAt returns the code associated with a certain account in the blockchain.
|
|
||||||
func (b *SimulatedBackend) CodeAt(ctx context.Context, contract common.Address, blockNumber *big.Int) ([]byte, error) {
|
|
||||||
b.mu.Lock()
|
|
||||||
defer b.mu.Unlock()
|
|
||||||
|
|
||||||
stateDB, err := b.stateByBlockNumber(ctx, blockNumber)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return stateDB.GetCode(contract), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// BalanceAt returns the wei balance of a certain account in the blockchain.
|
|
||||||
func (b *SimulatedBackend) BalanceAt(ctx context.Context, contract common.Address, blockNumber *big.Int) (*big.Int, error) {
|
|
||||||
b.mu.Lock()
|
|
||||||
defer b.mu.Unlock()
|
|
||||||
|
|
||||||
stateDB, err := b.stateByBlockNumber(ctx, blockNumber)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return stateDB.GetBalance(contract), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// NonceAt returns the nonce of a certain account in the blockchain.
|
|
||||||
func (b *SimulatedBackend) NonceAt(ctx context.Context, contract common.Address, blockNumber *big.Int) (uint64, error) {
|
|
||||||
b.mu.Lock()
|
|
||||||
defer b.mu.Unlock()
|
|
||||||
|
|
||||||
stateDB, err := b.stateByBlockNumber(ctx, blockNumber)
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return stateDB.GetNonce(contract), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// StorageAt returns the value of key in the storage of an account in the blockchain.
|
|
||||||
func (b *SimulatedBackend) StorageAt(ctx context.Context, contract common.Address, key common.Hash, blockNumber *big.Int) ([]byte, error) {
|
|
||||||
b.mu.Lock()
|
|
||||||
defer b.mu.Unlock()
|
|
||||||
|
|
||||||
stateDB, err := b.stateByBlockNumber(ctx, blockNumber)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
val := stateDB.GetState(contract, key)
|
|
||||||
return val[:], nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// TransactionReceipt returns the receipt of a transaction.
|
|
||||||
func (b *SimulatedBackend) TransactionReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error) {
|
|
||||||
b.mu.Lock()
|
|
||||||
defer b.mu.Unlock()
|
|
||||||
|
|
||||||
receipt, _, _, _ := rawdb.ReadReceipt(b.database, txHash, b.config)
|
|
||||||
if receipt == nil {
|
|
||||||
return nil, ethereum.NotFound
|
|
||||||
}
|
|
||||||
return receipt, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// TransactionByHash checks the pool of pending transactions in addition to the
|
|
||||||
// blockchain. The isPending return value indicates whether the transaction has been
|
|
||||||
// mined yet. Note that the transaction may not be part of the canonical chain even if
|
|
||||||
// it's not pending.
|
|
||||||
func (b *SimulatedBackend) TransactionByHash(ctx context.Context, txHash common.Hash) (*types.Transaction, bool, error) {
|
|
||||||
b.mu.Lock()
|
|
||||||
defer b.mu.Unlock()
|
|
||||||
|
|
||||||
tx := b.pendingBlock.Transaction(txHash)
|
|
||||||
if tx != nil {
|
|
||||||
return tx, true, nil
|
|
||||||
}
|
|
||||||
tx, _, _, _ = rawdb.ReadTransaction(b.database, txHash)
|
|
||||||
if tx != nil {
|
|
||||||
return tx, false, nil
|
|
||||||
}
|
|
||||||
return nil, false, ethereum.NotFound
|
|
||||||
}
|
|
||||||
|
|
||||||
// BlockByHash retrieves a block based on the block hash.
|
|
||||||
func (b *SimulatedBackend) BlockByHash(ctx context.Context, hash common.Hash) (*types.Block, error) {
|
|
||||||
b.mu.Lock()
|
|
||||||
defer b.mu.Unlock()
|
|
||||||
|
|
||||||
return b.blockByHash(ctx, hash)
|
|
||||||
}
|
|
||||||
|
|
||||||
// blockByHash retrieves a block based on the block hash without Locking.
|
|
||||||
func (b *SimulatedBackend) blockByHash(ctx context.Context, hash common.Hash) (*types.Block, error) {
|
|
||||||
if hash == b.pendingBlock.Hash() {
|
|
||||||
return b.pendingBlock, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
block := b.blockchain.GetBlockByHash(hash)
|
|
||||||
if block != nil {
|
|
||||||
return block, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, errBlockDoesNotExist
|
|
||||||
}
|
|
||||||
|
|
||||||
// BlockByNumber retrieves a block from the database by number, caching it
|
|
||||||
// (associated with its hash) if found.
|
|
||||||
func (b *SimulatedBackend) BlockByNumber(ctx context.Context, number *big.Int) (*types.Block, error) {
|
|
||||||
b.mu.Lock()
|
|
||||||
defer b.mu.Unlock()
|
|
||||||
|
|
||||||
return b.blockByNumber(ctx, number)
|
|
||||||
}
|
|
||||||
|
|
||||||
// blockByNumber retrieves a block from the database by number, caching it
|
|
||||||
// (associated with its hash) if found without Lock.
|
|
||||||
func (b *SimulatedBackend) blockByNumber(ctx context.Context, number *big.Int) (*types.Block, error) {
|
|
||||||
if number == nil || number.Cmp(b.pendingBlock.Number()) == 0 {
|
|
||||||
return b.blockByHash(ctx, b.blockchain.CurrentBlock().Hash())
|
|
||||||
}
|
|
||||||
|
|
||||||
block := b.blockchain.GetBlockByNumber(uint64(number.Int64()))
|
|
||||||
if block == nil {
|
|
||||||
return nil, errBlockDoesNotExist
|
|
||||||
}
|
|
||||||
|
|
||||||
return block, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// HeaderByHash returns a block header from the current canonical chain.
|
|
||||||
func (b *SimulatedBackend) HeaderByHash(ctx context.Context, hash common.Hash) (*types.Header, error) {
|
|
||||||
b.mu.Lock()
|
|
||||||
defer b.mu.Unlock()
|
|
||||||
|
|
||||||
if hash == b.pendingBlock.Hash() {
|
|
||||||
return b.pendingBlock.Header(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
header := b.blockchain.GetHeaderByHash(hash)
|
|
||||||
if header == nil {
|
|
||||||
return nil, errBlockDoesNotExist
|
|
||||||
}
|
|
||||||
|
|
||||||
return header, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// HeaderByNumber returns a block header from the current canonical chain. If number is
|
|
||||||
// nil, the latest known header is returned.
|
|
||||||
func (b *SimulatedBackend) HeaderByNumber(ctx context.Context, block *big.Int) (*types.Header, error) {
|
|
||||||
b.mu.Lock()
|
|
||||||
defer b.mu.Unlock()
|
|
||||||
|
|
||||||
if block == nil || block.Cmp(b.pendingBlock.Number()) == 0 {
|
|
||||||
return b.blockchain.CurrentHeader(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return b.blockchain.GetHeaderByNumber(uint64(block.Int64())), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// TransactionCount returns the number of transactions in a given block.
|
|
||||||
func (b *SimulatedBackend) TransactionCount(ctx context.Context, blockHash common.Hash) (uint, error) {
|
|
||||||
b.mu.Lock()
|
|
||||||
defer b.mu.Unlock()
|
|
||||||
|
|
||||||
if blockHash == b.pendingBlock.Hash() {
|
|
||||||
return uint(b.pendingBlock.Transactions().Len()), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
block := b.blockchain.GetBlockByHash(blockHash)
|
|
||||||
if block == nil {
|
|
||||||
return uint(0), errBlockDoesNotExist
|
|
||||||
}
|
|
||||||
|
|
||||||
return uint(block.Transactions().Len()), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// TransactionInBlock returns the transaction for a specific block at a specific index.
|
|
||||||
func (b *SimulatedBackend) TransactionInBlock(ctx context.Context, blockHash common.Hash, index uint) (*types.Transaction, error) {
|
|
||||||
b.mu.Lock()
|
|
||||||
defer b.mu.Unlock()
|
|
||||||
|
|
||||||
if blockHash == b.pendingBlock.Hash() {
|
|
||||||
transactions := b.pendingBlock.Transactions()
|
|
||||||
if uint(len(transactions)) < index+1 {
|
|
||||||
return nil, errTransactionDoesNotExist
|
|
||||||
}
|
|
||||||
|
|
||||||
return transactions[index], nil
|
|
||||||
}
|
|
||||||
|
|
||||||
block := b.blockchain.GetBlockByHash(blockHash)
|
|
||||||
if block == nil {
|
|
||||||
return nil, errBlockDoesNotExist
|
|
||||||
}
|
|
||||||
|
|
||||||
transactions := block.Transactions()
|
|
||||||
if uint(len(transactions)) < index+1 {
|
|
||||||
return nil, errTransactionDoesNotExist
|
|
||||||
}
|
|
||||||
|
|
||||||
return transactions[index], nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// PendingCodeAt returns the code associated with an account in the pending state.
|
|
||||||
func (b *SimulatedBackend) PendingCodeAt(ctx context.Context, contract common.Address) ([]byte, error) {
|
|
||||||
b.mu.Lock()
|
|
||||||
defer b.mu.Unlock()
|
|
||||||
|
|
||||||
return b.pendingState.GetCode(contract), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func newRevertError(result *core.ExecutionResult) *revertError {
|
|
||||||
reason, errUnpack := abi.UnpackRevert(result.Revert())
|
|
||||||
err := errors.New("execution reverted")
|
|
||||||
if errUnpack == nil {
|
|
||||||
err = fmt.Errorf("execution reverted: %v", reason)
|
|
||||||
}
|
|
||||||
return &revertError{
|
|
||||||
error: err,
|
|
||||||
reason: hexutil.Encode(result.Revert()),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// revertError is an API error that encompasses an EVM revert with JSON error
|
|
||||||
// code and a binary data blob.
|
|
||||||
type revertError struct {
|
|
||||||
error
|
|
||||||
reason string // revert reason hex encoded
|
|
||||||
}
|
|
||||||
|
|
||||||
// ErrorCode returns the JSON error code for a revert.
|
|
||||||
// See: https://github.com/ethereum/wiki/wiki/JSON-RPC-Error-Codes-Improvement-Proposal
|
|
||||||
func (e *revertError) ErrorCode() int {
|
|
||||||
return 3
|
|
||||||
}
|
|
||||||
|
|
||||||
// ErrorData returns the hex encoded revert reason.
|
|
||||||
func (e *revertError) ErrorData() interface{} {
|
|
||||||
return e.reason
|
|
||||||
}
|
|
||||||
|
|
||||||
// CallContract executes a contract call.
|
|
||||||
func (b *SimulatedBackend) CallContract(ctx context.Context, call ethereum.CallMsg, blockNumber *big.Int) ([]byte, error) {
|
|
||||||
b.mu.Lock()
|
|
||||||
defer b.mu.Unlock()
|
|
||||||
|
|
||||||
if blockNumber != nil && blockNumber.Cmp(b.blockchain.CurrentBlock().Number) != 0 {
|
|
||||||
return nil, errBlockNumberUnsupported
|
|
||||||
}
|
|
||||||
stateDB, err := b.blockchain.State()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
res, err := b.callContract(ctx, call, b.blockchain.CurrentBlock(), stateDB)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
// If the result contains a revert reason, try to unpack and return it.
|
|
||||||
if len(res.Revert()) > 0 {
|
|
||||||
return nil, newRevertError(res)
|
|
||||||
}
|
|
||||||
return res.Return(), res.Err
|
|
||||||
}
|
|
||||||
|
|
||||||
// PendingCallContract executes a contract call on the pending state.
|
|
||||||
func (b *SimulatedBackend) PendingCallContract(ctx context.Context, call ethereum.CallMsg) ([]byte, error) {
|
|
||||||
b.mu.Lock()
|
|
||||||
defer b.mu.Unlock()
|
|
||||||
defer b.pendingState.RevertToSnapshot(b.pendingState.Snapshot())
|
|
||||||
|
|
||||||
res, err := b.callContract(ctx, call, b.pendingBlock.Header(), b.pendingState)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
// If the result contains a revert reason, try to unpack and return it.
|
|
||||||
if len(res.Revert()) > 0 {
|
|
||||||
return nil, newRevertError(res)
|
|
||||||
}
|
|
||||||
return res.Return(), res.Err
|
|
||||||
}
|
|
||||||
|
|
||||||
// PendingNonceAt implements PendingStateReader.PendingNonceAt, retrieving
|
|
||||||
// the nonce currently pending for the account.
|
|
||||||
func (b *SimulatedBackend) PendingNonceAt(ctx context.Context, account common.Address) (uint64, error) {
|
|
||||||
b.mu.Lock()
|
|
||||||
defer b.mu.Unlock()
|
|
||||||
|
|
||||||
return b.pendingState.GetOrNewStateObject(account).Nonce(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// SuggestGasPrice implements ContractTransactor.SuggestGasPrice. Since the simulated
|
|
||||||
// chain doesn't have miners, we just return a gas price of 1 for any call.
|
|
||||||
func (b *SimulatedBackend) SuggestGasPrice(ctx context.Context) (*big.Int, error) {
|
|
||||||
b.mu.Lock()
|
|
||||||
defer b.mu.Unlock()
|
|
||||||
|
|
||||||
if b.pendingBlock.Header().BaseFee != nil {
|
|
||||||
return b.pendingBlock.Header().BaseFee, nil
|
|
||||||
}
|
|
||||||
return big.NewInt(1), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// SuggestGasTipCap implements ContractTransactor.SuggestGasTipCap. Since the simulated
|
|
||||||
// chain doesn't have miners, we just return a gas tip of 1 for any call.
|
|
||||||
func (b *SimulatedBackend) SuggestGasTipCap(ctx context.Context) (*big.Int, error) {
|
|
||||||
return big.NewInt(1), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// EstimateGas executes the requested code against the currently pending block/state and
|
|
||||||
// returns the used amount of gas.
|
|
||||||
func (b *SimulatedBackend) EstimateGas(ctx context.Context, call ethereum.CallMsg) (uint64, error) {
|
|
||||||
b.mu.Lock()
|
|
||||||
defer b.mu.Unlock()
|
|
||||||
|
|
||||||
// Determine the lowest and highest possible gas limits to binary search in between
|
|
||||||
var (
|
|
||||||
lo uint64 = params.TxGas - 1
|
|
||||||
hi uint64
|
|
||||||
cap uint64
|
|
||||||
)
|
|
||||||
if call.Gas >= params.TxGas {
|
|
||||||
hi = call.Gas
|
|
||||||
} else {
|
|
||||||
hi = b.pendingBlock.GasLimit()
|
|
||||||
}
|
|
||||||
// Normalize the max fee per gas the call is willing to spend.
|
|
||||||
var feeCap *big.Int
|
|
||||||
if call.GasPrice != nil && (call.GasFeeCap != nil || call.GasTipCap != nil) {
|
|
||||||
return 0, errors.New("both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified")
|
|
||||||
} else if call.GasPrice != nil {
|
|
||||||
feeCap = call.GasPrice
|
|
||||||
} else if call.GasFeeCap != nil {
|
|
||||||
feeCap = call.GasFeeCap
|
|
||||||
} else {
|
|
||||||
feeCap = common.Big0
|
|
||||||
}
|
|
||||||
// Recap the highest gas allowance with account's balance.
|
|
||||||
if feeCap.BitLen() != 0 {
|
|
||||||
balance := b.pendingState.GetBalance(call.From) // from can't be nil
|
|
||||||
available := new(big.Int).Set(balance)
|
|
||||||
if call.Value != nil {
|
|
||||||
if call.Value.Cmp(available) >= 0 {
|
|
||||||
return 0, core.ErrInsufficientFundsForTransfer
|
|
||||||
}
|
|
||||||
available.Sub(available, call.Value)
|
|
||||||
}
|
|
||||||
allowance := new(big.Int).Div(available, feeCap)
|
|
||||||
if allowance.IsUint64() && hi > allowance.Uint64() {
|
|
||||||
transfer := call.Value
|
|
||||||
if transfer == nil {
|
|
||||||
transfer = new(big.Int)
|
|
||||||
}
|
|
||||||
log.Warn("Gas estimation capped by limited funds", "original", hi, "balance", balance,
|
|
||||||
"sent", transfer, "feecap", feeCap, "fundable", allowance)
|
|
||||||
hi = allowance.Uint64()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cap = hi
|
|
||||||
|
|
||||||
// Create a helper to check if a gas allowance results in an executable transaction
|
|
||||||
executable := func(gas uint64) (bool, *core.ExecutionResult, error) {
|
|
||||||
call.Gas = gas
|
|
||||||
|
|
||||||
snapshot := b.pendingState.Snapshot()
|
|
||||||
res, err := b.callContract(ctx, call, b.pendingBlock.Header(), b.pendingState)
|
|
||||||
b.pendingState.RevertToSnapshot(snapshot)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
if errors.Is(err, core.ErrIntrinsicGas) {
|
|
||||||
return true, nil, nil // Special case, raise gas limit
|
|
||||||
}
|
|
||||||
return true, nil, err // Bail out
|
|
||||||
}
|
|
||||||
return res.Failed(), res, nil
|
|
||||||
}
|
|
||||||
// Execute the binary search and hone in on an executable gas limit
|
|
||||||
for lo+1 < hi {
|
|
||||||
mid := (hi + lo) / 2
|
|
||||||
failed, _, err := executable(mid)
|
|
||||||
|
|
||||||
// If the error is not nil(consensus error), it means the provided message
|
|
||||||
// call or transaction will never be accepted no matter how much gas it is
|
|
||||||
// assigned. Return the error directly, don't struggle any more
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
if failed {
|
|
||||||
lo = mid
|
|
||||||
} else {
|
|
||||||
hi = mid
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Reject the transaction as invalid if it still fails at the highest allowance
|
|
||||||
if hi == cap {
|
|
||||||
failed, result, err := executable(hi)
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
if failed {
|
|
||||||
if result != nil && result.Err != vm.ErrOutOfGas {
|
|
||||||
if len(result.Revert()) > 0 {
|
|
||||||
return 0, newRevertError(result)
|
|
||||||
}
|
|
||||||
return 0, result.Err
|
|
||||||
}
|
|
||||||
// Otherwise, the specified gas cap is too low
|
|
||||||
return 0, fmt.Errorf("gas required exceeds allowance (%d)", cap)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return hi, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// callContract implements common code between normal and pending contract calls.
|
|
||||||
// state is modified during execution, make sure to copy it if necessary.
|
|
||||||
func (b *SimulatedBackend) callContract(ctx context.Context, call ethereum.CallMsg, header *types.Header, stateDB *state.StateDB) (*core.ExecutionResult, error) {
|
|
||||||
// Gas prices post 1559 need to be initialized
|
|
||||||
if call.GasPrice != nil && (call.GasFeeCap != nil || call.GasTipCap != nil) {
|
|
||||||
return nil, errors.New("both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified")
|
|
||||||
}
|
|
||||||
head := b.blockchain.CurrentHeader()
|
|
||||||
if !b.blockchain.Config().IsLondon(head.Number) {
|
|
||||||
// If there's no basefee, then it must be a non-1559 execution
|
|
||||||
if call.GasPrice == nil {
|
|
||||||
call.GasPrice = new(big.Int)
|
|
||||||
}
|
|
||||||
call.GasFeeCap, call.GasTipCap = call.GasPrice, call.GasPrice
|
|
||||||
} else {
|
|
||||||
// A basefee is provided, necessitating 1559-type execution
|
|
||||||
if call.GasPrice != nil {
|
|
||||||
// User specified the legacy gas field, convert to 1559 gas typing
|
|
||||||
call.GasFeeCap, call.GasTipCap = call.GasPrice, call.GasPrice
|
|
||||||
} else {
|
|
||||||
// User specified 1559 gas fields (or none), use those
|
|
||||||
if call.GasFeeCap == nil {
|
|
||||||
call.GasFeeCap = new(big.Int)
|
|
||||||
}
|
|
||||||
if call.GasTipCap == nil {
|
|
||||||
call.GasTipCap = new(big.Int)
|
|
||||||
}
|
|
||||||
// Backfill the legacy gasPrice for EVM execution, unless we're all zeroes
|
|
||||||
call.GasPrice = new(big.Int)
|
|
||||||
if call.GasFeeCap.BitLen() > 0 || call.GasTipCap.BitLen() > 0 {
|
|
||||||
call.GasPrice = math.BigMin(new(big.Int).Add(call.GasTipCap, head.BaseFee), call.GasFeeCap)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Ensure message is initialized properly.
|
|
||||||
if call.Gas == 0 {
|
|
||||||
call.Gas = 50000000
|
|
||||||
}
|
|
||||||
if call.Value == nil {
|
|
||||||
call.Value = new(big.Int)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set infinite balance to the fake caller account.
|
|
||||||
from := stateDB.GetOrNewStateObject(call.From)
|
|
||||||
from.SetBalance(math.MaxBig256)
|
|
||||||
|
|
||||||
// Execute the call.
|
|
||||||
msg := &core.Message{
|
|
||||||
From: call.From,
|
|
||||||
To: call.To,
|
|
||||||
Value: call.Value,
|
|
||||||
GasLimit: call.Gas,
|
|
||||||
GasPrice: call.GasPrice,
|
|
||||||
GasFeeCap: call.GasFeeCap,
|
|
||||||
GasTipCap: call.GasTipCap,
|
|
||||||
Data: call.Data,
|
|
||||||
AccessList: call.AccessList,
|
|
||||||
SkipAccountChecks: true,
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a new environment which holds all relevant information
|
|
||||||
// about the transaction and calling mechanisms.
|
|
||||||
txContext := core.NewEVMTxContext(msg)
|
|
||||||
evmContext := core.NewEVMBlockContext(header, b.blockchain, nil)
|
|
||||||
vmEnv := vm.NewEVM(evmContext, txContext, stateDB, b.config, vm.Config{NoBaseFee: true})
|
|
||||||
gasPool := new(core.GasPool).AddGas(math.MaxUint64)
|
|
||||||
|
|
||||||
return core.ApplyMessage(vmEnv, msg, gasPool)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SendTransaction updates the pending block to include the given transaction.
|
|
||||||
func (b *SimulatedBackend) SendTransaction(ctx context.Context, tx *types.Transaction) error {
|
|
||||||
b.mu.Lock()
|
|
||||||
defer b.mu.Unlock()
|
|
||||||
|
|
||||||
// Get the last block
|
|
||||||
block, err := b.blockByHash(ctx, b.pendingBlock.ParentHash())
|
|
||||||
if err != nil {
|
|
||||||
return errors.New("could not fetch parent")
|
|
||||||
}
|
|
||||||
// Check transaction validity
|
|
||||||
signer := types.MakeSigner(b.blockchain.Config(), block.Number(), block.Time())
|
|
||||||
sender, err := types.Sender(signer, tx)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("invalid transaction: %v", err)
|
|
||||||
}
|
|
||||||
nonce := b.pendingState.GetNonce(sender)
|
|
||||||
if tx.Nonce() != nonce {
|
|
||||||
return fmt.Errorf("invalid transaction nonce: got %d, want %d", tx.Nonce(), nonce)
|
|
||||||
}
|
|
||||||
// Include tx in chain
|
|
||||||
blocks, receipts := core.GenerateChain(b.config, block, ethash.NewFaker(), b.database, 1, func(number int, block *core.BlockGen) {
|
|
||||||
for _, tx := range b.pendingBlock.Transactions() {
|
|
||||||
block.AddTxWithChain(b.blockchain, tx)
|
|
||||||
}
|
|
||||||
block.AddTxWithChain(b.blockchain, tx)
|
|
||||||
})
|
|
||||||
stateDB, _ := b.blockchain.State()
|
|
||||||
|
|
||||||
b.pendingBlock = blocks[0]
|
|
||||||
b.pendingState, _ = state.New(b.pendingBlock.Root(), stateDB.Database(), nil)
|
|
||||||
b.pendingReceipts = receipts[0]
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// SendTransaction updates the pending block to include the given transaction.
|
|
||||||
func (b *SimulatedBackend) SendTransactionConditional(ctx context.Context, tx *types.Transaction, opts ethapi.TransactionOpts) error {
|
|
||||||
state, err := b.blockchain.State()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := opts.Check(b.pendingBlock.NumberU64(), b.pendingBlock.Time(), state); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return b.SendTransaction(ctx, tx)
|
|
||||||
}
|
|
||||||
|
|
||||||
// FilterLogs executes a log filter operation, blocking during execution and
|
|
||||||
// returning all the results in one batch.
|
|
||||||
//
|
|
||||||
// TODO(karalabe): Deprecate when the subscription one can return past data too.
|
|
||||||
func (b *SimulatedBackend) FilterLogs(ctx context.Context, query ethereum.FilterQuery) ([]types.Log, error) {
|
|
||||||
var filter *filters.Filter
|
|
||||||
if query.BlockHash != nil {
|
|
||||||
// Block filter requested, construct a single-shot filter
|
|
||||||
filter = b.filterSystem.NewBlockFilter(*query.BlockHash, query.Addresses, query.Topics)
|
|
||||||
} else {
|
|
||||||
// Initialize unset filter boundaries to run from genesis to chain head
|
|
||||||
from := int64(0)
|
|
||||||
if query.FromBlock != nil {
|
|
||||||
from = query.FromBlock.Int64()
|
|
||||||
}
|
|
||||||
to := int64(-1)
|
|
||||||
if query.ToBlock != nil {
|
|
||||||
to = query.ToBlock.Int64()
|
|
||||||
}
|
|
||||||
// Construct the range filter
|
|
||||||
filter = b.filterSystem.NewRangeFilter(from, to, query.Addresses, query.Topics, false)
|
|
||||||
}
|
|
||||||
// Run the filter and return all the logs
|
|
||||||
logs, err := filter.Logs(ctx)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
res := make([]types.Log, len(logs))
|
|
||||||
for i, nLog := range logs {
|
|
||||||
res[i] = *nLog
|
|
||||||
}
|
|
||||||
return res, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// SubscribeFilterLogs creates a background log filtering operation, returning a
|
|
||||||
// subscription immediately, which can be used to stream the found events.
|
|
||||||
func (b *SimulatedBackend) SubscribeFilterLogs(ctx context.Context, query ethereum.FilterQuery, ch chan<- types.Log) (ethereum.Subscription, error) {
|
|
||||||
// Subscribe to contract events
|
|
||||||
sink := make(chan []*types.Log)
|
|
||||||
|
|
||||||
sub, err := b.events.SubscribeLogs(query, sink)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
// Since we're getting logs in batches, we need to flatten them into a plain stream
|
|
||||||
return event.NewSubscription(func(quit <-chan struct{}) error {
|
|
||||||
defer sub.Unsubscribe()
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case logs := <-sink:
|
|
||||||
for _, nlog := range logs {
|
|
||||||
select {
|
|
||||||
case ch <- *nlog:
|
|
||||||
case err := <-sub.Err():
|
|
||||||
return err
|
|
||||||
case <-quit:
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case err := <-sub.Err():
|
|
||||||
return err
|
|
||||||
case <-quit:
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// SubscribeNewHead returns an event subscription for a new header.
|
|
||||||
func (b *SimulatedBackend) SubscribeNewHead(ctx context.Context, ch chan<- *types.Header) (ethereum.Subscription, error) {
|
|
||||||
// subscribe to a new head
|
|
||||||
sink := make(chan *types.Header)
|
|
||||||
sub := b.events.SubscribeNewHeads(sink)
|
|
||||||
|
|
||||||
return event.NewSubscription(func(quit <-chan struct{}) error {
|
|
||||||
defer sub.Unsubscribe()
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case head := <-sink:
|
|
||||||
select {
|
|
||||||
case ch <- head:
|
|
||||||
case err := <-sub.Err():
|
|
||||||
return err
|
|
||||||
case <-quit:
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
case err := <-sub.Err():
|
|
||||||
return err
|
|
||||||
case <-quit:
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// AdjustTime adds a time shift to the simulated clock.
|
|
||||||
// It can only be called on empty blocks.
|
|
||||||
func (b *SimulatedBackend) AdjustTime(adjustment time.Duration) error {
|
|
||||||
b.mu.Lock()
|
|
||||||
defer b.mu.Unlock()
|
|
||||||
|
|
||||||
if len(b.pendingBlock.Transactions()) != 0 {
|
|
||||||
return errors.New("Could not adjust time on non-empty block")
|
|
||||||
}
|
|
||||||
// Get the last block
|
|
||||||
block := b.blockchain.GetBlockByHash(b.pendingBlock.ParentHash())
|
|
||||||
if block == nil {
|
|
||||||
return errors.New("could not find parent")
|
|
||||||
}
|
|
||||||
|
|
||||||
blocks, _ := core.GenerateChain(b.config, block, ethash.NewFaker(), b.database, 1, func(number int, block *core.BlockGen) {
|
|
||||||
block.OffsetTime(int64(adjustment.Seconds()))
|
|
||||||
})
|
|
||||||
stateDB, _ := b.blockchain.State()
|
|
||||||
|
|
||||||
b.pendingBlock = blocks[0]
|
|
||||||
b.pendingState, _ = state.New(b.pendingBlock.Root(), stateDB.Database(), nil)
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Blockchain returns the underlying blockchain.
|
|
||||||
func (b *SimulatedBackend) Blockchain() *core.BlockChain {
|
|
||||||
return b.blockchain
|
|
||||||
}
|
|
||||||
|
|
||||||
// filterBackend implements filters.Backend to support filtering for logs without
|
|
||||||
// taking bloom-bits acceleration structures into account.
|
|
||||||
type filterBackend struct {
|
|
||||||
db ethdb.Database
|
|
||||||
bc *core.BlockChain
|
|
||||||
backend *SimulatedBackend
|
|
||||||
}
|
|
||||||
|
|
||||||
func (fb *filterBackend) ChainDb() ethdb.Database { return fb.db }
|
|
||||||
|
|
||||||
func (fb *filterBackend) EventMux() *event.TypeMux { panic("not supported") }
|
|
||||||
|
|
||||||
func (fb *filterBackend) HeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Header, error) {
|
|
||||||
switch number {
|
|
||||||
case rpc.PendingBlockNumber:
|
|
||||||
if block := fb.backend.pendingBlock; block != nil {
|
|
||||||
return block.Header(), nil
|
|
||||||
}
|
|
||||||
return nil, nil
|
|
||||||
case rpc.LatestBlockNumber:
|
|
||||||
return fb.bc.CurrentHeader(), nil
|
|
||||||
case rpc.FinalizedBlockNumber:
|
|
||||||
return fb.bc.CurrentFinalBlock(), nil
|
|
||||||
case rpc.SafeBlockNumber:
|
|
||||||
return fb.bc.CurrentSafeBlock(), nil
|
|
||||||
default:
|
|
||||||
return fb.bc.GetHeaderByNumber(uint64(number.Int64())), nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (fb *filterBackend) HeaderByHash(ctx context.Context, hash common.Hash) (*types.Header, error) {
|
|
||||||
return fb.bc.GetHeaderByHash(hash), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (fb *filterBackend) GetBody(ctx context.Context, hash common.Hash, number rpc.BlockNumber) (*types.Body, error) {
|
|
||||||
if body := fb.bc.GetBody(hash); body != nil {
|
|
||||||
return body, nil
|
|
||||||
}
|
|
||||||
return nil, errors.New("block body not found")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (fb *filterBackend) PendingBlockAndReceipts() (*types.Block, types.Receipts) {
|
|
||||||
return fb.backend.pendingBlock, fb.backend.pendingReceipts
|
|
||||||
}
|
|
||||||
|
|
||||||
func (fb *filterBackend) GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error) {
|
|
||||||
number := rawdb.ReadHeaderNumber(fb.db, hash)
|
|
||||||
if number == nil {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
header := rawdb.ReadHeader(fb.db, hash, *number)
|
|
||||||
if header == nil {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
return rawdb.ReadReceipts(fb.db, hash, *number, header.Time, fb.bc.Config()), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (fb *filterBackend) GetLogs(ctx context.Context, hash common.Hash, number uint64) ([][]*types.Log, error) {
|
|
||||||
logs := rawdb.ReadLogs(fb.db, hash, number, fb.bc.Config())
|
|
||||||
return logs, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (fb *filterBackend) SubscribeNewTxsEvent(ch chan<- core.NewTxsEvent) event.Subscription {
|
|
||||||
return nullSubscription()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (fb *filterBackend) SubscribeNewVoteEvent(ch chan<- core.NewVoteEvent) event.Subscription {
|
|
||||||
return nullSubscription()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (fb *filterBackend) SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription {
|
|
||||||
return fb.bc.SubscribeChainEvent(ch)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (fb *filterBackend) SubscribeFinalizedHeaderEvent(ch chan<- core.FinalizedHeaderEvent) event.Subscription {
|
|
||||||
return fb.bc.SubscribeFinalizedHeaderEvent(ch)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (fb *filterBackend) SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription {
|
|
||||||
return fb.bc.SubscribeRemovedLogsEvent(ch)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (fb *filterBackend) SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscription {
|
|
||||||
return fb.bc.SubscribeLogsEvent(ch)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (fb *filterBackend) SubscribePendingLogsEvent(ch chan<- []*types.Log) event.Subscription {
|
|
||||||
return nullSubscription()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (fb *filterBackend) BloomStatus() (uint64, uint64) { return 4096, 0 }
|
|
||||||
|
|
||||||
func (fb *filterBackend) ServiceFilter(ctx context.Context, ms *bloombits.MatcherSession) {
|
|
||||||
panic("not supported")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (fb *filterBackend) ChainConfig() *params.ChainConfig {
|
|
||||||
panic("not supported")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (fb *filterBackend) CurrentHeader() *types.Header {
|
|
||||||
panic("not supported")
|
|
||||||
}
|
|
||||||
|
|
||||||
func nullSubscription() event.Subscription {
|
|
||||||
return event.NewSubscription(func(quit <-chan struct{}) error {
|
|
||||||
<-quit
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -48,6 +48,7 @@ type CallOpts struct {
|
|||||||
Pending bool // Whether to operate on the pending state or the last known one
|
Pending bool // Whether to operate on the pending state or the last known one
|
||||||
From common.Address // Optional the sender address, otherwise the first account is used
|
From common.Address // Optional the sender address, otherwise the first account is used
|
||||||
BlockNumber *big.Int // Optional the block number on which the call should be performed
|
BlockNumber *big.Int // Optional the block number on which the call should be performed
|
||||||
|
BlockHash common.Hash // Optional the block hash on which the call should be performed
|
||||||
Context context.Context // Network context to support cancellation and timeouts (nil = no timeout)
|
Context context.Context // Network context to support cancellation and timeouts (nil = no timeout)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -189,6 +190,23 @@ func (c *BoundContract) Call(opts *CallOpts, results *[]interface{}, method stri
|
|||||||
return ErrNoCode
|
return ErrNoCode
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if opts.BlockHash != (common.Hash{}) {
|
||||||
|
bh, ok := c.caller.(BlockHashContractCaller)
|
||||||
|
if !ok {
|
||||||
|
return ErrNoBlockHashState
|
||||||
|
}
|
||||||
|
output, err = bh.CallContractAtHash(ctx, msg, opts.BlockHash)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if len(output) == 0 {
|
||||||
|
// Make sure we have a contract to operate on, and bail out otherwise.
|
||||||
|
if code, err = bh.CodeAtHash(ctx, c.address, opts.BlockHash); err != nil {
|
||||||
|
return err
|
||||||
|
} else if len(code) == 0 {
|
||||||
|
return ErrNoCode
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
output, err = c.caller.CallContract(ctx, msg, opts.BlockNumber)
|
output, err = c.caller.CallContract(ctx, msg, opts.BlockNumber)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -220,7 +238,7 @@ func (c *BoundContract) Transact(opts *TransactOpts, method string, params ...in
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
// todo(rjl493456442) check the method is payable or not,
|
// todo(rjl493456442) check whether the method is payable or not,
|
||||||
// reject invalid transaction at the first place
|
// reject invalid transaction at the first place
|
||||||
return c.transact(opts, &c.address, input)
|
return c.transact(opts, &c.address, input)
|
||||||
}
|
}
|
||||||
@@ -228,7 +246,7 @@ func (c *BoundContract) Transact(opts *TransactOpts, method string, params ...in
|
|||||||
// RawTransact initiates a transaction with the given raw calldata as the input.
|
// RawTransact initiates a transaction with the given raw calldata as the input.
|
||||||
// It's usually used to initiate transactions for invoking **Fallback** function.
|
// It's usually used to initiate transactions for invoking **Fallback** function.
|
||||||
func (c *BoundContract) RawTransact(opts *TransactOpts, calldata []byte) (*types.Transaction, error) {
|
func (c *BoundContract) RawTransact(opts *TransactOpts, calldata []byte) (*types.Transaction, error) {
|
||||||
// todo(rjl493456442) check the method is payable or not,
|
// todo(rjl493456442) check whether the method is payable or not,
|
||||||
// reject invalid transaction at the first place
|
// reject invalid transaction at the first place
|
||||||
return c.transact(opts, &c.address, calldata)
|
return c.transact(opts, &c.address, calldata)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -119,7 +119,28 @@ func (mc *mockPendingCaller) PendingCallContract(ctx context.Context, call ether
|
|||||||
return mc.pendingCallContractBytes, mc.pendingCallContractErr
|
return mc.pendingCallContractBytes, mc.pendingCallContractErr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type mockBlockHashCaller struct {
|
||||||
|
*mockCaller
|
||||||
|
codeAtHashBytes []byte
|
||||||
|
codeAtHashErr error
|
||||||
|
codeAtHashCalled bool
|
||||||
|
callContractAtHashCalled bool
|
||||||
|
callContractAtHashBytes []byte
|
||||||
|
callContractAtHashErr error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mc *mockBlockHashCaller) CodeAtHash(ctx context.Context, contract common.Address, hash common.Hash) ([]byte, error) {
|
||||||
|
mc.codeAtHashCalled = true
|
||||||
|
return mc.codeAtHashBytes, mc.codeAtHashErr
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mc *mockBlockHashCaller) CallContractAtHash(ctx context.Context, call ethereum.CallMsg, hash common.Hash) ([]byte, error) {
|
||||||
|
mc.callContractAtHashCalled = true
|
||||||
|
return mc.callContractAtHashBytes, mc.callContractAtHashErr
|
||||||
|
}
|
||||||
|
|
||||||
func TestPassingBlockNumber(t *testing.T) {
|
func TestPassingBlockNumber(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
mc := &mockPendingCaller{
|
mc := &mockPendingCaller{
|
||||||
mockCaller: &mockCaller{
|
mockCaller: &mockCaller{
|
||||||
codeAtBytes: []byte{1, 2, 3},
|
codeAtBytes: []byte{1, 2, 3},
|
||||||
@@ -171,6 +192,7 @@ func TestPassingBlockNumber(t *testing.T) {
|
|||||||
const hexData = "0x000000000000000000000000376c47978271565f56deb45495afa69e59c16ab200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000158"
|
const hexData = "0x000000000000000000000000376c47978271565f56deb45495afa69e59c16ab200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000158"
|
||||||
|
|
||||||
func TestUnpackIndexedStringTyLogIntoMap(t *testing.T) {
|
func TestUnpackIndexedStringTyLogIntoMap(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
hash := crypto.Keccak256Hash([]byte("testName"))
|
hash := crypto.Keccak256Hash([]byte("testName"))
|
||||||
topics := []common.Hash{
|
topics := []common.Hash{
|
||||||
crypto.Keccak256Hash([]byte("received(string,address,uint256,bytes)")),
|
crypto.Keccak256Hash([]byte("received(string,address,uint256,bytes)")),
|
||||||
@@ -192,6 +214,7 @@ func TestUnpackIndexedStringTyLogIntoMap(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestUnpackAnonymousLogIntoMap(t *testing.T) {
|
func TestUnpackAnonymousLogIntoMap(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
mockLog := newMockLog(nil, common.HexToHash("0x0"))
|
mockLog := newMockLog(nil, common.HexToHash("0x0"))
|
||||||
|
|
||||||
abiString := `[{"anonymous":false,"inputs":[{"indexed":false,"name":"amount","type":"uint256"}],"name":"received","type":"event"}]`
|
abiString := `[{"anonymous":false,"inputs":[{"indexed":false,"name":"amount","type":"uint256"}],"name":"received","type":"event"}]`
|
||||||
@@ -209,6 +232,7 @@ func TestUnpackAnonymousLogIntoMap(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestUnpackIndexedSliceTyLogIntoMap(t *testing.T) {
|
func TestUnpackIndexedSliceTyLogIntoMap(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
sliceBytes, err := rlp.EncodeToBytes([]string{"name1", "name2", "name3", "name4"})
|
sliceBytes, err := rlp.EncodeToBytes([]string{"name1", "name2", "name3", "name4"})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@@ -234,6 +258,7 @@ func TestUnpackIndexedSliceTyLogIntoMap(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestUnpackIndexedArrayTyLogIntoMap(t *testing.T) {
|
func TestUnpackIndexedArrayTyLogIntoMap(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
arrBytes, err := rlp.EncodeToBytes([2]common.Address{common.HexToAddress("0x0"), common.HexToAddress("0x376c47978271565f56DEB45495afa69E59c16Ab2")})
|
arrBytes, err := rlp.EncodeToBytes([2]common.Address{common.HexToAddress("0x0"), common.HexToAddress("0x376c47978271565f56DEB45495afa69E59c16Ab2")})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@@ -259,6 +284,7 @@ func TestUnpackIndexedArrayTyLogIntoMap(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestUnpackIndexedFuncTyLogIntoMap(t *testing.T) {
|
func TestUnpackIndexedFuncTyLogIntoMap(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
mockAddress := common.HexToAddress("0x376c47978271565f56DEB45495afa69E59c16Ab2")
|
mockAddress := common.HexToAddress("0x376c47978271565f56DEB45495afa69E59c16Ab2")
|
||||||
addrBytes := mockAddress.Bytes()
|
addrBytes := mockAddress.Bytes()
|
||||||
hash := crypto.Keccak256Hash([]byte("mockFunction(address,uint)"))
|
hash := crypto.Keccak256Hash([]byte("mockFunction(address,uint)"))
|
||||||
@@ -285,6 +311,7 @@ func TestUnpackIndexedFuncTyLogIntoMap(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestUnpackIndexedBytesTyLogIntoMap(t *testing.T) {
|
func TestUnpackIndexedBytesTyLogIntoMap(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
bytes := []byte{1, 2, 3, 4, 5}
|
bytes := []byte{1, 2, 3, 4, 5}
|
||||||
hash := crypto.Keccak256Hash(bytes)
|
hash := crypto.Keccak256Hash(bytes)
|
||||||
topics := []common.Hash{
|
topics := []common.Hash{
|
||||||
@@ -307,6 +334,7 @@ func TestUnpackIndexedBytesTyLogIntoMap(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestTransactGasFee(t *testing.T) {
|
func TestTransactGasFee(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
assert := assert.New(t)
|
assert := assert.New(t)
|
||||||
|
|
||||||
// GasTipCap and GasFeeCap
|
// GasTipCap and GasFeeCap
|
||||||
@@ -382,6 +410,7 @@ func newMockLog(topics []common.Hash, txHash common.Hash) types.Log {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestCall(t *testing.T) {
|
func TestCall(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
var method, methodWithArg = "something", "somethingArrrrg"
|
var method, methodWithArg = "something", "somethingArrrrg"
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name, method string
|
name, method string
|
||||||
@@ -405,6 +434,15 @@ func TestCall(t *testing.T) {
|
|||||||
Pending: true,
|
Pending: true,
|
||||||
},
|
},
|
||||||
method: method,
|
method: method,
|
||||||
|
}, {
|
||||||
|
name: "ok hash",
|
||||||
|
mc: &mockBlockHashCaller{
|
||||||
|
codeAtHashBytes: []byte{0},
|
||||||
|
},
|
||||||
|
opts: &bind.CallOpts{
|
||||||
|
BlockHash: common.Hash{0xaa},
|
||||||
|
},
|
||||||
|
method: method,
|
||||||
}, {
|
}, {
|
||||||
name: "pack error, no method",
|
name: "pack error, no method",
|
||||||
mc: new(mockCaller),
|
mc: new(mockCaller),
|
||||||
@@ -418,6 +456,14 @@ func TestCall(t *testing.T) {
|
|||||||
},
|
},
|
||||||
method: method,
|
method: method,
|
||||||
wantErrExact: bind.ErrNoPendingState,
|
wantErrExact: bind.ErrNoPendingState,
|
||||||
|
}, {
|
||||||
|
name: "interface error, blockHash but not a BlockHashContractCaller",
|
||||||
|
mc: new(mockCaller),
|
||||||
|
opts: &bind.CallOpts{
|
||||||
|
BlockHash: common.Hash{0xaa},
|
||||||
|
},
|
||||||
|
method: method,
|
||||||
|
wantErrExact: bind.ErrNoBlockHashState,
|
||||||
}, {
|
}, {
|
||||||
name: "pending call canceled",
|
name: "pending call canceled",
|
||||||
mc: &mockPendingCaller{
|
mc: &mockPendingCaller{
|
||||||
@@ -465,6 +511,34 @@ func TestCall(t *testing.T) {
|
|||||||
mc: new(mockCaller),
|
mc: new(mockCaller),
|
||||||
method: method,
|
method: method,
|
||||||
wantErrExact: bind.ErrNoCode,
|
wantErrExact: bind.ErrNoCode,
|
||||||
|
}, {
|
||||||
|
name: "call contract at hash error",
|
||||||
|
mc: &mockBlockHashCaller{
|
||||||
|
callContractAtHashErr: context.DeadlineExceeded,
|
||||||
|
},
|
||||||
|
opts: &bind.CallOpts{
|
||||||
|
BlockHash: common.Hash{0xaa},
|
||||||
|
},
|
||||||
|
method: method,
|
||||||
|
wantErrExact: context.DeadlineExceeded,
|
||||||
|
}, {
|
||||||
|
name: "code at error",
|
||||||
|
mc: &mockBlockHashCaller{
|
||||||
|
codeAtHashErr: errors.New(""),
|
||||||
|
},
|
||||||
|
opts: &bind.CallOpts{
|
||||||
|
BlockHash: common.Hash{0xaa},
|
||||||
|
},
|
||||||
|
method: method,
|
||||||
|
wantErr: true,
|
||||||
|
}, {
|
||||||
|
name: "no code at hash",
|
||||||
|
mc: new(mockBlockHashCaller),
|
||||||
|
opts: &bind.CallOpts{
|
||||||
|
BlockHash: common.Hash{0xaa},
|
||||||
|
},
|
||||||
|
method: method,
|
||||||
|
wantErrExact: bind.ErrNoCode,
|
||||||
}, {
|
}, {
|
||||||
name: "unpack error missing arg",
|
name: "unpack error missing arg",
|
||||||
mc: &mockCaller{
|
mc: &mockCaller{
|
||||||
@@ -512,6 +586,7 @@ func TestCall(t *testing.T) {
|
|||||||
|
|
||||||
// TestCrashers contains some strings which previously caused the abi codec to crash.
|
// TestCrashers contains some strings which previously caused the abi codec to crash.
|
||||||
func TestCrashers(t *testing.T) {
|
func TestCrashers(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
abi.JSON(strings.NewReader(`[{"inputs":[{"type":"tuple[]","components":[{"type":"bool","name":"_1"}]}]}]`))
|
abi.JSON(strings.NewReader(`[{"inputs":[{"type":"tuple[]","components":[{"type":"bool","name":"_1"}]}]}]`))
|
||||||
abi.JSON(strings.NewReader(`[{"inputs":[{"type":"tuple[]","components":[{"type":"bool","name":"&"}]}]}]`))
|
abi.JSON(strings.NewReader(`[{"inputs":[{"type":"tuple[]","components":[{"type":"bool","name":"&"}]}]}]`))
|
||||||
abi.JSON(strings.NewReader(`[{"inputs":[{"type":"tuple[]","components":[{"type":"bool","name":"----"}]}]}]`))
|
abi.JSON(strings.NewReader(`[{"inputs":[{"type":"tuple[]","components":[{"type":"bool","name":"----"}]}]}]`))
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ func isKeyWord(arg string) bool {
|
|||||||
|
|
||||||
// Bind generates a Go wrapper around a contract ABI. This wrapper isn't meant
|
// Bind generates a Go wrapper around a contract ABI. This wrapper isn't meant
|
||||||
// to be used as is in client code, but rather as an intermediate struct which
|
// to be used as is in client code, but rather as an intermediate struct which
|
||||||
// enforces compile time type safety and naming convention opposed to having to
|
// enforces compile time type safety and naming convention as opposed to having to
|
||||||
// manually maintain hard coded strings that break on runtime.
|
// manually maintain hard coded strings that break on runtime.
|
||||||
func Bind(types []string, abis []string, bytecodes []string, fsigs []map[string]string, pkg string, lang Lang, libs map[string]string, aliases map[string]string) (string, error) {
|
func Bind(types []string, abis []string, bytecodes []string, fsigs []map[string]string, pkg string, lang Lang, libs map[string]string, aliases map[string]string) (string, error) {
|
||||||
var (
|
var (
|
||||||
@@ -363,7 +363,7 @@ func bindTopicTypeGo(kind abi.Type, structs map[string]*tmplStruct) string {
|
|||||||
// parameters that are not value types i.e. arrays and structs are not
|
// parameters that are not value types i.e. arrays and structs are not
|
||||||
// stored directly but instead a keccak256-hash of an encoding is stored.
|
// stored directly but instead a keccak256-hash of an encoding is stored.
|
||||||
//
|
//
|
||||||
// We only convert stringS and bytes to hash, still need to deal with
|
// We only convert strings and bytes to hash, still need to deal with
|
||||||
// array(both fixed-size and dynamic-size) and struct.
|
// array(both fixed-size and dynamic-size) and struct.
|
||||||
if bound == "string" || bound == "[]byte" {
|
if bound == "string" || bound == "[]byte" {
|
||||||
bound = "common.Hash"
|
bound = "common.Hash"
|
||||||
|
|||||||
@@ -289,7 +289,7 @@ var bindTests = []struct {
|
|||||||
|
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
`,
|
`,
|
||||||
`
|
`
|
||||||
@@ -297,7 +297,7 @@ var bindTests = []struct {
|
|||||||
key, _ := crypto.GenerateKey()
|
key, _ := crypto.GenerateKey()
|
||||||
auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
||||||
|
|
||||||
sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000000000)}}, 10000000)
|
sim := backends.NewSimulatedBackend(types.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000000000)}}, 10000000)
|
||||||
defer sim.Close()
|
defer sim.Close()
|
||||||
|
|
||||||
// Deploy an interaction tester contract and call a transaction on it
|
// Deploy an interaction tester contract and call a transaction on it
|
||||||
@@ -305,6 +305,7 @@ var bindTests = []struct {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to deploy interactor contract: %v", err)
|
t.Fatalf("Failed to deploy interactor contract: %v", err)
|
||||||
}
|
}
|
||||||
|
sim.Commit()
|
||||||
if _, err := interactor.Transact(auth, "Transact string"); err != nil {
|
if _, err := interactor.Transact(auth, "Transact string"); err != nil {
|
||||||
t.Fatalf("Failed to transact with interactor contract: %v", err)
|
t.Fatalf("Failed to transact with interactor contract: %v", err)
|
||||||
}
|
}
|
||||||
@@ -344,7 +345,7 @@ var bindTests = []struct {
|
|||||||
|
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
`,
|
`,
|
||||||
`
|
`
|
||||||
@@ -352,7 +353,7 @@ var bindTests = []struct {
|
|||||||
key, _ := crypto.GenerateKey()
|
key, _ := crypto.GenerateKey()
|
||||||
auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
||||||
|
|
||||||
sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000000000)}}, 10000000)
|
sim := backends.NewSimulatedBackend(types.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000000000)}}, 10000000)
|
||||||
defer sim.Close()
|
defer sim.Close()
|
||||||
|
|
||||||
// Deploy a tuple tester contract and execute a structured call on it
|
// Deploy a tuple tester contract and execute a structured call on it
|
||||||
@@ -390,7 +391,7 @@ var bindTests = []struct {
|
|||||||
|
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
`,
|
`,
|
||||||
`
|
`
|
||||||
@@ -398,7 +399,7 @@ var bindTests = []struct {
|
|||||||
key, _ := crypto.GenerateKey()
|
key, _ := crypto.GenerateKey()
|
||||||
auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
||||||
|
|
||||||
sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000000000)}}, 10000000)
|
sim := backends.NewSimulatedBackend(types.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000000000)}}, 10000000)
|
||||||
defer sim.Close()
|
defer sim.Close()
|
||||||
|
|
||||||
// Deploy a tuple tester contract and execute a structured call on it
|
// Deploy a tuple tester contract and execute a structured call on it
|
||||||
@@ -448,7 +449,7 @@ var bindTests = []struct {
|
|||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
`,
|
`,
|
||||||
`
|
`
|
||||||
@@ -456,7 +457,7 @@ var bindTests = []struct {
|
|||||||
key, _ := crypto.GenerateKey()
|
key, _ := crypto.GenerateKey()
|
||||||
auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
||||||
|
|
||||||
sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000000000)}}, 10000000)
|
sim := backends.NewSimulatedBackend(types.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000000000)}}, 10000000)
|
||||||
defer sim.Close()
|
defer sim.Close()
|
||||||
|
|
||||||
// Deploy a slice tester contract and execute a n array call on it
|
// Deploy a slice tester contract and execute a n array call on it
|
||||||
@@ -496,7 +497,7 @@ var bindTests = []struct {
|
|||||||
|
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
`,
|
`,
|
||||||
`
|
`
|
||||||
@@ -504,7 +505,7 @@ var bindTests = []struct {
|
|||||||
key, _ := crypto.GenerateKey()
|
key, _ := crypto.GenerateKey()
|
||||||
auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
||||||
|
|
||||||
sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000000000)}}, 10000000)
|
sim := backends.NewSimulatedBackend(types.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000000000)}}, 10000000)
|
||||||
defer sim.Close()
|
defer sim.Close()
|
||||||
|
|
||||||
// Deploy a default method invoker contract and execute its default method
|
// Deploy a default method invoker contract and execute its default method
|
||||||
@@ -512,6 +513,7 @@ var bindTests = []struct {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to deploy defaulter contract: %v", err)
|
t.Fatalf("Failed to deploy defaulter contract: %v", err)
|
||||||
}
|
}
|
||||||
|
sim.Commit()
|
||||||
if _, err := (&DefaulterRaw{defaulter}).Transfer(auth); err != nil {
|
if _, err := (&DefaulterRaw{defaulter}).Transfer(auth); err != nil {
|
||||||
t.Fatalf("Failed to invoke default method: %v", err)
|
t.Fatalf("Failed to invoke default method: %v", err)
|
||||||
}
|
}
|
||||||
@@ -562,7 +564,7 @@ var bindTests = []struct {
|
|||||||
|
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
`,
|
`,
|
||||||
`
|
`
|
||||||
@@ -570,7 +572,7 @@ var bindTests = []struct {
|
|||||||
key, _ := crypto.GenerateKey()
|
key, _ := crypto.GenerateKey()
|
||||||
auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
||||||
|
|
||||||
sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000000000)}}, 10000000)
|
sim := backends.NewSimulatedBackend(types.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000000000)}}, 10000000)
|
||||||
defer sim.Close()
|
defer sim.Close()
|
||||||
|
|
||||||
// Deploy a structs method invoker contract and execute its default method
|
// Deploy a structs method invoker contract and execute its default method
|
||||||
@@ -608,12 +610,12 @@ var bindTests = []struct {
|
|||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
`,
|
`,
|
||||||
`
|
`
|
||||||
// Create a simulator and wrap a non-deployed contract
|
// Create a simulator and wrap a non-deployed contract
|
||||||
|
|
||||||
sim := backends.NewSimulatedBackend(core.GenesisAlloc{}, uint64(10000000000))
|
sim := backends.NewSimulatedBackend(types.GenesisAlloc{}, uint64(10000000000))
|
||||||
defer sim.Close()
|
defer sim.Close()
|
||||||
|
|
||||||
nonexistent, err := NewNonExistent(common.Address{}, sim)
|
nonexistent, err := NewNonExistent(common.Address{}, sim)
|
||||||
@@ -647,12 +649,12 @@ var bindTests = []struct {
|
|||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
`,
|
`,
|
||||||
`
|
`
|
||||||
// Create a simulator and wrap a non-deployed contract
|
// Create a simulator and wrap a non-deployed contract
|
||||||
|
|
||||||
sim := backends.NewSimulatedBackend(core.GenesisAlloc{}, uint64(10000000000))
|
sim := backends.NewSimulatedBackend(types.GenesisAlloc{}, uint64(10000000000))
|
||||||
defer sim.Close()
|
defer sim.Close()
|
||||||
|
|
||||||
nonexistent, err := NewNonExistentStruct(common.Address{}, sim)
|
nonexistent, err := NewNonExistentStruct(common.Address{}, sim)
|
||||||
@@ -694,7 +696,7 @@ var bindTests = []struct {
|
|||||||
|
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
`,
|
`,
|
||||||
`
|
`
|
||||||
@@ -702,7 +704,7 @@ var bindTests = []struct {
|
|||||||
key, _ := crypto.GenerateKey()
|
key, _ := crypto.GenerateKey()
|
||||||
auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
||||||
|
|
||||||
sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000000000)}}, 10000000)
|
sim := backends.NewSimulatedBackend(types.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000000000)}}, 10000000)
|
||||||
defer sim.Close()
|
defer sim.Close()
|
||||||
|
|
||||||
// Deploy a funky gas pattern contract
|
// Deploy a funky gas pattern contract
|
||||||
@@ -744,7 +746,7 @@ var bindTests = []struct {
|
|||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
`,
|
`,
|
||||||
`
|
`
|
||||||
@@ -752,7 +754,7 @@ var bindTests = []struct {
|
|||||||
key, _ := crypto.GenerateKey()
|
key, _ := crypto.GenerateKey()
|
||||||
auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
||||||
|
|
||||||
sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000000000)}}, 10000000)
|
sim := backends.NewSimulatedBackend(types.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000000000)}}, 10000000)
|
||||||
defer sim.Close()
|
defer sim.Close()
|
||||||
|
|
||||||
// Deploy a sender tester contract and execute a structured call on it
|
// Deploy a sender tester contract and execute a structured call on it
|
||||||
@@ -819,7 +821,7 @@ var bindTests = []struct {
|
|||||||
|
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
`,
|
`,
|
||||||
`
|
`
|
||||||
@@ -827,7 +829,7 @@ var bindTests = []struct {
|
|||||||
key, _ := crypto.GenerateKey()
|
key, _ := crypto.GenerateKey()
|
||||||
auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
||||||
|
|
||||||
sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000000000)}}, 10000000)
|
sim := backends.NewSimulatedBackend(types.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000000000)}}, 10000000)
|
||||||
defer sim.Close()
|
defer sim.Close()
|
||||||
|
|
||||||
// Deploy a underscorer tester contract and execute a structured call on it
|
// Deploy a underscorer tester contract and execute a structured call on it
|
||||||
@@ -913,7 +915,7 @@ var bindTests = []struct {
|
|||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
`,
|
`,
|
||||||
`
|
`
|
||||||
@@ -921,7 +923,7 @@ var bindTests = []struct {
|
|||||||
key, _ := crypto.GenerateKey()
|
key, _ := crypto.GenerateKey()
|
||||||
auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
||||||
|
|
||||||
sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000000000)}}, 10000000)
|
sim := backends.NewSimulatedBackend(types.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000000000)}}, 10000000)
|
||||||
defer sim.Close()
|
defer sim.Close()
|
||||||
|
|
||||||
// Deploy an eventer contract
|
// Deploy an eventer contract
|
||||||
@@ -1103,7 +1105,7 @@ var bindTests = []struct {
|
|||||||
|
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
`,
|
`,
|
||||||
`
|
`
|
||||||
@@ -1111,7 +1113,7 @@ var bindTests = []struct {
|
|||||||
key, _ := crypto.GenerateKey()
|
key, _ := crypto.GenerateKey()
|
||||||
auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
||||||
|
|
||||||
sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000000000)}}, 10000000)
|
sim := backends.NewSimulatedBackend(types.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000000000)}}, 10000000)
|
||||||
defer sim.Close()
|
defer sim.Close()
|
||||||
|
|
||||||
//deploy the test contract
|
//deploy the test contract
|
||||||
@@ -1238,7 +1240,7 @@ var bindTests = []struct {
|
|||||||
|
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
`,
|
`,
|
||||||
|
|
||||||
@@ -1246,7 +1248,7 @@ var bindTests = []struct {
|
|||||||
key, _ := crypto.GenerateKey()
|
key, _ := crypto.GenerateKey()
|
||||||
auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
||||||
|
|
||||||
sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000000000)}}, 10000000)
|
sim := backends.NewSimulatedBackend(types.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000000000)}}, 10000000)
|
||||||
defer sim.Close()
|
defer sim.Close()
|
||||||
|
|
||||||
_, _, contract, err := DeployTuple(auth, sim)
|
_, _, contract, err := DeployTuple(auth, sim)
|
||||||
@@ -1380,7 +1382,7 @@ var bindTests = []struct {
|
|||||||
|
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
`,
|
`,
|
||||||
`
|
`
|
||||||
@@ -1388,7 +1390,7 @@ var bindTests = []struct {
|
|||||||
key, _ := crypto.GenerateKey()
|
key, _ := crypto.GenerateKey()
|
||||||
auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
||||||
|
|
||||||
sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000000000)}}, 10000000)
|
sim := backends.NewSimulatedBackend(types.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000000000)}}, 10000000)
|
||||||
defer sim.Close()
|
defer sim.Close()
|
||||||
|
|
||||||
//deploy the test contract
|
//deploy the test contract
|
||||||
@@ -1446,14 +1448,14 @@ var bindTests = []struct {
|
|||||||
|
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
`,
|
`,
|
||||||
`
|
`
|
||||||
// Initialize test accounts
|
// Initialize test accounts
|
||||||
key, _ := crypto.GenerateKey()
|
key, _ := crypto.GenerateKey()
|
||||||
auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
||||||
sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000000000)}}, 10000000)
|
sim := backends.NewSimulatedBackend(types.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000000000)}}, 10000000)
|
||||||
defer sim.Close()
|
defer sim.Close()
|
||||||
|
|
||||||
// deploy the test contract
|
// deploy the test contract
|
||||||
@@ -1535,7 +1537,7 @@ var bindTests = []struct {
|
|||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
`,
|
`,
|
||||||
`
|
`
|
||||||
// Initialize test accounts
|
// Initialize test accounts
|
||||||
@@ -1543,7 +1545,7 @@ var bindTests = []struct {
|
|||||||
addr := crypto.PubkeyToAddress(key.PublicKey)
|
addr := crypto.PubkeyToAddress(key.PublicKey)
|
||||||
|
|
||||||
// Deploy registrar contract
|
// Deploy registrar contract
|
||||||
sim := backends.NewSimulatedBackend(core.GenesisAlloc{addr: {Balance: big.NewInt(10000000000000000)}}, 10000000)
|
sim := backends.NewSimulatedBackend(types.GenesisAlloc{addr: {Balance: big.NewInt(10000000000000000)}}, 10000000)
|
||||||
defer sim.Close()
|
defer sim.Close()
|
||||||
|
|
||||||
transactOpts, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
transactOpts, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
||||||
@@ -1598,14 +1600,14 @@ var bindTests = []struct {
|
|||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
`,
|
`,
|
||||||
`
|
`
|
||||||
key, _ := crypto.GenerateKey()
|
key, _ := crypto.GenerateKey()
|
||||||
addr := crypto.PubkeyToAddress(key.PublicKey)
|
addr := crypto.PubkeyToAddress(key.PublicKey)
|
||||||
|
|
||||||
// Deploy registrar contract
|
// Deploy registrar contract
|
||||||
sim := backends.NewSimulatedBackend(core.GenesisAlloc{addr: {Balance: big.NewInt(10000000000000000)}}, 10000000)
|
sim := backends.NewSimulatedBackend(types.GenesisAlloc{addr: {Balance: big.NewInt(10000000000000000)}}, 10000000)
|
||||||
defer sim.Close()
|
defer sim.Close()
|
||||||
|
|
||||||
transactOpts, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
transactOpts, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
||||||
@@ -1659,7 +1661,7 @@ var bindTests = []struct {
|
|||||||
|
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
`,
|
`,
|
||||||
`
|
`
|
||||||
@@ -1667,7 +1669,7 @@ var bindTests = []struct {
|
|||||||
key, _ := crypto.GenerateKey()
|
key, _ := crypto.GenerateKey()
|
||||||
auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
||||||
|
|
||||||
sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000000000)}}, 10000000)
|
sim := backends.NewSimulatedBackend(types.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000000000)}}, 10000000)
|
||||||
defer sim.Close()
|
defer sim.Close()
|
||||||
|
|
||||||
// Deploy a tester contract and execute a structured call on it
|
// Deploy a tester contract and execute a structured call on it
|
||||||
@@ -1677,7 +1679,7 @@ var bindTests = []struct {
|
|||||||
}
|
}
|
||||||
sim.Commit()
|
sim.Commit()
|
||||||
|
|
||||||
// This test the existence of the free retreiver call for view and pure functions
|
// This test the existence of the free retriever call for view and pure functions
|
||||||
if num, err := pav.PureFunc(nil); err != nil {
|
if num, err := pav.PureFunc(nil); err != nil {
|
||||||
t.Fatalf("Failed to call anonymous field retriever: %v", err)
|
t.Fatalf("Failed to call anonymous field retriever: %v", err)
|
||||||
} else if num.Cmp(big.NewInt(42)) != 0 {
|
} else if num.Cmp(big.NewInt(42)) != 0 {
|
||||||
@@ -1720,14 +1722,14 @@ var bindTests = []struct {
|
|||||||
|
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
`,
|
`,
|
||||||
`
|
`
|
||||||
key, _ := crypto.GenerateKey()
|
key, _ := crypto.GenerateKey()
|
||||||
addr := crypto.PubkeyToAddress(key.PublicKey)
|
addr := crypto.PubkeyToAddress(key.PublicKey)
|
||||||
|
|
||||||
sim := backends.NewSimulatedBackend(core.GenesisAlloc{addr: {Balance: big.NewInt(10000000000000000)}}, 1000000)
|
sim := backends.NewSimulatedBackend(types.GenesisAlloc{addr: {Balance: big.NewInt(10000000000000000)}}, 1000000)
|
||||||
defer sim.Close()
|
defer sim.Close()
|
||||||
|
|
||||||
opts, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
opts, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
||||||
@@ -1808,7 +1810,7 @@ var bindTests = []struct {
|
|||||||
|
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/eth/ethconfig"
|
"github.com/ethereum/go-ethereum/eth/ethconfig"
|
||||||
`,
|
`,
|
||||||
@@ -1816,7 +1818,7 @@ var bindTests = []struct {
|
|||||||
var (
|
var (
|
||||||
key, _ = crypto.GenerateKey()
|
key, _ = crypto.GenerateKey()
|
||||||
user, _ = bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
user, _ = bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
||||||
sim = backends.NewSimulatedBackend(core.GenesisAlloc{user.From: {Balance: big.NewInt(1000000000000000000)}}, ethconfig.Defaults.Miner.GasCeil)
|
sim = backends.NewSimulatedBackend(types.GenesisAlloc{user.From: {Balance: big.NewInt(1000000000000000000)}}, ethconfig.Defaults.Miner.GasCeil)
|
||||||
)
|
)
|
||||||
defer sim.Close()
|
defer sim.Close()
|
||||||
|
|
||||||
@@ -1874,11 +1876,12 @@ var bindTests = []struct {
|
|||||||
[]string{"0x6080604052348015600f57600080fd5b5060998061001e6000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c8063726c638214602d575b600080fd5b60336035565b005b60405163024876cd60e61b815260016004820152600260248201526003604482015260640160405180910390fdfea264697066735822122093f786a1bc60216540cd999fbb4a6109e0fef20abcff6e9107fb2817ca968f3c64736f6c63430008070033"},
|
[]string{"0x6080604052348015600f57600080fd5b5060998061001e6000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c8063726c638214602d575b600080fd5b60336035565b005b60405163024876cd60e61b815260016004820152600260248201526003604482015260640160405180910390fdfea264697066735822122093f786a1bc60216540cd999fbb4a6109e0fef20abcff6e9107fb2817ca968f3c64736f6c63430008070033"},
|
||||||
[]string{`[{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"MyError","type":"error"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"MyError1","type":"error"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"MyError2","type":"error"},{"inputs":[{"internalType":"uint256","name":"a","type":"uint256"},{"internalType":"uint256","name":"b","type":"uint256"},{"internalType":"uint256","name":"c","type":"uint256"}],"name":"MyError3","type":"error"},{"inputs":[],"name":"Error","outputs":[],"stateMutability":"pure","type":"function"}]`},
|
[]string{`[{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"MyError","type":"error"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"MyError1","type":"error"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"MyError2","type":"error"},{"inputs":[{"internalType":"uint256","name":"a","type":"uint256"},{"internalType":"uint256","name":"b","type":"uint256"},{"internalType":"uint256","name":"c","type":"uint256"}],"name":"MyError3","type":"error"},{"inputs":[],"name":"Error","outputs":[],"stateMutability":"pure","type":"function"}]`},
|
||||||
`
|
`
|
||||||
|
"context"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/eth/ethconfig"
|
"github.com/ethereum/go-ethereum/eth/ethconfig"
|
||||||
`,
|
`,
|
||||||
@@ -1886,7 +1889,7 @@ var bindTests = []struct {
|
|||||||
var (
|
var (
|
||||||
key, _ = crypto.GenerateKey()
|
key, _ = crypto.GenerateKey()
|
||||||
user, _ = bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
user, _ = bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
||||||
sim = backends.NewSimulatedBackend(core.GenesisAlloc{user.From: {Balance: big.NewInt(1000000000000000000)}}, ethconfig.Defaults.Miner.GasCeil)
|
sim = backends.NewSimulatedBackend(types.GenesisAlloc{user.From: {Balance: big.NewInt(1000000000000000000)}}, ethconfig.Defaults.Miner.GasCeil)
|
||||||
)
|
)
|
||||||
defer sim.Close()
|
defer sim.Close()
|
||||||
|
|
||||||
@@ -1895,7 +1898,7 @@ var bindTests = []struct {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
sim.Commit()
|
sim.Commit()
|
||||||
_, err = bind.WaitDeployed(nil, sim, tx)
|
_, err = bind.WaitDeployed(context.Background(), sim, tx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
@@ -1926,11 +1929,12 @@ var bindTests = []struct {
|
|||||||
bytecode: []string{`0x608060405234801561001057600080fd5b506040516101c43803806101c48339818101604052810190610032919061014a565b50610177565b6000604051905090565b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6100958261004c565b810181811067ffffffffffffffff821117156100b4576100b361005d565b5b80604052505050565b60006100c7610038565b90506100d3828261008c565b919050565b6000819050919050565b6100eb816100d8565b81146100f657600080fd5b50565b600081519050610108816100e2565b92915050565b60006020828403121561012457610123610047565b5b61012e60206100bd565b9050600061013e848285016100f9565b60008301525092915050565b6000602082840312156101605761015f610042565b5b600061016e8482850161010e565b91505092915050565b603f806101856000396000f3fe6080604052600080fdfea2646970667358221220cdffa667affecefac5561f65f4a4ba914204a8d4eb859d8cd426fb306e5c12a364736f6c634300080a0033`},
|
bytecode: []string{`0x608060405234801561001057600080fd5b506040516101c43803806101c48339818101604052810190610032919061014a565b50610177565b6000604051905090565b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6100958261004c565b810181811067ffffffffffffffff821117156100b4576100b361005d565b5b80604052505050565b60006100c7610038565b90506100d3828261008c565b919050565b6000819050919050565b6100eb816100d8565b81146100f657600080fd5b50565b600081519050610108816100e2565b92915050565b60006020828403121561012457610123610047565b5b61012e60206100bd565b9050600061013e848285016100f9565b60008301525092915050565b6000602082840312156101605761015f610042565b5b600061016e8482850161010e565b91505092915050565b603f806101856000396000f3fe6080604052600080fdfea2646970667358221220cdffa667affecefac5561f65f4a4ba914204a8d4eb859d8cd426fb306e5c12a364736f6c634300080a0033`},
|
||||||
abi: []string{`[{"inputs":[{"components":[{"internalType":"uint256","name":"field","type":"uint256"}],"internalType":"struct ConstructorWithStructParam.StructType","name":"st","type":"tuple"}],"stateMutability":"nonpayable","type":"constructor"}]`},
|
abi: []string{`[{"inputs":[{"components":[{"internalType":"uint256","name":"field","type":"uint256"}],"internalType":"struct ConstructorWithStructParam.StructType","name":"st","type":"tuple"}],"stateMutability":"nonpayable","type":"constructor"}]`},
|
||||||
imports: `
|
imports: `
|
||||||
|
"context"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/eth/ethconfig"
|
"github.com/ethereum/go-ethereum/eth/ethconfig"
|
||||||
`,
|
`,
|
||||||
@@ -1938,7 +1942,7 @@ var bindTests = []struct {
|
|||||||
var (
|
var (
|
||||||
key, _ = crypto.GenerateKey()
|
key, _ = crypto.GenerateKey()
|
||||||
user, _ = bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
user, _ = bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
||||||
sim = backends.NewSimulatedBackend(core.GenesisAlloc{user.From: {Balance: big.NewInt(1000000000000000000)}}, ethconfig.Defaults.Miner.GasCeil)
|
sim = backends.NewSimulatedBackend(types.GenesisAlloc{user.From: {Balance: big.NewInt(1000000000000000000)}}, ethconfig.Defaults.Miner.GasCeil)
|
||||||
)
|
)
|
||||||
defer sim.Close()
|
defer sim.Close()
|
||||||
|
|
||||||
@@ -1948,7 +1952,7 @@ var bindTests = []struct {
|
|||||||
}
|
}
|
||||||
sim.Commit()
|
sim.Commit()
|
||||||
|
|
||||||
if _, err = bind.WaitDeployed(nil, sim, tx); err != nil {
|
if _, err = bind.WaitDeployed(context.Background(), sim, tx); err != nil {
|
||||||
t.Logf("Deployment tx: %+v", tx)
|
t.Logf("Deployment tx: %+v", tx)
|
||||||
t.Errorf("bind.WaitDeployed(nil, %T, <deployment tx>) got err %v; want nil err", sim, err)
|
t.Errorf("bind.WaitDeployed(nil, %T, <deployment tx>) got err %v; want nil err", sim, err)
|
||||||
}
|
}
|
||||||
@@ -1974,11 +1978,12 @@ var bindTests = []struct {
|
|||||||
bytecode: []string{"0x608060405234801561001057600080fd5b5061042b806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c8063c2bb515f1461003b578063cce7b04814610059575b600080fd5b610043610075565b60405161005091906101af565b60405180910390f35b610073600480360381019061006e91906103ac565b6100b5565b005b61007d6100b8565b604051806040016040528060405180602001604052806000815250815260200160405180602001604052806000815250815250905090565b50565b604051806040016040528060608152602001606081525090565b600081519050919050565b600082825260208201905092915050565b60005b8381101561010c5780820151818401526020810190506100f1565b8381111561011b576000848401525b50505050565b6000601f19601f8301169050919050565b600061013d826100d2565b61014781856100dd565b93506101578185602086016100ee565b61016081610121565b840191505092915050565b600060408301600083015184820360008601526101888282610132565b915050602083015184820360208601526101a28282610132565b9150508091505092915050565b600060208201905081810360008301526101c9818461016b565b905092915050565b6000604051905090565b600080fd5b600080fd5b600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b61022282610121565b810181811067ffffffffffffffff82111715610241576102406101ea565b5b80604052505050565b60006102546101d1565b90506102608282610219565b919050565b600080fd5b600080fd5b600080fd5b600067ffffffffffffffff82111561028f5761028e6101ea565b5b61029882610121565b9050602081019050919050565b82818337600083830152505050565b60006102c76102c284610274565b61024a565b9050828152602081018484840111156102e3576102e261026f565b5b6102ee8482856102a5565b509392505050565b600082601f83011261030b5761030a61026a565b5b813561031b8482602086016102b4565b91505092915050565b60006040828403121561033a576103396101e5565b5b610344604061024a565b9050600082013567ffffffffffffffff81111561036457610363610265565b5b610370848285016102f6565b600083015250602082013567ffffffffffffffff81111561039457610393610265565b5b6103a0848285016102f6565b60208301525092915050565b6000602082840312156103c2576103c16101db565b5b600082013567ffffffffffffffff8111156103e0576103df6101e0565b5b6103ec84828501610324565b9150509291505056fea264697066735822122033bca1606af9b6aeba1673f98c52003cec19338539fb44b86690ce82c51483b564736f6c634300080e0033"},
|
bytecode: []string{"0x608060405234801561001057600080fd5b5061042b806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c8063c2bb515f1461003b578063cce7b04814610059575b600080fd5b610043610075565b60405161005091906101af565b60405180910390f35b610073600480360381019061006e91906103ac565b6100b5565b005b61007d6100b8565b604051806040016040528060405180602001604052806000815250815260200160405180602001604052806000815250815250905090565b50565b604051806040016040528060608152602001606081525090565b600081519050919050565b600082825260208201905092915050565b60005b8381101561010c5780820151818401526020810190506100f1565b8381111561011b576000848401525b50505050565b6000601f19601f8301169050919050565b600061013d826100d2565b61014781856100dd565b93506101578185602086016100ee565b61016081610121565b840191505092915050565b600060408301600083015184820360008601526101888282610132565b915050602083015184820360208601526101a28282610132565b9150508091505092915050565b600060208201905081810360008301526101c9818461016b565b905092915050565b6000604051905090565b600080fd5b600080fd5b600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b61022282610121565b810181811067ffffffffffffffff82111715610241576102406101ea565b5b80604052505050565b60006102546101d1565b90506102608282610219565b919050565b600080fd5b600080fd5b600080fd5b600067ffffffffffffffff82111561028f5761028e6101ea565b5b61029882610121565b9050602081019050919050565b82818337600083830152505050565b60006102c76102c284610274565b61024a565b9050828152602081018484840111156102e3576102e261026f565b5b6102ee8482856102a5565b509392505050565b600082601f83011261030b5761030a61026a565b5b813561031b8482602086016102b4565b91505092915050565b60006040828403121561033a576103396101e5565b5b610344604061024a565b9050600082013567ffffffffffffffff81111561036457610363610265565b5b610370848285016102f6565b600083015250602082013567ffffffffffffffff81111561039457610393610265565b5b6103a0848285016102f6565b60208301525092915050565b6000602082840312156103c2576103c16101db565b5b600082013567ffffffffffffffff8111156103e0576103df6101e0565b5b6103ec84828501610324565b9150509291505056fea264697066735822122033bca1606af9b6aeba1673f98c52003cec19338539fb44b86690ce82c51483b564736f6c634300080e0033"},
|
||||||
abi: []string{`[ { "anonymous": false, "inputs": [ { "indexed": false, "internalType": "int256", "name": "msg", "type": "int256" }, { "indexed": false, "internalType": "int256", "name": "_msg", "type": "int256" } ], "name": "log", "type": "event" }, { "inputs": [ { "components": [ { "internalType": "bytes", "name": "data", "type": "bytes" }, { "internalType": "bytes", "name": "_data", "type": "bytes" } ], "internalType": "struct oracle.request", "name": "req", "type": "tuple" } ], "name": "addRequest", "outputs": [], "stateMutability": "pure", "type": "function" }, { "inputs": [], "name": "getRequest", "outputs": [ { "components": [ { "internalType": "bytes", "name": "data", "type": "bytes" }, { "internalType": "bytes", "name": "_data", "type": "bytes" } ], "internalType": "struct oracle.request", "name": "", "type": "tuple" } ], "stateMutability": "pure", "type": "function" } ]`},
|
abi: []string{`[ { "anonymous": false, "inputs": [ { "indexed": false, "internalType": "int256", "name": "msg", "type": "int256" }, { "indexed": false, "internalType": "int256", "name": "_msg", "type": "int256" } ], "name": "log", "type": "event" }, { "inputs": [ { "components": [ { "internalType": "bytes", "name": "data", "type": "bytes" }, { "internalType": "bytes", "name": "_data", "type": "bytes" } ], "internalType": "struct oracle.request", "name": "req", "type": "tuple" } ], "name": "addRequest", "outputs": [], "stateMutability": "pure", "type": "function" }, { "inputs": [], "name": "getRequest", "outputs": [ { "components": [ { "internalType": "bytes", "name": "data", "type": "bytes" }, { "internalType": "bytes", "name": "_data", "type": "bytes" } ], "internalType": "struct oracle.request", "name": "", "type": "tuple" } ], "stateMutability": "pure", "type": "function" } ]`},
|
||||||
imports: `
|
imports: `
|
||||||
|
"context"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/eth/ethconfig"
|
"github.com/ethereum/go-ethereum/eth/ethconfig"
|
||||||
`,
|
`,
|
||||||
@@ -1986,7 +1991,7 @@ var bindTests = []struct {
|
|||||||
var (
|
var (
|
||||||
key, _ = crypto.GenerateKey()
|
key, _ = crypto.GenerateKey()
|
||||||
user, _ = bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
user, _ = bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
||||||
sim = backends.NewSimulatedBackend(core.GenesisAlloc{user.From: {Balance: big.NewInt(1000000000000000000)}}, ethconfig.Defaults.Miner.GasCeil)
|
sim = backends.NewSimulatedBackend(types.GenesisAlloc{user.From: {Balance: big.NewInt(1000000000000000000)}}, ethconfig.Defaults.Miner.GasCeil)
|
||||||
)
|
)
|
||||||
defer sim.Close()
|
defer sim.Close()
|
||||||
|
|
||||||
@@ -1996,7 +2001,7 @@ var bindTests = []struct {
|
|||||||
}
|
}
|
||||||
sim.Commit()
|
sim.Commit()
|
||||||
|
|
||||||
if _, err = bind.WaitDeployed(nil, sim, tx); err != nil {
|
if _, err = bind.WaitDeployed(context.Background(), sim, tx); err != nil {
|
||||||
t.Logf("Deployment tx: %+v", tx)
|
t.Logf("Deployment tx: %+v", tx)
|
||||||
t.Errorf("bind.WaitDeployed(nil, %T, <deployment tx>) got err %v; want nil err", sim, err)
|
t.Errorf("bind.WaitDeployed(nil, %T, <deployment tx>) got err %v; want nil err", sim, err)
|
||||||
}
|
}
|
||||||
@@ -2014,11 +2019,12 @@ var bindTests = []struct {
|
|||||||
bytecode: []string{"0x608060405234801561001057600080fd5b5060dc8061001f6000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c8063527a119f14602d575b600080fd5b60436004803603810190603f9190605b565b6045565b005b50565b6000813590506055816092565b92915050565b600060208284031215606e57606d608d565b5b6000607a848285016048565b91505092915050565b6000819050919050565b600080fd5b6099816083565b811460a357600080fd5b5056fea2646970667358221220d4f4525e2615516394055d369fb17df41c359e5e962734f27fd683ea81fd9db164736f6c63430008070033"},
|
bytecode: []string{"0x608060405234801561001057600080fd5b5060dc8061001f6000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c8063527a119f14602d575b600080fd5b60436004803603810190603f9190605b565b6045565b005b50565b6000813590506055816092565b92915050565b600060208284031215606e57606d608d565b5b6000607a848285016048565b91505092915050565b6000819050919050565b600080fd5b6099816083565b811460a357600080fd5b5056fea2646970667358221220d4f4525e2615516394055d369fb17df41c359e5e962734f27fd683ea81fd9db164736f6c63430008070033"},
|
||||||
abi: []string{`[{"inputs":[{"internalType":"uint256","name":"range","type":"uint256"}],"name":"functionWithKeywordParameter","outputs":[],"stateMutability":"pure","type":"function"}]`},
|
abi: []string{`[{"inputs":[{"internalType":"uint256","name":"range","type":"uint256"}],"name":"functionWithKeywordParameter","outputs":[],"stateMutability":"pure","type":"function"}]`},
|
||||||
imports: `
|
imports: `
|
||||||
|
"context"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/eth/ethconfig"
|
"github.com/ethereum/go-ethereum/eth/ethconfig"
|
||||||
`,
|
`,
|
||||||
@@ -2026,7 +2032,7 @@ var bindTests = []struct {
|
|||||||
var (
|
var (
|
||||||
key, _ = crypto.GenerateKey()
|
key, _ = crypto.GenerateKey()
|
||||||
user, _ = bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
user, _ = bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
|
||||||
sim = backends.NewSimulatedBackend(core.GenesisAlloc{user.From: {Balance: big.NewInt(1000000000000000000)}}, ethconfig.Defaults.Miner.GasCeil)
|
sim = backends.NewSimulatedBackend(types.GenesisAlloc{user.From: {Balance: big.NewInt(1000000000000000000)}}, ethconfig.Defaults.Miner.GasCeil)
|
||||||
)
|
)
|
||||||
_, tx, _, err := DeployRangeKeyword(user, sim)
|
_, tx, _, err := DeployRangeKeyword(user, sim)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -2034,7 +2040,7 @@ var bindTests = []struct {
|
|||||||
}
|
}
|
||||||
sim.Commit()
|
sim.Commit()
|
||||||
|
|
||||||
if _, err = bind.WaitDeployed(nil, sim, tx); err != nil {
|
if _, err = bind.WaitDeployed(context.Background(), sim, tx); err != nil {
|
||||||
t.Errorf("error deploying the contract: %v", err)
|
t.Errorf("error deploying the contract: %v", err)
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
@@ -2067,6 +2073,7 @@ var bindTests = []struct {
|
|||||||
// Tests that packages generated by the binder can be successfully compiled and
|
// Tests that packages generated by the binder can be successfully compiled and
|
||||||
// the requested tester run against it.
|
// the requested tester run against it.
|
||||||
func TestGolangBindings(t *testing.T) {
|
func TestGolangBindings(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
// Skip the test if no Go command can be found
|
// Skip the test if no Go command can be found
|
||||||
gocmd := runtime.GOROOT() + "/bin/go"
|
gocmd := runtime.GOROOT() + "/bin/go"
|
||||||
if !common.FileExist(gocmd) {
|
if !common.FileExist(gocmd) {
|
||||||
@@ -2127,7 +2134,7 @@ func TestGolangBindings(t *testing.T) {
|
|||||||
t.Fatalf("failed to replace binding test dependency to current source tree: %v\n%s", err, out)
|
t.Fatalf("failed to replace binding test dependency to current source tree: %v\n%s", err, out)
|
||||||
}
|
}
|
||||||
|
|
||||||
replacer = exec.Command(gocmd, "mod", "edit", "-x", "-require", "github.com/tendermint/tendermint@v0.0.0", "-replace", "github.com/tendermint/tendermint=github.com/bnb-chain/tendermint@v0.31.15") // Repo root
|
replacer = exec.Command(gocmd, "mod", "edit", "-x", "-require", "github.com/tendermint/tendermint@v0.0.0", "-replace", "github.com/tendermint/tendermint=github.com/bnb-chain/tendermint@v0.31.16") // Repo root
|
||||||
replacer.Dir = pkg
|
replacer.Dir = pkg
|
||||||
if out, err := replacer.CombinedOutput(); err != nil {
|
if out, err := replacer.CombinedOutput(); err != nil {
|
||||||
t.Fatalf("failed to replace tendermint dependency to bnb-chain source: %v\n%s", err, out)
|
t.Fatalf("failed to replace tendermint dependency to bnb-chain source: %v\n%s", err, out)
|
||||||
@@ -2145,7 +2152,7 @@ func TestGolangBindings(t *testing.T) {
|
|||||||
t.Fatalf("failed to replace cometbft dependency to bnb-chain source: %v\n%s", err, out)
|
t.Fatalf("failed to replace cometbft dependency to bnb-chain source: %v\n%s", err, out)
|
||||||
}
|
}
|
||||||
|
|
||||||
tidier := exec.Command(gocmd, "mod", "tidy", "-compat=1.20")
|
tidier := exec.Command(gocmd, "mod", "tidy", "-compat=1.21")
|
||||||
tidier.Dir = pkg
|
tidier.Dir = pkg
|
||||||
if out, err := tidier.CombinedOutput(); err != nil {
|
if out, err := tidier.CombinedOutput(); err != nil {
|
||||||
t.Fatalf("failed to tidy Go module file: %v\n%s", err, out)
|
t.Fatalf("failed to tidy Go module file: %v\n%s", err, out)
|
||||||
|
|||||||
@@ -24,11 +24,11 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
|
"github.com/ethereum/go-ethereum/ethclient/simulated"
|
||||||
|
"github.com/ethereum/go-ethereum/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
var testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
var testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
||||||
@@ -53,21 +53,21 @@ var waitDeployedTests = map[string]struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestWaitDeployed(t *testing.T) {
|
func TestWaitDeployed(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
for name, test := range waitDeployedTests {
|
for name, test := range waitDeployedTests {
|
||||||
backend := backends.NewSimulatedBackend(
|
backend := simulated.NewBackend(
|
||||||
core.GenesisAlloc{
|
types.GenesisAlloc{
|
||||||
crypto.PubkeyToAddress(testKey.PublicKey): {Balance: big.NewInt(10000000000000000)},
|
crypto.PubkeyToAddress(testKey.PublicKey): {Balance: big.NewInt(10000000000000000)},
|
||||||
},
|
},
|
||||||
10000000,
|
|
||||||
)
|
)
|
||||||
defer backend.Close()
|
defer backend.Close()
|
||||||
|
|
||||||
// Create the transaction
|
// Create the transaction
|
||||||
head, _ := backend.HeaderByNumber(context.Background(), nil) // Should be child's, good enough
|
head, _ := backend.Client().HeaderByNumber(context.Background(), nil) // Should be child's, good enough
|
||||||
gasPrice := new(big.Int).Add(head.BaseFee, big.NewInt(1))
|
gasPrice := new(big.Int).Add(head.BaseFee, big.NewInt(params.GWei))
|
||||||
|
|
||||||
tx := types.NewContractCreation(0, big.NewInt(0), test.gas, gasPrice, common.FromHex(test.code))
|
tx := types.NewContractCreation(0, big.NewInt(0), test.gas, gasPrice, common.FromHex(test.code))
|
||||||
tx, _ = types.SignTx(tx, types.HomesteadSigner{}, testKey)
|
tx, _ = types.SignTx(tx, types.LatestSignerForChainID(big.NewInt(1337)), testKey)
|
||||||
|
|
||||||
// Wait for it to get mined in the background.
|
// Wait for it to get mined in the background.
|
||||||
var (
|
var (
|
||||||
@@ -77,12 +77,12 @@ func TestWaitDeployed(t *testing.T) {
|
|||||||
ctx = context.Background()
|
ctx = context.Background()
|
||||||
)
|
)
|
||||||
go func() {
|
go func() {
|
||||||
address, err = bind.WaitDeployed(ctx, backend, tx)
|
address, err = bind.WaitDeployed(ctx, backend.Client(), tx)
|
||||||
close(mined)
|
close(mined)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// Send and mine the transaction.
|
// Send and mine the transaction.
|
||||||
backend.SendTransaction(ctx, tx)
|
backend.Client().SendTransaction(ctx, tx)
|
||||||
backend.Commit()
|
backend.Commit()
|
||||||
|
|
||||||
select {
|
select {
|
||||||
@@ -100,41 +100,40 @@ func TestWaitDeployed(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestWaitDeployedCornerCases(t *testing.T) {
|
func TestWaitDeployedCornerCases(t *testing.T) {
|
||||||
backend := backends.NewSimulatedBackend(
|
backend := simulated.NewBackend(
|
||||||
core.GenesisAlloc{
|
types.GenesisAlloc{
|
||||||
crypto.PubkeyToAddress(testKey.PublicKey): {Balance: big.NewInt(10000000000000000)},
|
crypto.PubkeyToAddress(testKey.PublicKey): {Balance: big.NewInt(10000000000000000)},
|
||||||
},
|
},
|
||||||
10000000,
|
|
||||||
)
|
)
|
||||||
defer backend.Close()
|
defer backend.Close()
|
||||||
|
|
||||||
head, _ := backend.HeaderByNumber(context.Background(), nil) // Should be child's, good enough
|
head, _ := backend.Client().HeaderByNumber(context.Background(), nil) // Should be child's, good enough
|
||||||
gasPrice := new(big.Int).Add(head.BaseFee, big.NewInt(1))
|
gasPrice := new(big.Int).Add(head.BaseFee, big.NewInt(1))
|
||||||
|
|
||||||
// Create a transaction to an account.
|
// Create a transaction to an account.
|
||||||
code := "6060604052600a8060106000396000f360606040526008565b00"
|
code := "6060604052600a8060106000396000f360606040526008565b00"
|
||||||
tx := types.NewTransaction(0, common.HexToAddress("0x01"), big.NewInt(0), 3000000, gasPrice, common.FromHex(code))
|
tx := types.NewTransaction(0, common.HexToAddress("0x01"), big.NewInt(0), 3000000, gasPrice, common.FromHex(code))
|
||||||
tx, _ = types.SignTx(tx, types.HomesteadSigner{}, testKey)
|
tx, _ = types.SignTx(tx, types.LatestSigner(params.AllDevChainProtocolChanges), testKey)
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
defer cancel()
|
defer cancel()
|
||||||
backend.SendTransaction(ctx, tx)
|
backend.Client().SendTransaction(ctx, tx)
|
||||||
backend.Commit()
|
backend.Commit()
|
||||||
notContentCreation := errors.New("tx is not contract creation")
|
notContractCreation := errors.New("tx is not contract creation")
|
||||||
if _, err := bind.WaitDeployed(ctx, backend, tx); err.Error() != notContentCreation.Error() {
|
if _, err := bind.WaitDeployed(ctx, backend.Client(), tx); err.Error() != notContractCreation.Error() {
|
||||||
t.Errorf("error missmatch: want %q, got %q, ", notContentCreation, err)
|
t.Errorf("error mismatch: want %q, got %q, ", notContractCreation, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a transaction that is not mined.
|
// Create a transaction that is not mined.
|
||||||
tx = types.NewContractCreation(1, big.NewInt(0), 3000000, gasPrice, common.FromHex(code))
|
tx = types.NewContractCreation(1, big.NewInt(0), 3000000, gasPrice, common.FromHex(code))
|
||||||
tx, _ = types.SignTx(tx, types.HomesteadSigner{}, testKey)
|
tx, _ = types.SignTx(tx, types.LatestSigner(params.AllDevChainProtocolChanges), testKey)
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
contextCanceled := errors.New("context canceled")
|
contextCanceled := errors.New("context canceled")
|
||||||
if _, err := bind.WaitDeployed(ctx, backend, tx); err.Error() != contextCanceled.Error() {
|
if _, err := bind.WaitDeployed(ctx, backend.Client(), tx); err.Error() != contextCanceled.Error() {
|
||||||
t.Errorf("error missmatch: want %q, got %q, ", contextCanceled, err)
|
t.Errorf("error mismatch: want %q, got %q, ", contextCanceled, err)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
backend.SendTransaction(ctx, tx)
|
backend.Client().SendTransaction(ctx, tx)
|
||||||
cancel()
|
cancel()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ package abi
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@@ -84,10 +83,10 @@ func (e Error) String() string {
|
|||||||
|
|
||||||
func (e *Error) Unpack(data []byte) (interface{}, error) {
|
func (e *Error) Unpack(data []byte) (interface{}, error) {
|
||||||
if len(data) < 4 {
|
if len(data) < 4 {
|
||||||
return "", errors.New("invalid data for unpacking")
|
return "", fmt.Errorf("insufficient data for unpacking: have %d, want at least 4", len(data))
|
||||||
}
|
}
|
||||||
if !bytes.Equal(data[:4], e.ID[:4]) {
|
if !bytes.Equal(data[:4], e.ID[:4]) {
|
||||||
return "", errors.New("invalid data for unpacking")
|
return "", fmt.Errorf("invalid identifier, have %#x want %#x", data[:4], e.ID[:4])
|
||||||
}
|
}
|
||||||
return e.Inputs.Unpack(data[4:])
|
return e.Inputs.Unpack(data[4:])
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -81,6 +81,7 @@ var pledgeData1 = "00000000000000000000000000ce0d46d924cc8437c806721496599fc3ffa
|
|||||||
var mixedCaseData1 = "00000000000000000000000000000000000000000000000000000000000f42400000000000000000000000000000000000000000000000000000020489e8000000000000000000000000000000000000000000000000000000000000000f4241"
|
var mixedCaseData1 = "00000000000000000000000000000000000000000000000000000000000f42400000000000000000000000000000000000000000000000000000020489e8000000000000000000000000000000000000000000000000000000000000000f4241"
|
||||||
|
|
||||||
func TestEventId(t *testing.T) {
|
func TestEventId(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
var table = []struct {
|
var table = []struct {
|
||||||
definition string
|
definition string
|
||||||
expectations map[string]common.Hash
|
expectations map[string]common.Hash
|
||||||
@@ -112,6 +113,7 @@ func TestEventId(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestEventString(t *testing.T) {
|
func TestEventString(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
var table = []struct {
|
var table = []struct {
|
||||||
definition string
|
definition string
|
||||||
expectations map[string]string
|
expectations map[string]string
|
||||||
@@ -146,6 +148,7 @@ func TestEventString(t *testing.T) {
|
|||||||
|
|
||||||
// TestEventMultiValueWithArrayUnpack verifies that array fields will be counted after parsing array.
|
// TestEventMultiValueWithArrayUnpack verifies that array fields will be counted after parsing array.
|
||||||
func TestEventMultiValueWithArrayUnpack(t *testing.T) {
|
func TestEventMultiValueWithArrayUnpack(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
definition := `[{"name": "test", "type": "event", "inputs": [{"indexed": false, "name":"value1", "type":"uint8[2]"},{"indexed": false, "name":"value2", "type":"uint8"}]}]`
|
definition := `[{"name": "test", "type": "event", "inputs": [{"indexed": false, "name":"value1", "type":"uint8[2]"},{"indexed": false, "name":"value2", "type":"uint8"}]}]`
|
||||||
abi, err := JSON(strings.NewReader(definition))
|
abi, err := JSON(strings.NewReader(definition))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
@@ -161,6 +164,7 @@ func TestEventMultiValueWithArrayUnpack(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestEventTupleUnpack(t *testing.T) {
|
func TestEventTupleUnpack(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
type EventTransfer struct {
|
type EventTransfer struct {
|
||||||
Value *big.Int
|
Value *big.Int
|
||||||
}
|
}
|
||||||
@@ -351,6 +355,7 @@ func unpackTestEventData(dest interface{}, hexData string, jsonEvent []byte, ass
|
|||||||
|
|
||||||
// TestEventUnpackIndexed verifies that indexed field will be skipped by event decoder.
|
// TestEventUnpackIndexed verifies that indexed field will be skipped by event decoder.
|
||||||
func TestEventUnpackIndexed(t *testing.T) {
|
func TestEventUnpackIndexed(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
definition := `[{"name": "test", "type": "event", "inputs": [{"indexed": true, "name":"value1", "type":"uint8"},{"indexed": false, "name":"value2", "type":"uint8"}]}]`
|
definition := `[{"name": "test", "type": "event", "inputs": [{"indexed": true, "name":"value1", "type":"uint8"},{"indexed": false, "name":"value2", "type":"uint8"}]}]`
|
||||||
type testStruct struct {
|
type testStruct struct {
|
||||||
Value1 uint8 // indexed
|
Value1 uint8 // indexed
|
||||||
@@ -368,6 +373,7 @@ func TestEventUnpackIndexed(t *testing.T) {
|
|||||||
|
|
||||||
// TestEventIndexedWithArrayUnpack verifies that decoder will not overflow when static array is indexed input.
|
// TestEventIndexedWithArrayUnpack verifies that decoder will not overflow when static array is indexed input.
|
||||||
func TestEventIndexedWithArrayUnpack(t *testing.T) {
|
func TestEventIndexedWithArrayUnpack(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
definition := `[{"name": "test", "type": "event", "inputs": [{"indexed": true, "name":"value1", "type":"uint8[2]"},{"indexed": false, "name":"value2", "type":"string"}]}]`
|
definition := `[{"name": "test", "type": "event", "inputs": [{"indexed": true, "name":"value1", "type":"uint8[2]"},{"indexed": false, "name":"value2", "type":"string"}]}]`
|
||||||
type testStruct struct {
|
type testStruct struct {
|
||||||
Value1 [2]uint8 // indexed
|
Value1 [2]uint8 // indexed
|
||||||
|
|||||||
@@ -117,24 +117,23 @@ func NewMethod(name string, rawName string, funType FunctionType, mutability str
|
|||||||
sig = fmt.Sprintf("%v(%v)", rawName, strings.Join(types, ","))
|
sig = fmt.Sprintf("%v(%v)", rawName, strings.Join(types, ","))
|
||||||
id = crypto.Keccak256([]byte(sig))[:4]
|
id = crypto.Keccak256([]byte(sig))[:4]
|
||||||
}
|
}
|
||||||
// Extract meaningful state mutability of solidity method.
|
|
||||||
// If it's default value, never print it.
|
|
||||||
state := mutability
|
|
||||||
if state == "nonpayable" {
|
|
||||||
state = ""
|
|
||||||
}
|
|
||||||
if state != "" {
|
|
||||||
state = state + " "
|
|
||||||
}
|
|
||||||
identity := fmt.Sprintf("function %v", rawName)
|
identity := fmt.Sprintf("function %v", rawName)
|
||||||
if funType == Fallback {
|
switch funType {
|
||||||
|
case Fallback:
|
||||||
identity = "fallback"
|
identity = "fallback"
|
||||||
} else if funType == Receive {
|
case Receive:
|
||||||
identity = "receive"
|
identity = "receive"
|
||||||
} else if funType == Constructor {
|
case Constructor:
|
||||||
identity = "constructor"
|
identity = "constructor"
|
||||||
}
|
}
|
||||||
str := fmt.Sprintf("%v(%v) %sreturns(%v)", identity, strings.Join(inputNames, ", "), state, strings.Join(outputNames, ", "))
|
var str string
|
||||||
|
// Extract meaningful state mutability of solidity method.
|
||||||
|
// If it's empty string or default value "nonpayable", never print it.
|
||||||
|
if mutability == "" || mutability == "nonpayable" {
|
||||||
|
str = fmt.Sprintf("%v(%v) returns(%v)", identity, strings.Join(inputNames, ", "), strings.Join(outputNames, ", "))
|
||||||
|
} else {
|
||||||
|
str = fmt.Sprintf("%v(%v) %s returns(%v)", identity, strings.Join(inputNames, ", "), mutability, strings.Join(outputNames, ", "))
|
||||||
|
}
|
||||||
|
|
||||||
return Method{
|
return Method{
|
||||||
Name: name,
|
Name: name,
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ const methoddata = `
|
|||||||
]`
|
]`
|
||||||
|
|
||||||
func TestMethodString(t *testing.T) {
|
func TestMethodString(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
var table = []struct {
|
var table = []struct {
|
||||||
method string
|
method string
|
||||||
expectation string
|
expectation string
|
||||||
@@ -84,11 +85,12 @@ func TestMethodString(t *testing.T) {
|
|||||||
|
|
||||||
for _, test := range table {
|
for _, test := range table {
|
||||||
var got string
|
var got string
|
||||||
if test.method == "fallback" {
|
switch test.method {
|
||||||
|
case "fallback":
|
||||||
got = abi.Fallback.String()
|
got = abi.Fallback.String()
|
||||||
} else if test.method == "receive" {
|
case "receive":
|
||||||
got = abi.Receive.String()
|
got = abi.Receive.String()
|
||||||
} else {
|
default:
|
||||||
got = abi.Methods[test.method].String()
|
got = abi.Methods[test.method].String()
|
||||||
}
|
}
|
||||||
if got != test.expectation {
|
if got != test.expectation {
|
||||||
@@ -98,6 +100,7 @@ func TestMethodString(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestMethodSig(t *testing.T) {
|
func TestMethodSig(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
var cases = []struct {
|
var cases = []struct {
|
||||||
method string
|
method string
|
||||||
expect string
|
expect string
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ func packElement(t Type, reflectValue reflect.Value) ([]byte, error) {
|
|||||||
reflectValue = mustArrayToByteSlice(reflectValue)
|
reflectValue = mustArrayToByteSlice(reflectValue)
|
||||||
}
|
}
|
||||||
if reflectValue.Type() != reflect.TypeOf([]byte{}) {
|
if reflectValue.Type() != reflect.TypeOf([]byte{}) {
|
||||||
return []byte{}, errors.New("Bytes type is neither slice nor array")
|
return []byte{}, errors.New("bytes type is neither slice nor array")
|
||||||
}
|
}
|
||||||
return packBytesSlice(reflectValue.Bytes(), reflectValue.Len()), nil
|
return packBytesSlice(reflectValue.Bytes(), reflectValue.Len()), nil
|
||||||
case FixedBytesTy, FunctionTy:
|
case FixedBytesTy, FunctionTy:
|
||||||
@@ -66,7 +66,7 @@ func packElement(t Type, reflectValue reflect.Value) ([]byte, error) {
|
|||||||
}
|
}
|
||||||
return common.RightPadBytes(reflectValue.Bytes(), 32), nil
|
return common.RightPadBytes(reflectValue.Bytes(), 32), nil
|
||||||
default:
|
default:
|
||||||
return []byte{}, fmt.Errorf("Could not pack element, unknown type: %v", t.T)
|
return []byte{}, fmt.Errorf("could not pack element, unknown type: %v", t.T)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -32,8 +32,11 @@ import (
|
|||||||
|
|
||||||
// TestPack tests the general pack/unpack tests in packing_test.go
|
// TestPack tests the general pack/unpack tests in packing_test.go
|
||||||
func TestPack(t *testing.T) {
|
func TestPack(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
for i, test := range packUnpackTests {
|
for i, test := range packUnpackTests {
|
||||||
|
i, test := i, test
|
||||||
t.Run(strconv.Itoa(i), func(t *testing.T) {
|
t.Run(strconv.Itoa(i), func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
encb, err := hex.DecodeString(test.packed)
|
encb, err := hex.DecodeString(test.packed)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("invalid hex %s: %v", test.packed, err)
|
t.Fatalf("invalid hex %s: %v", test.packed, err)
|
||||||
@@ -57,6 +60,7 @@ func TestPack(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestMethodPack(t *testing.T) {
|
func TestMethodPack(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
abi, err := JSON(strings.NewReader(jsondata))
|
abi, err := JSON(strings.NewReader(jsondata))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@@ -177,6 +181,7 @@ func TestMethodPack(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestPackNumber(t *testing.T) {
|
func TestPackNumber(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
value reflect.Value
|
value reflect.Value
|
||||||
packed []byte
|
packed []byte
|
||||||
|
|||||||
@@ -134,7 +134,7 @@ func setSlice(dst, src reflect.Value) error {
|
|||||||
dst.Set(slice)
|
dst.Set(slice)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return errors.New("Cannot set slice, destination not settable")
|
return errors.New("cannot set slice, destination not settable")
|
||||||
}
|
}
|
||||||
|
|
||||||
func setArray(dst, src reflect.Value) error {
|
func setArray(dst, src reflect.Value) error {
|
||||||
@@ -155,7 +155,7 @@ func setArray(dst, src reflect.Value) error {
|
|||||||
dst.Set(array)
|
dst.Set(array)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return errors.New("Cannot set array, destination not settable")
|
return errors.New("cannot set array, destination not settable")
|
||||||
}
|
}
|
||||||
|
|
||||||
func setStruct(dst, src reflect.Value) error {
|
func setStruct(dst, src reflect.Value) error {
|
||||||
@@ -163,7 +163,7 @@ func setStruct(dst, src reflect.Value) error {
|
|||||||
srcField := src.Field(i)
|
srcField := src.Field(i)
|
||||||
dstField := dst.Field(i)
|
dstField := dst.Field(i)
|
||||||
if !dstField.IsValid() || !srcField.IsValid() {
|
if !dstField.IsValid() || !srcField.IsValid() {
|
||||||
return fmt.Errorf("Could not find src field: %v value: %v in destination", srcField.Type().Name(), srcField)
|
return fmt.Errorf("could not find src field: %v value: %v in destination", srcField.Type().Name(), srcField)
|
||||||
}
|
}
|
||||||
if err := set(dstField, srcField); err != nil {
|
if err := set(dstField, srcField); err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -170,8 +170,11 @@ var reflectTests = []reflectTest{
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestReflectNameToStruct(t *testing.T) {
|
func TestReflectNameToStruct(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
for _, test := range reflectTests {
|
for _, test := range reflectTests {
|
||||||
|
test := test
|
||||||
t.Run(test.name, func(t *testing.T) {
|
t.Run(test.name, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
m, err := mapArgNamesToStructFields(test.args, reflect.ValueOf(test.struc))
|
m, err := mapArgNamesToStructFields(test.args, reflect.ValueOf(test.struc))
|
||||||
if len(test.err) > 0 {
|
if len(test.err) > 0 {
|
||||||
if err == nil || err.Error() != test.err {
|
if err == nil || err.Error() != test.err {
|
||||||
@@ -192,6 +195,7 @@ func TestReflectNameToStruct(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestConvertType(t *testing.T) {
|
func TestConvertType(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
// Test Basic Struct
|
// Test Basic Struct
|
||||||
type T struct {
|
type T struct {
|
||||||
X *big.Int
|
X *big.Int
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestParseSelector(t *testing.T) {
|
func TestParseSelector(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
mkType := func(types ...interface{}) []ArgumentMarshaling {
|
mkType := func(types ...interface{}) []ArgumentMarshaling {
|
||||||
var result []ArgumentMarshaling
|
var result []ArgumentMarshaling
|
||||||
for i, typeOrComponents := range types {
|
for i, typeOrComponents := range types {
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import (
|
|||||||
"reflect"
|
"reflect"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/common/math"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -41,8 +42,7 @@ func MakeTopics(query ...[]interface{}) ([][]common.Hash, error) {
|
|||||||
case common.Address:
|
case common.Address:
|
||||||
copy(topic[common.HashLength-common.AddressLength:], rule[:])
|
copy(topic[common.HashLength-common.AddressLength:], rule[:])
|
||||||
case *big.Int:
|
case *big.Int:
|
||||||
blob := rule.Bytes()
|
copy(topic[:], math.U256Bytes(rule))
|
||||||
copy(topic[common.HashLength-len(blob):], blob)
|
|
||||||
case bool:
|
case bool:
|
||||||
if rule {
|
if rule {
|
||||||
topic[common.HashLength-1] = 1
|
topic[common.HashLength-1] = 1
|
||||||
@@ -75,7 +75,7 @@ func MakeTopics(query ...[]interface{}) ([][]common.Hash, error) {
|
|||||||
copy(topic[:], hash[:])
|
copy(topic[:], hash[:])
|
||||||
|
|
||||||
default:
|
default:
|
||||||
// todo(rjl493456442) according solidity documentation, indexed event
|
// todo(rjl493456442) according to solidity documentation, indexed event
|
||||||
// parameters that are not value types i.e. arrays and structs are not
|
// parameters that are not value types i.e. arrays and structs are not
|
||||||
// stored directly but instead a keccak256-hash of an encoding is stored.
|
// stored directly but instead a keccak256-hash of an encoding is stored.
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
package abi
|
package abi
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"math"
|
||||||
"math/big"
|
"math/big"
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
@@ -26,6 +27,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestMakeTopics(t *testing.T) {
|
func TestMakeTopics(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
type args struct {
|
type args struct {
|
||||||
query [][]interface{}
|
query [][]interface{}
|
||||||
}
|
}
|
||||||
@@ -54,9 +56,27 @@ func TestMakeTopics(t *testing.T) {
|
|||||||
false,
|
false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"support *big.Int types in topics",
|
"support positive *big.Int types in topics",
|
||||||
args{[][]interface{}{{big.NewInt(1).Lsh(big.NewInt(2), 254)}}},
|
args{[][]interface{}{
|
||||||
[][]common.Hash{{common.Hash{128}}},
|
{big.NewInt(1)},
|
||||||
|
{big.NewInt(1).Lsh(big.NewInt(2), 254)},
|
||||||
|
}},
|
||||||
|
[][]common.Hash{
|
||||||
|
{common.HexToHash("0000000000000000000000000000000000000000000000000000000000000001")},
|
||||||
|
{common.Hash{128}},
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"support negative *big.Int types in topics",
|
||||||
|
args{[][]interface{}{
|
||||||
|
{big.NewInt(-1)},
|
||||||
|
{big.NewInt(math.MinInt64)},
|
||||||
|
}},
|
||||||
|
[][]common.Hash{
|
||||||
|
{common.MaxHash},
|
||||||
|
{common.HexToHash("ffffffffffffffffffffffffffffffffffffffffffffffff8000000000000000")},
|
||||||
|
},
|
||||||
false,
|
false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -117,7 +137,9 @@ func TestMakeTopics(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
|
tt := tt
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
got, err := MakeTopics(tt.args.query...)
|
got, err := MakeTopics(tt.args.query...)
|
||||||
if (err != nil) != tt.wantErr {
|
if (err != nil) != tt.wantErr {
|
||||||
t.Errorf("makeTopics() error = %v, wantErr %v", err, tt.wantErr)
|
t.Errorf("makeTopics() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
@@ -347,10 +369,13 @@ func setupTopicsTests() []topicTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestParseTopics(t *testing.T) {
|
func TestParseTopics(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
tests := setupTopicsTests()
|
tests := setupTopicsTests()
|
||||||
|
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
|
tt := tt
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
createObj := tt.args.createObj()
|
createObj := tt.args.createObj()
|
||||||
if err := ParseTopics(createObj, tt.args.fields, tt.args.topics); (err != nil) != tt.wantErr {
|
if err := ParseTopics(createObj, tt.args.fields, tt.args.topics); (err != nil) != tt.wantErr {
|
||||||
t.Errorf("parseTopics() error = %v, wantErr %v", err, tt.wantErr)
|
t.Errorf("parseTopics() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
@@ -364,10 +389,13 @@ func TestParseTopics(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestParseTopicsIntoMap(t *testing.T) {
|
func TestParseTopicsIntoMap(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
tests := setupTopicsTests()
|
tests := setupTopicsTests()
|
||||||
|
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
|
tt := tt
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
outMap := make(map[string]interface{})
|
outMap := make(map[string]interface{})
|
||||||
if err := ParseTopicsIntoMap(outMap, tt.args.fields, tt.args.topics); (err != nil) != tt.wantErr {
|
if err := ParseTopicsIntoMap(outMap, tt.args.fields, tt.args.topics); (err != nil) != tt.wantErr {
|
||||||
t.Errorf("parseTopicsIntoMap() error = %v, wantErr %v", err, tt.wantErr)
|
t.Errorf("parseTopicsIntoMap() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ type typeWithoutStringer Type
|
|||||||
|
|
||||||
// Tests that all allowed types get recognized by the type parser.
|
// Tests that all allowed types get recognized by the type parser.
|
||||||
func TestTypeRegexp(t *testing.T) {
|
func TestTypeRegexp(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
blob string
|
blob string
|
||||||
components []ArgumentMarshaling
|
components []ArgumentMarshaling
|
||||||
@@ -117,6 +118,7 @@ func TestTypeRegexp(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestTypeCheck(t *testing.T) {
|
func TestTypeCheck(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
for i, test := range []struct {
|
for i, test := range []struct {
|
||||||
typ string
|
typ string
|
||||||
components []ArgumentMarshaling
|
components []ArgumentMarshaling
|
||||||
@@ -308,6 +310,7 @@ func TestTypeCheck(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestInternalType(t *testing.T) {
|
func TestInternalType(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
components := []ArgumentMarshaling{{Name: "a", Type: "int64"}}
|
components := []ArgumentMarshaling{{Name: "a", Type: "int64"}}
|
||||||
internalType := "struct a.b[]"
|
internalType := "struct a.b[]"
|
||||||
kind := Type{
|
kind := Type{
|
||||||
@@ -332,6 +335,7 @@ func TestInternalType(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestGetTypeSize(t *testing.T) {
|
func TestGetTypeSize(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
var testCases = []struct {
|
var testCases = []struct {
|
||||||
typ string
|
typ string
|
||||||
components []ArgumentMarshaling
|
components []ArgumentMarshaling
|
||||||
@@ -368,6 +372,7 @@ func TestGetTypeSize(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestNewFixedBytesOver32(t *testing.T) {
|
func TestNewFixedBytesOver32(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
_, err := NewType("bytes4096", "", nil)
|
_, err := NewType("bytes4096", "", nil)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Errorf("fixed bytes with size over 32 is not spec'd")
|
t.Errorf("fixed bytes with size over 32 is not spec'd")
|
||||||
|
|||||||
@@ -160,13 +160,14 @@ func forEachUnpack(t Type, output []byte, start, size int) (interface{}, error)
|
|||||||
// this value will become our slice or our array, depending on the type
|
// this value will become our slice or our array, depending on the type
|
||||||
var refSlice reflect.Value
|
var refSlice reflect.Value
|
||||||
|
|
||||||
if t.T == SliceTy {
|
switch t.T {
|
||||||
|
case SliceTy:
|
||||||
// declare our slice
|
// declare our slice
|
||||||
refSlice = reflect.MakeSlice(t.GetType(), size, size)
|
refSlice = reflect.MakeSlice(t.GetType(), size, size)
|
||||||
} else if t.T == ArrayTy {
|
case ArrayTy:
|
||||||
// declare our array
|
// declare our array
|
||||||
refSlice = reflect.New(t.GetType()).Elem()
|
refSlice = reflect.New(t.GetType()).Elem()
|
||||||
} else {
|
default:
|
||||||
return nil, errors.New("abi: invalid type in array/slice unpacking stage")
|
return nil, errors.New("abi: invalid type in array/slice unpacking stage")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ import (
|
|||||||
|
|
||||||
// TestUnpack tests the general pack/unpack tests in packing_test.go
|
// TestUnpack tests the general pack/unpack tests in packing_test.go
|
||||||
func TestUnpack(t *testing.T) {
|
func TestUnpack(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
for i, test := range packUnpackTests {
|
for i, test := range packUnpackTests {
|
||||||
t.Run(strconv.Itoa(i)+" "+test.def, func(t *testing.T) {
|
t.Run(strconv.Itoa(i)+" "+test.def, func(t *testing.T) {
|
||||||
//Unpack
|
//Unpack
|
||||||
@@ -206,13 +207,13 @@ var unpackTests = []unpackTest{
|
|||||||
def: `[{"type":"bool"}]`,
|
def: `[{"type":"bool"}]`,
|
||||||
enc: "",
|
enc: "",
|
||||||
want: false,
|
want: false,
|
||||||
err: "abi: attempting to unmarshall an empty string while arguments are expected",
|
err: "abi: attempting to unmarshal an empty string while arguments are expected",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
def: `[{"type":"bytes32","indexed":true},{"type":"uint256","indexed":false}]`,
|
def: `[{"type":"bytes32","indexed":true},{"type":"uint256","indexed":false}]`,
|
||||||
enc: "",
|
enc: "",
|
||||||
want: false,
|
want: false,
|
||||||
err: "abi: attempting to unmarshall an empty string while arguments are expected",
|
err: "abi: attempting to unmarshal an empty string while arguments are expected",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
def: `[{"type":"bool","indexed":true},{"type":"uint64","indexed":true}]`,
|
def: `[{"type":"bool","indexed":true},{"type":"uint64","indexed":true}]`,
|
||||||
@@ -224,6 +225,7 @@ var unpackTests = []unpackTest{
|
|||||||
// TestLocalUnpackTests runs test specially designed only for unpacking.
|
// TestLocalUnpackTests runs test specially designed only for unpacking.
|
||||||
// All test cases that can be used to test packing and unpacking should move to packing_test.go
|
// All test cases that can be used to test packing and unpacking should move to packing_test.go
|
||||||
func TestLocalUnpackTests(t *testing.T) {
|
func TestLocalUnpackTests(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
for i, test := range unpackTests {
|
for i, test := range unpackTests {
|
||||||
t.Run(strconv.Itoa(i), func(t *testing.T) {
|
t.Run(strconv.Itoa(i), func(t *testing.T) {
|
||||||
//Unpack
|
//Unpack
|
||||||
@@ -251,6 +253,7 @@ func TestLocalUnpackTests(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestUnpackIntoInterfaceSetDynamicArrayOutput(t *testing.T) {
|
func TestUnpackIntoInterfaceSetDynamicArrayOutput(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
abi, err := JSON(strings.NewReader(`[{"constant":true,"inputs":[],"name":"testDynamicFixedBytes15","outputs":[{"name":"","type":"bytes15[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"testDynamicFixedBytes32","outputs":[{"name":"","type":"bytes32[]"}],"payable":false,"stateMutability":"view","type":"function"}]`))
|
abi, err := JSON(strings.NewReader(`[{"constant":true,"inputs":[],"name":"testDynamicFixedBytes15","outputs":[{"name":"","type":"bytes15[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"testDynamicFixedBytes32","outputs":[{"name":"","type":"bytes32[]"}],"payable":false,"stateMutability":"view","type":"function"}]`))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@@ -321,6 +324,7 @@ func methodMultiReturn(require *require.Assertions) (ABI, []byte, methodMultiOut
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestMethodMultiReturn(t *testing.T) {
|
func TestMethodMultiReturn(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
type reversed struct {
|
type reversed struct {
|
||||||
String string
|
String string
|
||||||
Int *big.Int
|
Int *big.Int
|
||||||
@@ -400,6 +404,7 @@ func TestMethodMultiReturn(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestMultiReturnWithArray(t *testing.T) {
|
func TestMultiReturnWithArray(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
const definition = `[{"name" : "multi", "type": "function", "outputs": [{"type": "uint64[3]"}, {"type": "uint64"}]}]`
|
const definition = `[{"name" : "multi", "type": "function", "outputs": [{"type": "uint64[3]"}, {"type": "uint64"}]}]`
|
||||||
abi, err := JSON(strings.NewReader(definition))
|
abi, err := JSON(strings.NewReader(definition))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -423,6 +428,7 @@ func TestMultiReturnWithArray(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestMultiReturnWithStringArray(t *testing.T) {
|
func TestMultiReturnWithStringArray(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
const definition = `[{"name" : "multi", "type": "function", "outputs": [{"name": "","type": "uint256[3]"},{"name": "","type": "address"},{"name": "","type": "string[2]"},{"name": "","type": "bool"}]}]`
|
const definition = `[{"name" : "multi", "type": "function", "outputs": [{"name": "","type": "uint256[3]"},{"name": "","type": "address"},{"name": "","type": "string[2]"},{"name": "","type": "bool"}]}]`
|
||||||
abi, err := JSON(strings.NewReader(definition))
|
abi, err := JSON(strings.NewReader(definition))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -453,6 +459,7 @@ func TestMultiReturnWithStringArray(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestMultiReturnWithStringSlice(t *testing.T) {
|
func TestMultiReturnWithStringSlice(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
const definition = `[{"name" : "multi", "type": "function", "outputs": [{"name": "","type": "string[]"},{"name": "","type": "uint256[]"}]}]`
|
const definition = `[{"name" : "multi", "type": "function", "outputs": [{"name": "","type": "string[]"},{"name": "","type": "uint256[]"}]}]`
|
||||||
abi, err := JSON(strings.NewReader(definition))
|
abi, err := JSON(strings.NewReader(definition))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -485,6 +492,7 @@ func TestMultiReturnWithStringSlice(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestMultiReturnWithDeeplyNestedArray(t *testing.T) {
|
func TestMultiReturnWithDeeplyNestedArray(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
// Similar to TestMultiReturnWithArray, but with a special case in mind:
|
// Similar to TestMultiReturnWithArray, but with a special case in mind:
|
||||||
// values of nested static arrays count towards the size as well, and any element following
|
// values of nested static arrays count towards the size as well, and any element following
|
||||||
// after such nested array argument should be read with the correct offset,
|
// after such nested array argument should be read with the correct offset,
|
||||||
@@ -525,6 +533,7 @@ func TestMultiReturnWithDeeplyNestedArray(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestUnmarshal(t *testing.T) {
|
func TestUnmarshal(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
const definition = `[
|
const definition = `[
|
||||||
{ "name" : "int", "type": "function", "outputs": [ { "type": "uint256" } ] },
|
{ "name" : "int", "type": "function", "outputs": [ { "type": "uint256" } ] },
|
||||||
{ "name" : "bool", "type": "function", "outputs": [ { "type": "bool" } ] },
|
{ "name" : "bool", "type": "function", "outputs": [ { "type": "bool" } ] },
|
||||||
@@ -774,6 +783,7 @@ func TestUnmarshal(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestUnpackTuple(t *testing.T) {
|
func TestUnpackTuple(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
const simpleTuple = `[{"name":"tuple","type":"function","outputs":[{"type":"tuple","name":"ret","components":[{"type":"int256","name":"a"},{"type":"int256","name":"b"}]}]}]`
|
const simpleTuple = `[{"name":"tuple","type":"function","outputs":[{"type":"tuple","name":"ret","components":[{"type":"int256","name":"a"},{"type":"int256","name":"b"}]}]}]`
|
||||||
abi, err := JSON(strings.NewReader(simpleTuple))
|
abi, err := JSON(strings.NewReader(simpleTuple))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -876,6 +886,7 @@ func TestUnpackTuple(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestOOMMaliciousInput(t *testing.T) {
|
func TestOOMMaliciousInput(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
oomTests := []unpackTest{
|
oomTests := []unpackTest{
|
||||||
{
|
{
|
||||||
def: `[{"type": "uint8[]"}]`,
|
def: `[{"type": "uint8[]"}]`,
|
||||||
@@ -946,6 +957,7 @@ func TestOOMMaliciousInput(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestPackAndUnpackIncompatibleNumber(t *testing.T) {
|
func TestPackAndUnpackIncompatibleNumber(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
var encodeABI Arguments
|
var encodeABI Arguments
|
||||||
uint256Ty, err := NewType("uint256", "", nil)
|
uint256Ty, err := NewType("uint256", "", nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestTextHash(t *testing.T) {
|
func TestTextHash(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
hash := TextHash([]byte("Hello Joe"))
|
hash := TextHash([]byte("Hello Joe"))
|
||||||
want := hexutil.MustDecode("0xa080337ae51c4e064c189e113edd0ba391df9206e2f49db658bb32cf2911730b")
|
want := hexutil.MustDecode("0xa080337ae51c4e064c189e113edd0ba391df9206e2f49db658bb32cf2911730b")
|
||||||
if !bytes.Equal(hash, want) {
|
if !bytes.Equal(hash, want) {
|
||||||
|
|||||||
2
accounts/external/backend.go
vendored
2
accounts/external/backend.go
vendored
@@ -163,7 +163,7 @@ func (api *ExternalSigner) SignData(account accounts.Account, mimeType string, d
|
|||||||
hexutil.Encode(data)); err != nil {
|
hexutil.Encode(data)); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
// If V is on 27/28-form, convert to to 0/1 for Clique and Parlia
|
// If V is on 27/28-form, convert to 0/1 for Clique and Parlia
|
||||||
if (mimeType == accounts.MimetypeClique || mimeType == accounts.MimetypeParlia) && (res[64] == 27 || res[64] == 28) {
|
if (mimeType == accounts.MimetypeClique || mimeType == accounts.MimetypeParlia) && (res[64] == 27 || res[64] == 28) {
|
||||||
res[64] -= 27 // Transform V from 27/28 to 0/1 for Clique and Parlia use
|
res[64] -= 27 // Transform V from 27/28 to 0/1 for Clique and Parlia use
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import (
|
|||||||
// Tests that HD derivation paths can be correctly parsed into our internal binary
|
// Tests that HD derivation paths can be correctly parsed into our internal binary
|
||||||
// representation.
|
// representation.
|
||||||
func TestHDPathParsing(t *testing.T) {
|
func TestHDPathParsing(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
input string
|
input string
|
||||||
output DerivationPath
|
output DerivationPath
|
||||||
@@ -89,6 +90,7 @@ func testDerive(t *testing.T, next func() DerivationPath, expected []string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestHdPathIteration(t *testing.T) {
|
func TestHdPathIteration(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
testDerive(t, DefaultIterator(DefaultBaseDerivationPath),
|
testDerive(t, DefaultIterator(DefaultBaseDerivationPath),
|
||||||
[]string{
|
[]string{
|
||||||
"m/44'/60'/0'/0/0", "m/44'/60'/0'/0/1",
|
"m/44'/60'/0'/0/0", "m/44'/60'/0'/0/1",
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ var (
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
// waitWatcherStarts waits up to 1s for the keystore watcher to start.
|
// waitWatcherStart waits up to 1s for the keystore watcher to start.
|
||||||
func waitWatcherStart(ks *KeyStore) bool {
|
func waitWatcherStart(ks *KeyStore) bool {
|
||||||
// On systems where file watch is not supported, just return "ok".
|
// On systems where file watch is not supported, just return "ok".
|
||||||
if !ks.cache.watcher.enabled() {
|
if !ks.cache.watcher.enabled() {
|
||||||
@@ -68,7 +68,7 @@ func waitWatcherStart(ks *KeyStore) bool {
|
|||||||
|
|
||||||
func waitForAccounts(wantAccounts []accounts.Account, ks *KeyStore) error {
|
func waitForAccounts(wantAccounts []accounts.Account, ks *KeyStore) error {
|
||||||
var list []accounts.Account
|
var list []accounts.Account
|
||||||
for t0 := time.Now(); time.Since(t0) < 5*time.Second; time.Sleep(200 * time.Millisecond) {
|
for t0 := time.Now(); time.Since(t0) < 5*time.Second; time.Sleep(100 * time.Millisecond) {
|
||||||
list = ks.Accounts()
|
list = ks.Accounts()
|
||||||
if reflect.DeepEqual(list, wantAccounts) {
|
if reflect.DeepEqual(list, wantAccounts) {
|
||||||
// ks should have also received change notifications
|
// ks should have also received change notifications
|
||||||
@@ -152,6 +152,7 @@ func TestWatchNoDir(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestCacheInitialReload(t *testing.T) {
|
func TestCacheInitialReload(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
cache, _ := newAccountCache(cachetestDir)
|
cache, _ := newAccountCache(cachetestDir)
|
||||||
accounts := cache.accounts()
|
accounts := cache.accounts()
|
||||||
if !reflect.DeepEqual(accounts, cachetestAccounts) {
|
if !reflect.DeepEqual(accounts, cachetestAccounts) {
|
||||||
@@ -160,6 +161,7 @@ func TestCacheInitialReload(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestCacheAddDeleteOrder(t *testing.T) {
|
func TestCacheAddDeleteOrder(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
cache, _ := newAccountCache("testdata/no-such-dir")
|
cache, _ := newAccountCache("testdata/no-such-dir")
|
||||||
cache.watcher.running = true // prevent unexpected reloads
|
cache.watcher.running = true // prevent unexpected reloads
|
||||||
|
|
||||||
@@ -244,6 +246,7 @@ func TestCacheAddDeleteOrder(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestCacheFind(t *testing.T) {
|
func TestCacheFind(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
dir := filepath.Join("testdata", "dir")
|
dir := filepath.Join("testdata", "dir")
|
||||||
cache, _ := newAccountCache(dir)
|
cache, _ := newAccountCache(dir)
|
||||||
cache.watcher.running = true // prevent unexpected reloads
|
cache.watcher.running = true // prevent unexpected reloads
|
||||||
@@ -350,12 +353,11 @@ func TestUpdatedKeyfileContents(t *testing.T) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
// needed so that modTime of `file` is different to its current value after forceCopyFile
|
// needed so that modTime of `file` is different to its current value after forceCopyFile
|
||||||
time.Sleep(time.Second)
|
os.Chtimes(file, time.Now().Add(-time.Second), time.Now().Add(-time.Second))
|
||||||
|
|
||||||
// Now replace file contents
|
// Now replace file contents
|
||||||
if err := forceCopyFile(file, cachetestAccounts[1].URL.Path); err != nil {
|
if err := forceCopyFile(file, cachetestAccounts[1].URL.Path); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
wantAccounts = []accounts.Account{cachetestAccounts[1]}
|
wantAccounts = []accounts.Account{cachetestAccounts[1]}
|
||||||
wantAccounts[0].URL = accounts.URL{Scheme: KeyStoreScheme, Path: file}
|
wantAccounts[0].URL = accounts.URL{Scheme: KeyStoreScheme, Path: file}
|
||||||
@@ -366,12 +368,11 @@ func TestUpdatedKeyfileContents(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// needed so that modTime of `file` is different to its current value after forceCopyFile
|
// needed so that modTime of `file` is different to its current value after forceCopyFile
|
||||||
time.Sleep(time.Second)
|
os.Chtimes(file, time.Now().Add(-time.Second), time.Now().Add(-time.Second))
|
||||||
|
|
||||||
// Now replace file contents again
|
// Now replace file contents again
|
||||||
if err := forceCopyFile(file, cachetestAccounts[2].URL.Path); err != nil {
|
if err := forceCopyFile(file, cachetestAccounts[2].URL.Path); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
wantAccounts = []accounts.Account{cachetestAccounts[2]}
|
wantAccounts = []accounts.Account{cachetestAccounts[2]}
|
||||||
wantAccounts[0].URL = accounts.URL{Scheme: KeyStoreScheme, Path: file}
|
wantAccounts[0].URL = accounts.URL{Scheme: KeyStoreScheme, Path: file}
|
||||||
@@ -382,12 +383,11 @@ func TestUpdatedKeyfileContents(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// needed so that modTime of `file` is different to its current value after os.WriteFile
|
// needed so that modTime of `file` is different to its current value after os.WriteFile
|
||||||
time.Sleep(time.Second)
|
os.Chtimes(file, time.Now().Add(-time.Second), time.Now().Add(-time.Second))
|
||||||
|
|
||||||
// Now replace file contents with crap
|
// Now replace file contents with crap
|
||||||
if err := os.WriteFile(file, []byte("foo"), 0600); err != nil {
|
if err := os.WriteFile(file, []byte("foo"), 0600); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
if err := waitForAccounts([]accounts.Account{}, ks); err != nil {
|
if err := waitForAccounts([]accounts.Account{}, ks); err != nil {
|
||||||
t.Errorf("Emptying account file failed")
|
t.Errorf("Emptying account file failed")
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright 2019 The go-ethereum Authors
|
// Copyright 2017 The go-ethereum Authors
|
||||||
// This file is part of the go-ethereum library.
|
// This file is part of the go-ethereum library.
|
||||||
//
|
//
|
||||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||||
@@ -17,21 +17,18 @@
|
|||||||
package keystore
|
package keystore
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
"testing"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/accounts/keystore"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func Fuzz(input []byte) int {
|
func FuzzPassword(f *testing.F) {
|
||||||
ks := keystore.NewKeyStore("/tmp/ks", keystore.LightScryptN, keystore.LightScryptP)
|
f.Fuzz(func(t *testing.T, password string) {
|
||||||
|
ks := NewKeyStore(t.TempDir(), LightScryptN, LightScryptP)
|
||||||
a, err := ks.NewAccount(string(input))
|
a, err := ks.NewAccount(password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if err := ks.Unlock(a, string(input)); err != nil {
|
if err := ks.Unlock(a, password); err != nil {
|
||||||
panic(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
os.Remove(a.URL.Path)
|
})
|
||||||
return 1
|
|
||||||
}
|
}
|
||||||
@@ -36,6 +36,7 @@ import (
|
|||||||
var testSigData = make([]byte, 32)
|
var testSigData = make([]byte, 32)
|
||||||
|
|
||||||
func TestKeyStore(t *testing.T) {
|
func TestKeyStore(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
dir, ks := tmpKeyStore(t, true)
|
dir, ks := tmpKeyStore(t, true)
|
||||||
|
|
||||||
a, err := ks.NewAccount("foo")
|
a, err := ks.NewAccount("foo")
|
||||||
@@ -70,6 +71,7 @@ func TestKeyStore(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestSign(t *testing.T) {
|
func TestSign(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
_, ks := tmpKeyStore(t, true)
|
_, ks := tmpKeyStore(t, true)
|
||||||
|
|
||||||
pass := "" // not used but required by API
|
pass := "" // not used but required by API
|
||||||
@@ -86,6 +88,7 @@ func TestSign(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestSignWithPassphrase(t *testing.T) {
|
func TestSignWithPassphrase(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
_, ks := tmpKeyStore(t, true)
|
_, ks := tmpKeyStore(t, true)
|
||||||
|
|
||||||
pass := "passwd"
|
pass := "passwd"
|
||||||
@@ -280,6 +283,7 @@ type walletEvent struct {
|
|||||||
// Tests that wallet notifications and correctly fired when accounts are added
|
// Tests that wallet notifications and correctly fired when accounts are added
|
||||||
// or deleted from the keystore.
|
// or deleted from the keystore.
|
||||||
func TestWalletNotifications(t *testing.T) {
|
func TestWalletNotifications(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
_, ks := tmpKeyStore(t, false)
|
_, ks := tmpKeyStore(t, false)
|
||||||
|
|
||||||
// Subscribe to the wallet feed and collect events.
|
// Subscribe to the wallet feed and collect events.
|
||||||
@@ -339,8 +343,9 @@ func TestWalletNotifications(t *testing.T) {
|
|||||||
checkEvents(t, wantEvents, events)
|
checkEvents(t, wantEvents, events)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestImportExport tests the import functionality of a keystore.
|
// TestImportECDSA tests the import functionality of a keystore.
|
||||||
func TestImportECDSA(t *testing.T) {
|
func TestImportECDSA(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
_, ks := tmpKeyStore(t, true)
|
_, ks := tmpKeyStore(t, true)
|
||||||
key, err := crypto.GenerateKey()
|
key, err := crypto.GenerateKey()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -357,8 +362,9 @@ func TestImportECDSA(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestImportECDSA tests the import and export functionality of a keystore.
|
// TestImportExport tests the import and export functionality of a keystore.
|
||||||
func TestImportExport(t *testing.T) {
|
func TestImportExport(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
_, ks := tmpKeyStore(t, true)
|
_, ks := tmpKeyStore(t, true)
|
||||||
acc, err := ks.NewAccount("old")
|
acc, err := ks.NewAccount("old")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -387,6 +393,7 @@ func TestImportExport(t *testing.T) {
|
|||||||
// TestImportRace tests the keystore on races.
|
// TestImportRace tests the keystore on races.
|
||||||
// This test should fail under -race if importing races.
|
// This test should fail under -race if importing races.
|
||||||
func TestImportRace(t *testing.T) {
|
func TestImportRace(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
_, ks := tmpKeyStore(t, true)
|
_, ks := tmpKeyStore(t, true)
|
||||||
acc, err := ks.NewAccount("old")
|
acc, err := ks.NewAccount("old")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -136,7 +136,7 @@ func (ks keyStorePassphrase) JoinPath(filename string) string {
|
|||||||
return filepath.Join(ks.keysDirPath, filename)
|
return filepath.Join(ks.keysDirPath, filename)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Encryptdata encrypts the data given as 'data' with the password 'auth'.
|
// EncryptDataV3 encrypts the data given as 'data' with the password 'auth'.
|
||||||
func EncryptDataV3(data, auth []byte, scryptN, scryptP int) (CryptoJSON, error) {
|
func EncryptDataV3(data, auth []byte, scryptN, scryptP int) (CryptoJSON, error) {
|
||||||
salt := make([]byte, 32)
|
salt := make([]byte, 32)
|
||||||
if _, err := io.ReadFull(rand.Reader, salt); err != nil {
|
if _, err := io.ReadFull(rand.Reader, salt); err != nil {
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ const (
|
|||||||
|
|
||||||
// Tests that a json key file can be decrypted and encrypted in multiple rounds.
|
// Tests that a json key file can be decrypted and encrypted in multiple rounds.
|
||||||
func TestKeyEncryptDecrypt(t *testing.T) {
|
func TestKeyEncryptDecrypt(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
keyjson, err := os.ReadFile("testdata/very-light-scrypt.json")
|
keyjson, err := os.ReadFile("testdata/very-light-scrypt.json")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@@ -54,7 +55,7 @@ func TestKeyEncryptDecrypt(t *testing.T) {
|
|||||||
// Recrypt with a new password and start over
|
// Recrypt with a new password and start over
|
||||||
password += "new data appended" // nolint: gosec
|
password += "new data appended" // nolint: gosec
|
||||||
if keyjson, err = EncryptKey(key, password, veryLightScryptN, veryLightScryptP); err != nil {
|
if keyjson, err = EncryptKey(key, password, veryLightScryptN, veryLightScryptP); err != nil {
|
||||||
t.Errorf("test %d: failed to recrypt key %v", i, err)
|
t.Errorf("test %d: failed to re-encrypt key %v", i, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ func tmpKeyStoreIface(t *testing.T, encrypted bool) (dir string, ks keyStore) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestKeyStorePlain(t *testing.T) {
|
func TestKeyStorePlain(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
_, ks := tmpKeyStoreIface(t, false)
|
_, ks := tmpKeyStoreIface(t, false)
|
||||||
|
|
||||||
pass := "" // not used but required by API
|
pass := "" // not used but required by API
|
||||||
@@ -60,6 +61,7 @@ func TestKeyStorePlain(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestKeyStorePassphrase(t *testing.T) {
|
func TestKeyStorePassphrase(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
_, ks := tmpKeyStoreIface(t, true)
|
_, ks := tmpKeyStoreIface(t, true)
|
||||||
|
|
||||||
pass := "foo"
|
pass := "foo"
|
||||||
@@ -80,6 +82,7 @@ func TestKeyStorePassphrase(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestKeyStorePassphraseDecryptionFail(t *testing.T) {
|
func TestKeyStorePassphraseDecryptionFail(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
_, ks := tmpKeyStoreIface(t, true)
|
_, ks := tmpKeyStoreIface(t, true)
|
||||||
|
|
||||||
pass := "foo"
|
pass := "foo"
|
||||||
@@ -93,6 +96,7 @@ func TestKeyStorePassphraseDecryptionFail(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestImportPreSaleKey(t *testing.T) {
|
func TestImportPreSaleKey(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
dir, ks := tmpKeyStoreIface(t, true)
|
dir, ks := tmpKeyStoreIface(t, true)
|
||||||
|
|
||||||
// file content of a presale key file generated with:
|
// file content of a presale key file generated with:
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
package keystore
|
package keystore
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"os"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
@@ -77,7 +78,9 @@ func (w *watcher) loop() {
|
|||||||
}
|
}
|
||||||
defer watcher.Close()
|
defer watcher.Close()
|
||||||
if err := watcher.Add(w.ac.keydir); err != nil {
|
if err := watcher.Add(w.ac.keydir); err != nil {
|
||||||
logger.Warn("Failed to watch keystore folder", "err", err)
|
if !os.IsNotExist(err) {
|
||||||
|
logger.Warn("Failed to watch keystore folder", "err", err)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -122,7 +125,7 @@ func (w *watcher) loop() {
|
|||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
log.Info("Filsystem watcher error", "err", err)
|
log.Info("Filesystem watcher error", "err", err)
|
||||||
case <-debounce.C:
|
case <-debounce.C:
|
||||||
w.ac.scanAccounts()
|
w.ac.scanAccounts()
|
||||||
rescanTriggered = false
|
rescanTriggered = false
|
||||||
|
|||||||
@@ -98,6 +98,9 @@ func NewManager(config *Config, backends ...Backend) *Manager {
|
|||||||
|
|
||||||
// Close terminates the account manager's internal notification processes.
|
// Close terminates the account manager's internal notification processes.
|
||||||
func (am *Manager) Close() error {
|
func (am *Manager) Close() error {
|
||||||
|
for _, w := range am.wallets {
|
||||||
|
w.Close()
|
||||||
|
}
|
||||||
errc := make(chan error)
|
errc := make(chan error)
|
||||||
am.quit <- errc
|
am.quit <- errc
|
||||||
return <-errc
|
return <-errc
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
## Preparing the smartcard
|
## Preparing the smartcard
|
||||||
|
|
||||||
**WARNING: FOILLOWING THESE INSTRUCTIONS WILL DESTROY THE MASTER KEY ON YOUR CARD. ONLY PROCEED IF NO FUNDS ARE ASSOCIATED WITH THESE ACCOUNTS**
|
**WARNING: FOLLOWING THESE INSTRUCTIONS WILL DESTROY THE MASTER KEY ON YOUR CARD. ONLY PROCEED IF NO FUNDS ARE ASSOCIATED WITH THESE ACCOUNTS**
|
||||||
|
|
||||||
You can use status' [keycard-cli](https://github.com/status-im/keycard-cli) and you should get _at least_ version 2.1.1 of their [smartcard application](https://github.com/status-im/status-keycard/releases/download/2.2.1/keycard_v2.2.1.cap)
|
You can use status' [keycard-cli](https://github.com/status-im/keycard-cli) and you should get _at least_ version 2.1.1 of their [smartcard application](https://github.com/status-im/status-keycard/releases/download/2.2.1/keycard_v2.2.1.cap)
|
||||||
|
|
||||||
|
|||||||
@@ -241,7 +241,7 @@ func (hub *Hub) refreshWallets() {
|
|||||||
card.Disconnect(pcsc.LeaveCard)
|
card.Disconnect(pcsc.LeaveCard)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// Card connected, start tracking in amongs the wallets
|
// Card connected, start tracking among the wallets
|
||||||
hub.wallets[reader] = wallet
|
hub.wallets[reader] = wallet
|
||||||
events = append(events, accounts.WalletEvent{Wallet: wallet, Kind: accounts.WalletArrived})
|
events = append(events, accounts.WalletEvent{Wallet: wallet, Kind: accounts.WalletArrived})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -72,11 +72,11 @@ func NewSecureChannelSession(card *pcsc.Card, keyData []byte) (*SecureChannelSes
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("could not unmarshal public key from card: %v", err)
|
return nil, fmt.Errorf("could not unmarshal public key from card: %v", err)
|
||||||
}
|
}
|
||||||
secret, _ := key.Curve.ScalarMult(cardPublic.X, cardPublic.Y, key.D.Bytes())
|
secret, _ := key.Curve.ScalarMult(cardPublic.X, cardPublic.Y, key.D.Bytes()) //nolint:all //TODO
|
||||||
return &SecureChannelSession{
|
return &SecureChannelSession{
|
||||||
card: card,
|
card: card,
|
||||||
secret: secret.Bytes(),
|
secret: secret.Bytes(),
|
||||||
publicKey: elliptic.Marshal(crypto.S256(), key.PublicKey.X, key.PublicKey.Y),
|
publicKey: elliptic.Marshal(crypto.S256(), key.PublicKey.X, key.PublicKey.Y), //nolint:all //TODO
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -776,16 +776,16 @@ func (w *Wallet) findAccountPath(account accounts.Account) (accounts.DerivationP
|
|||||||
return nil, fmt.Errorf("scheme %s does not match wallet scheme %s", account.URL.Scheme, w.Hub.scheme)
|
return nil, fmt.Errorf("scheme %s does not match wallet scheme %s", account.URL.Scheme, w.Hub.scheme)
|
||||||
}
|
}
|
||||||
|
|
||||||
parts := strings.SplitN(account.URL.Path, "/", 2)
|
url, path, found := strings.Cut(account.URL.Path, "/")
|
||||||
if len(parts) != 2 {
|
if !found {
|
||||||
return nil, fmt.Errorf("invalid URL format: %s", account.URL)
|
return nil, fmt.Errorf("invalid URL format: %s", account.URL)
|
||||||
}
|
}
|
||||||
|
|
||||||
if parts[0] != fmt.Sprintf("%x", w.PublicKey[1:3]) {
|
if url != fmt.Sprintf("%x", w.PublicKey[1:3]) {
|
||||||
return nil, fmt.Errorf("URL %s is not for this wallet", account.URL)
|
return nil, fmt.Errorf("URL %s is not for this wallet", account.URL)
|
||||||
}
|
}
|
||||||
|
|
||||||
return accounts.ParseDerivationPath(parts[1])
|
return accounts.ParseDerivationPath(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Session represents a secured communication session with the wallet.
|
// Session represents a secured communication session with the wallet.
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestURLParsing(t *testing.T) {
|
func TestURLParsing(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
url, err := parseURL("https://ethereum.org")
|
url, err := parseURL("https://ethereum.org")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
@@ -40,6 +41,7 @@ func TestURLParsing(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestURLString(t *testing.T) {
|
func TestURLString(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
url := URL{Scheme: "https", Path: "ethereum.org"}
|
url := URL{Scheme: "https", Path: "ethereum.org"}
|
||||||
if url.String() != "https://ethereum.org" {
|
if url.String() != "https://ethereum.org" {
|
||||||
t.Errorf("expected: %v, got: %v", "https://ethereum.org", url.String())
|
t.Errorf("expected: %v, got: %v", "https://ethereum.org", url.String())
|
||||||
@@ -52,10 +54,11 @@ func TestURLString(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestURLMarshalJSON(t *testing.T) {
|
func TestURLMarshalJSON(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
url := URL{Scheme: "https", Path: "ethereum.org"}
|
url := URL{Scheme: "https", Path: "ethereum.org"}
|
||||||
json, err := url.MarshalJSON()
|
json, err := url.MarshalJSON()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("unexpcted error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
if string(json) != "\"https://ethereum.org\"" {
|
if string(json) != "\"https://ethereum.org\"" {
|
||||||
t.Errorf("expected: %v, got: %v", "\"https://ethereum.org\"", string(json))
|
t.Errorf("expected: %v, got: %v", "\"https://ethereum.org\"", string(json))
|
||||||
@@ -63,10 +66,11 @@ func TestURLMarshalJSON(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestURLUnmarshalJSON(t *testing.T) {
|
func TestURLUnmarshalJSON(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
url := &URL{}
|
url := &URL{}
|
||||||
err := url.UnmarshalJSON([]byte("\"https://ethereum.org\""))
|
err := url.UnmarshalJSON([]byte("\"https://ethereum.org\""))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("unexpcted error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
if url.Scheme != "https" {
|
if url.Scheme != "https" {
|
||||||
t.Errorf("expected: %v, got: %v", "https", url.Scheme)
|
t.Errorf("expected: %v, got: %v", "https", url.Scheme)
|
||||||
@@ -77,6 +81,7 @@ func TestURLUnmarshalJSON(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestURLComparison(t *testing.T) {
|
func TestURLComparison(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
urlA URL
|
urlA URL
|
||||||
urlB URL
|
urlB URL
|
||||||
|
|||||||
@@ -279,7 +279,7 @@ func (w *ledgerDriver) ledgerDerive(derivationPath []uint32) (common.Address, er
|
|||||||
}
|
}
|
||||||
hexstr := reply[1 : 1+int(reply[0])]
|
hexstr := reply[1 : 1+int(reply[0])]
|
||||||
|
|
||||||
// Decode the hex sting into an Ethereum address and return
|
// Decode the hex string into an Ethereum address and return
|
||||||
var address common.Address
|
var address common.Address
|
||||||
if _, err = hex.Decode(address[:], hexstr); err != nil {
|
if _, err = hex.Decode(address[:], hexstr); err != nil {
|
||||||
return common.Address{}, err
|
return common.Address{}, err
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
// This file contains the implementation for interacting with the Trezor hardware
|
// This file contains the implementation for interacting with the Trezor hardware
|
||||||
// wallets. The wire protocol spec can be found on the SatoshiLabs website:
|
// wallets. The wire protocol spec can be found on the SatoshiLabs website:
|
||||||
// https://wiki.trezor.io/Developers_guide-Message_Workflows
|
// https://docs.trezor.io/trezor-firmware/common/message-workflows.html
|
||||||
|
|
||||||
// !!! STAHP !!!
|
// !!! STAHP !!!
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -483,6 +483,10 @@ func (w *wallet) Derive(path accounts.DerivationPath, pin bool) (accounts.Accoun
|
|||||||
w.stateLock.Lock()
|
w.stateLock.Lock()
|
||||||
defer w.stateLock.Unlock()
|
defer w.stateLock.Unlock()
|
||||||
|
|
||||||
|
if w.device == nil {
|
||||||
|
return accounts.Account{}, accounts.ErrWalletClosed
|
||||||
|
}
|
||||||
|
|
||||||
if _, ok := w.paths[address]; !ok {
|
if _, ok := w.paths[address]; !ok {
|
||||||
w.accounts = append(w.accounts, account)
|
w.accounts = append(w.accounts, account)
|
||||||
w.paths[address] = make(accounts.DerivationPath, len(path))
|
w.paths[address] = make(accounts.DerivationPath, len(path))
|
||||||
|
|||||||
@@ -54,4 +54,4 @@ for:
|
|||||||
- go run build/ci.go archive -arch %GETH_ARCH% -type zip -signer WINDOWS_SIGNING_KEY -upload gethstore/builds
|
- go run build/ci.go archive -arch %GETH_ARCH% -type zip -signer WINDOWS_SIGNING_KEY -upload gethstore/builds
|
||||||
- go run build/ci.go nsis -arch %GETH_ARCH% -signer WINDOWS_SIGNING_KEY -upload gethstore/builds
|
- go run build/ci.go nsis -arch %GETH_ARCH% -signer WINDOWS_SIGNING_KEY -upload gethstore/builds
|
||||||
test_script:
|
test_script:
|
||||||
- go run build/ci.go test -dlgo -arch %GETH_ARCH% -cc %GETH_CC%
|
- go run build/ci.go test -dlgo -arch %GETH_ARCH% -cc %GETH_CC% -short
|
||||||
|
|||||||
@@ -80,6 +80,7 @@ var (
|
|||||||
InvalidPayloadAttributes = &EngineAPIError{code: -38003, msg: "Invalid payload attributes"}
|
InvalidPayloadAttributes = &EngineAPIError{code: -38003, msg: "Invalid payload attributes"}
|
||||||
TooLargeRequest = &EngineAPIError{code: -38004, msg: "Too large request"}
|
TooLargeRequest = &EngineAPIError{code: -38004, msg: "Too large request"}
|
||||||
InvalidParams = &EngineAPIError{code: -32602, msg: "Invalid parameters"}
|
InvalidParams = &EngineAPIError{code: -32602, msg: "Invalid parameters"}
|
||||||
|
UnsupportedFork = &EngineAPIError{code: -38005, msg: "Unsupported fork"}
|
||||||
|
|
||||||
STATUS_INVALID = ForkChoiceResponse{PayloadStatus: PayloadStatusV1{Status: INVALID}, PayloadID: nil}
|
STATUS_INVALID = ForkChoiceResponse{PayloadStatus: PayloadStatusV1{Status: INVALID}, PayloadID: nil}
|
||||||
STATUS_SYNCING = ForkChoiceResponse{PayloadStatus: PayloadStatusV1{Status: SYNCING}, PayloadID: nil}
|
STATUS_SYNCING = ForkChoiceResponse{PayloadStatus: PayloadStatusV1{Status: SYNCING}, PayloadID: nil}
|
||||||
|
|||||||
@@ -20,12 +20,14 @@ func (p PayloadAttributes) MarshalJSON() ([]byte, error) {
|
|||||||
Random common.Hash `json:"prevRandao" gencodec:"required"`
|
Random common.Hash `json:"prevRandao" gencodec:"required"`
|
||||||
SuggestedFeeRecipient common.Address `json:"suggestedFeeRecipient" gencodec:"required"`
|
SuggestedFeeRecipient common.Address `json:"suggestedFeeRecipient" gencodec:"required"`
|
||||||
Withdrawals []*types.Withdrawal `json:"withdrawals"`
|
Withdrawals []*types.Withdrawal `json:"withdrawals"`
|
||||||
|
BeaconRoot *common.Hash `json:"parentBeaconBlockRoot"`
|
||||||
}
|
}
|
||||||
var enc PayloadAttributes
|
var enc PayloadAttributes
|
||||||
enc.Timestamp = hexutil.Uint64(p.Timestamp)
|
enc.Timestamp = hexutil.Uint64(p.Timestamp)
|
||||||
enc.Random = p.Random
|
enc.Random = p.Random
|
||||||
enc.SuggestedFeeRecipient = p.SuggestedFeeRecipient
|
enc.SuggestedFeeRecipient = p.SuggestedFeeRecipient
|
||||||
enc.Withdrawals = p.Withdrawals
|
enc.Withdrawals = p.Withdrawals
|
||||||
|
enc.BeaconRoot = p.BeaconRoot
|
||||||
return json.Marshal(&enc)
|
return json.Marshal(&enc)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -36,6 +38,7 @@ func (p *PayloadAttributes) UnmarshalJSON(input []byte) error {
|
|||||||
Random *common.Hash `json:"prevRandao" gencodec:"required"`
|
Random *common.Hash `json:"prevRandao" gencodec:"required"`
|
||||||
SuggestedFeeRecipient *common.Address `json:"suggestedFeeRecipient" gencodec:"required"`
|
SuggestedFeeRecipient *common.Address `json:"suggestedFeeRecipient" gencodec:"required"`
|
||||||
Withdrawals []*types.Withdrawal `json:"withdrawals"`
|
Withdrawals []*types.Withdrawal `json:"withdrawals"`
|
||||||
|
BeaconRoot *common.Hash `json:"parentBeaconBlockRoot"`
|
||||||
}
|
}
|
||||||
var dec PayloadAttributes
|
var dec PayloadAttributes
|
||||||
if err := json.Unmarshal(input, &dec); err != nil {
|
if err := json.Unmarshal(input, &dec); err != nil {
|
||||||
@@ -56,5 +59,8 @@ func (p *PayloadAttributes) UnmarshalJSON(input []byte) error {
|
|||||||
if dec.Withdrawals != nil {
|
if dec.Withdrawals != nil {
|
||||||
p.Withdrawals = dec.Withdrawals
|
p.Withdrawals = dec.Withdrawals
|
||||||
}
|
}
|
||||||
|
if dec.BeaconRoot != nil {
|
||||||
|
p.BeaconRoot = dec.BeaconRoot
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,11 +18,13 @@ func (e ExecutionPayloadEnvelope) MarshalJSON() ([]byte, error) {
|
|||||||
ExecutionPayload *ExecutableData `json:"executionPayload" gencodec:"required"`
|
ExecutionPayload *ExecutableData `json:"executionPayload" gencodec:"required"`
|
||||||
BlockValue *hexutil.Big `json:"blockValue" gencodec:"required"`
|
BlockValue *hexutil.Big `json:"blockValue" gencodec:"required"`
|
||||||
BlobsBundle *BlobsBundleV1 `json:"blobsBundle"`
|
BlobsBundle *BlobsBundleV1 `json:"blobsBundle"`
|
||||||
|
Override bool `json:"shouldOverrideBuilder"`
|
||||||
}
|
}
|
||||||
var enc ExecutionPayloadEnvelope
|
var enc ExecutionPayloadEnvelope
|
||||||
enc.ExecutionPayload = e.ExecutionPayload
|
enc.ExecutionPayload = e.ExecutionPayload
|
||||||
enc.BlockValue = (*hexutil.Big)(e.BlockValue)
|
enc.BlockValue = (*hexutil.Big)(e.BlockValue)
|
||||||
enc.BlobsBundle = e.BlobsBundle
|
enc.BlobsBundle = e.BlobsBundle
|
||||||
|
enc.Override = e.Override
|
||||||
return json.Marshal(&enc)
|
return json.Marshal(&enc)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -32,6 +34,7 @@ func (e *ExecutionPayloadEnvelope) UnmarshalJSON(input []byte) error {
|
|||||||
ExecutionPayload *ExecutableData `json:"executionPayload" gencodec:"required"`
|
ExecutionPayload *ExecutableData `json:"executionPayload" gencodec:"required"`
|
||||||
BlockValue *hexutil.Big `json:"blockValue" gencodec:"required"`
|
BlockValue *hexutil.Big `json:"blockValue" gencodec:"required"`
|
||||||
BlobsBundle *BlobsBundleV1 `json:"blobsBundle"`
|
BlobsBundle *BlobsBundleV1 `json:"blobsBundle"`
|
||||||
|
Override *bool `json:"shouldOverrideBuilder"`
|
||||||
}
|
}
|
||||||
var dec ExecutionPayloadEnvelope
|
var dec ExecutionPayloadEnvelope
|
||||||
if err := json.Unmarshal(input, &dec); err != nil {
|
if err := json.Unmarshal(input, &dec); err != nil {
|
||||||
@@ -48,5 +51,8 @@ func (e *ExecutionPayloadEnvelope) UnmarshalJSON(input []byte) error {
|
|||||||
if dec.BlobsBundle != nil {
|
if dec.BlobsBundle != nil {
|
||||||
e.BlobsBundle = dec.BlobsBundle
|
e.BlobsBundle = dec.BlobsBundle
|
||||||
}
|
}
|
||||||
|
if dec.Override != nil {
|
||||||
|
e.Override = *dec.Override
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,10 +23,19 @@ import (
|
|||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/crypto/kzg4844"
|
|
||||||
"github.com/ethereum/go-ethereum/trie"
|
"github.com/ethereum/go-ethereum/trie"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// PayloadVersion denotes the version of PayloadAttributes used to request the
|
||||||
|
// building of the payload to commence.
|
||||||
|
type PayloadVersion byte
|
||||||
|
|
||||||
|
var (
|
||||||
|
PayloadV1 PayloadVersion = 0x1
|
||||||
|
PayloadV2 PayloadVersion = 0x2
|
||||||
|
PayloadV3 PayloadVersion = 0x3
|
||||||
|
)
|
||||||
|
|
||||||
//go:generate go run github.com/fjl/gencodec -type PayloadAttributes -field-override payloadAttributesMarshaling -out gen_blockparams.go
|
//go:generate go run github.com/fjl/gencodec -type PayloadAttributes -field-override payloadAttributesMarshaling -out gen_blockparams.go
|
||||||
|
|
||||||
// PayloadAttributes describes the environment context in which a block should
|
// PayloadAttributes describes the environment context in which a block should
|
||||||
@@ -36,6 +45,7 @@ type PayloadAttributes struct {
|
|||||||
Random common.Hash `json:"prevRandao" gencodec:"required"`
|
Random common.Hash `json:"prevRandao" gencodec:"required"`
|
||||||
SuggestedFeeRecipient common.Address `json:"suggestedFeeRecipient" gencodec:"required"`
|
SuggestedFeeRecipient common.Address `json:"suggestedFeeRecipient" gencodec:"required"`
|
||||||
Withdrawals []*types.Withdrawal `json:"withdrawals"`
|
Withdrawals []*types.Withdrawal `json:"withdrawals"`
|
||||||
|
BeaconRoot *common.Hash `json:"parentBeaconBlockRoot"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// JSON type overrides for PayloadAttributes.
|
// JSON type overrides for PayloadAttributes.
|
||||||
@@ -86,6 +96,7 @@ type ExecutionPayloadEnvelope struct {
|
|||||||
ExecutionPayload *ExecutableData `json:"executionPayload" gencodec:"required"`
|
ExecutionPayload *ExecutableData `json:"executionPayload" gencodec:"required"`
|
||||||
BlockValue *big.Int `json:"blockValue" gencodec:"required"`
|
BlockValue *big.Int `json:"blockValue" gencodec:"required"`
|
||||||
BlobsBundle *BlobsBundleV1 `json:"blobsBundle"`
|
BlobsBundle *BlobsBundleV1 `json:"blobsBundle"`
|
||||||
|
Override bool `json:"shouldOverrideBuilder"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type BlobsBundleV1 struct {
|
type BlobsBundleV1 struct {
|
||||||
@@ -114,6 +125,21 @@ type TransitionConfigurationV1 struct {
|
|||||||
// PayloadID is an identifier of the payload build process
|
// PayloadID is an identifier of the payload build process
|
||||||
type PayloadID [8]byte
|
type PayloadID [8]byte
|
||||||
|
|
||||||
|
// Version returns the payload version associated with the identifier.
|
||||||
|
func (b PayloadID) Version() PayloadVersion {
|
||||||
|
return PayloadVersion(b[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
// Is returns whether the identifier matches any of provided payload versions.
|
||||||
|
func (b PayloadID) Is(versions ...PayloadVersion) bool {
|
||||||
|
for _, v := range versions {
|
||||||
|
if v == b.Version() {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
func (b PayloadID) String() string {
|
func (b PayloadID) String() string {
|
||||||
return hexutil.Encode(b[:])
|
return hexutil.Encode(b[:])
|
||||||
}
|
}
|
||||||
@@ -172,7 +198,7 @@ func decodeTransactions(enc [][]byte) ([]*types.Transaction, error) {
|
|||||||
// and that the blockhash of the constructed block matches the parameters. Nil
|
// and that the blockhash of the constructed block matches the parameters. Nil
|
||||||
// Withdrawals value will propagate through the returned block. Empty
|
// Withdrawals value will propagate through the returned block. Empty
|
||||||
// Withdrawals value must be passed via non-nil, length 0 value in params.
|
// Withdrawals value must be passed via non-nil, length 0 value in params.
|
||||||
func ExecutableDataToBlock(params ExecutableData, versionedHashes []common.Hash) (*types.Block, error) {
|
func ExecutableDataToBlock(params ExecutableData, versionedHashes []common.Hash, beaconRoot *common.Hash) (*types.Block, error) {
|
||||||
txs, err := decodeTransactions(params.Transactions)
|
txs, err := decodeTransactions(params.Transactions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -208,24 +234,25 @@ func ExecutableDataToBlock(params ExecutableData, versionedHashes []common.Hash)
|
|||||||
withdrawalsRoot = &h
|
withdrawalsRoot = &h
|
||||||
}
|
}
|
||||||
header := &types.Header{
|
header := &types.Header{
|
||||||
ParentHash: params.ParentHash,
|
ParentHash: params.ParentHash,
|
||||||
UncleHash: types.EmptyUncleHash,
|
UncleHash: types.EmptyUncleHash,
|
||||||
Coinbase: params.FeeRecipient,
|
Coinbase: params.FeeRecipient,
|
||||||
Root: params.StateRoot,
|
Root: params.StateRoot,
|
||||||
TxHash: types.DeriveSha(types.Transactions(txs), trie.NewStackTrie(nil)),
|
TxHash: types.DeriveSha(types.Transactions(txs), trie.NewStackTrie(nil)),
|
||||||
ReceiptHash: params.ReceiptsRoot,
|
ReceiptHash: params.ReceiptsRoot,
|
||||||
Bloom: types.BytesToBloom(params.LogsBloom),
|
Bloom: types.BytesToBloom(params.LogsBloom),
|
||||||
Difficulty: common.Big0,
|
Difficulty: common.Big0,
|
||||||
Number: new(big.Int).SetUint64(params.Number),
|
Number: new(big.Int).SetUint64(params.Number),
|
||||||
GasLimit: params.GasLimit,
|
GasLimit: params.GasLimit,
|
||||||
GasUsed: params.GasUsed,
|
GasUsed: params.GasUsed,
|
||||||
Time: params.Timestamp,
|
Time: params.Timestamp,
|
||||||
BaseFee: params.BaseFeePerGas,
|
BaseFee: params.BaseFeePerGas,
|
||||||
Extra: params.ExtraData,
|
Extra: params.ExtraData,
|
||||||
MixDigest: params.Random,
|
MixDigest: params.Random,
|
||||||
WithdrawalsHash: withdrawalsRoot,
|
WithdrawalsHash: withdrawalsRoot,
|
||||||
ExcessBlobGas: params.ExcessBlobGas,
|
ExcessBlobGas: params.ExcessBlobGas,
|
||||||
BlobGasUsed: params.BlobGasUsed,
|
BlobGasUsed: params.BlobGasUsed,
|
||||||
|
ParentBeaconRoot: beaconRoot,
|
||||||
}
|
}
|
||||||
block := types.NewBlockWithHeader(header).WithBody(txs, nil /* uncles */).WithWithdrawals(params.Withdrawals)
|
block := types.NewBlockWithHeader(header).WithBody(txs, nil /* uncles */).WithWithdrawals(params.Withdrawals)
|
||||||
if block.Hash() != params.BlockHash {
|
if block.Hash() != params.BlockHash {
|
||||||
@@ -236,7 +263,7 @@ func ExecutableDataToBlock(params ExecutableData, versionedHashes []common.Hash)
|
|||||||
|
|
||||||
// BlockToExecutableData constructs the ExecutableData structure by filling the
|
// BlockToExecutableData constructs the ExecutableData structure by filling the
|
||||||
// fields from the given block. It assumes the given block is post-merge block.
|
// fields from the given block. It assumes the given block is post-merge block.
|
||||||
func BlockToExecutableData(block *types.Block, fees *big.Int, blobs []kzg4844.Blob, commitments []kzg4844.Commitment, proofs []kzg4844.Proof) *ExecutionPayloadEnvelope {
|
func BlockToExecutableData(block *types.Block, fees *big.Int, sidecars types.BlobSidecars) *ExecutionPayloadEnvelope {
|
||||||
data := &ExecutableData{
|
data := &ExecutableData{
|
||||||
BlockHash: block.Hash(),
|
BlockHash: block.Hash(),
|
||||||
ParentHash: block.ParentHash(),
|
ParentHash: block.ParentHash(),
|
||||||
@@ -256,17 +283,19 @@ func BlockToExecutableData(block *types.Block, fees *big.Int, blobs []kzg4844.Bl
|
|||||||
BlobGasUsed: block.BlobGasUsed(),
|
BlobGasUsed: block.BlobGasUsed(),
|
||||||
ExcessBlobGas: block.ExcessBlobGas(),
|
ExcessBlobGas: block.ExcessBlobGas(),
|
||||||
}
|
}
|
||||||
blobsBundle := BlobsBundleV1{
|
bundle := BlobsBundleV1{
|
||||||
Commitments: make([]hexutil.Bytes, 0),
|
Commitments: make([]hexutil.Bytes, 0),
|
||||||
Blobs: make([]hexutil.Bytes, 0),
|
Blobs: make([]hexutil.Bytes, 0),
|
||||||
Proofs: make([]hexutil.Bytes, 0),
|
Proofs: make([]hexutil.Bytes, 0),
|
||||||
}
|
}
|
||||||
for i := range blobs {
|
for _, sidecar := range sidecars {
|
||||||
blobsBundle.Blobs = append(blobsBundle.Blobs, hexutil.Bytes(blobs[i][:]))
|
for j := range sidecar.Blobs {
|
||||||
blobsBundle.Commitments = append(blobsBundle.Commitments, hexutil.Bytes(commitments[i][:]))
|
bundle.Blobs = append(bundle.Blobs, hexutil.Bytes(sidecar.Blobs[j][:]))
|
||||||
blobsBundle.Proofs = append(blobsBundle.Proofs, hexutil.Bytes(proofs[i][:]))
|
bundle.Commitments = append(bundle.Commitments, hexutil.Bytes(sidecar.Commitments[j][:]))
|
||||||
|
bundle.Proofs = append(bundle.Proofs, hexutil.Bytes(sidecar.Proofs[j][:]))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return &ExecutionPayloadEnvelope{ExecutionPayload: data, BlockValue: fees, BlobsBundle: &blobsBundle}
|
return &ExecutionPayloadEnvelope{ExecutionPayload: data, BlockValue: fees, BlobsBundle: &bundle, Override: false}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExecutionPayloadBodyV1 is used in the response to GetPayloadBodiesByHashV1 and GetPayloadBodiesByRangeV1
|
// ExecutionPayloadBodyV1 is used in the response to GetPayloadBodiesByHashV1 and GetPayloadBodiesByRangeV1
|
||||||
@@ -274,3 +303,21 @@ type ExecutionPayloadBodyV1 struct {
|
|||||||
TransactionData []hexutil.Bytes `json:"transactions"`
|
TransactionData []hexutil.Bytes `json:"transactions"`
|
||||||
Withdrawals []*types.Withdrawal `json:"withdrawals"`
|
Withdrawals []*types.Withdrawal `json:"withdrawals"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Client identifiers to support ClientVersionV1.
|
||||||
|
const (
|
||||||
|
ClientCode = "GE"
|
||||||
|
ClientName = "go-ethereum"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ClientVersionV1 contains information which identifies a client implementation.
|
||||||
|
type ClientVersionV1 struct {
|
||||||
|
Code string `json:"code"`
|
||||||
|
Name string `json:"clientName"`
|
||||||
|
Version string `json:"version"`
|
||||||
|
Commit string `json:"commit"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *ClientVersionV1) String() string {
|
||||||
|
return fmt.Sprintf("%s-%s-%s-%s", v.Code, v.Name, v.Version, v.Commit)
|
||||||
|
}
|
||||||
|
|||||||
@@ -25,6 +25,24 @@ import (
|
|||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// BootstrapData contains a sync committee where light sync can be started,
|
||||||
|
// together with a proof through a beacon header and corresponding state.
|
||||||
|
// Note: BootstrapData is fetched from a server based on a known checkpoint hash.
|
||||||
|
type BootstrapData struct {
|
||||||
|
Header Header
|
||||||
|
CommitteeRoot common.Hash
|
||||||
|
Committee *SerializedSyncCommittee `rlp:"-"`
|
||||||
|
CommitteeBranch merkle.Values
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate verifies the proof included in BootstrapData.
|
||||||
|
func (c *BootstrapData) Validate() error {
|
||||||
|
if c.CommitteeRoot != c.Committee.Root() {
|
||||||
|
return errors.New("wrong committee root")
|
||||||
|
}
|
||||||
|
return merkle.VerifyProof(c.Header.StateRoot, params.StateIndexSyncCommittee, c.CommitteeBranch, merkle.Value(c.CommitteeRoot))
|
||||||
|
}
|
||||||
|
|
||||||
// LightClientUpdate is a proof of the next sync committee root based on a header
|
// LightClientUpdate is a proof of the next sync committee root based on a header
|
||||||
// signed by the sync committee of the given period. Optionally, the update can
|
// signed by the sync committee of the given period. Optionally, the update can
|
||||||
// prove quasi-finality by the signed header referring to a previous, finalized
|
// prove quasi-finality by the signed header referring to a previous, finalized
|
||||||
@@ -1,69 +1,65 @@
|
|||||||
# This file contains sha256 checksums of optional build dependencies.
|
# This file contains sha256 checksums of optional build dependencies.
|
||||||
|
|
||||||
2c5ee9c9ec1e733b0dbbc2bdfed3f62306e51d8172bf38f4f4e542b27520f597 go1.20.7.src.tar.gz
|
# version:spec-tests 2.1.0
|
||||||
785170eab380a8985d53896808b0a71336d0ea60e0a26099b4ccec77798b1cf4 go1.20.7.darwin-amd64.tar.gz
|
# https://github.com/ethereum/execution-spec-tests/releases
|
||||||
eea1e7e4c2f75c72629050e6a6c7c46c446d64056732a7787fb3ba16ace1982e go1.20.7.darwin-arm64.tar.gz
|
# https://github.com/ethereum/execution-spec-tests/releases/download/v2.1.0/
|
||||||
d8cff0357ac24eb06f3f280535397eeaacf95611d29f9b2abc3060f3d6dce3b4 go1.20.7.freebsd-386.tar.gz
|
ca89c76851b0900bfcc3cbb9a26cbece1f3d7c64a3bed38723e914713290df6c fixtures_develop.tar.gz
|
||||||
26918dcebf474a9e81ccf9f648cdf36968dfb76b481518cf615d78455dda4416 go1.20.7.freebsd-amd64.tar.gz
|
|
||||||
ddb48145f05bda2f4617a22c979d4e94b22802cdb1a1fde1b1974e733b26f091 go1.20.7.linux-386.tar.gz
|
|
||||||
f0a87f1bcae91c4b69f8dc2bc6d7e6bfcd7524fceec130af525058c0c17b1b44 go1.20.7.linux-amd64.tar.gz
|
|
||||||
44781ae3b153c3b07651d93b6bc554e835a36e2d72a696281c1e4dad9efffe43 go1.20.7.linux-arm64.tar.gz
|
|
||||||
7cc231b415b94f2f7065870a73f67dd2b0ec12b5a98052b7ee0121c42bc04f8d go1.20.7.linux-armv6l.tar.gz
|
|
||||||
6318a1db307c12b8afe68808bd6fae4fba1e558a85b958216096869ed506dcb3 go1.20.7.linux-ppc64le.tar.gz
|
|
||||||
26aea2ede8722ceecbd9db883328a8d963136fd96c11dacc356c44c4c19c6515 go1.20.7.linux-s390x.tar.gz
|
|
||||||
5b0ef6f58d3e04d6cc003aa98e9172f41ba9e091b1c98e7339b41c4c87fb78a1 go1.20.7.windows-386.zip
|
|
||||||
736dc6c7fcab1c96b682c8c93e38d7e371e62a17d34cb2c37d451a1147f66af9 go1.20.7.windows-amd64.zip
|
|
||||||
fc6f79c1e1ed9e506c65f2112ac4e387479916f1accb0d046a6a19ff6938baa5 go1.20.7.windows-arm64.zip
|
|
||||||
|
|
||||||
000d4d58f1e25323aaf0da20b337d059d401c8c1fb31cef92ce50ef35c05e877 golangci-lint-1.52.2-linux-ppc64le.deb
|
# version:golang 1.21.6
|
||||||
0970b2e3ecc20003a0fc78b078623ab27c61f0f809a44288e2cc438bfbbf5616 golangci-lint-1.52.2-linux-s390x.deb
|
# https://go.dev/dl/
|
||||||
0bfe9b51f68a33cc4e43139151d8032b57b15e61a19f5a7554b687a3fa166ab8 golangci-lint-1.52.2-netbsd-armv7.tar.gz
|
124926a62e45f78daabbaedb9c011d97633186a33c238ffc1e25320c02046248 go1.21.6.src.tar.gz
|
||||||
0e4e24085d364f4e03752c060d5f37b5ead52acd62f07392f4c9022515e0ecd8 golangci-lint-1.52.2-linux-armv7.rpm
|
31d6ecca09010ab351e51343a5af81d678902061fee871f912bdd5ef4d778850 go1.21.6.darwin-amd64.tar.gz
|
||||||
0f19ad6c037d45867f4978287a7a6d78bc761daf8e6cb3a5e6af86d5714b0258 golangci-lint-1.52.2-linux-armv6.tar.gz
|
0ff541fb37c38e5e5c5bcecc8f4f43c5ffd5e3a6c33a5d3e4003ded66fcfb331 go1.21.6.darwin-arm64.tar.gz
|
||||||
1506b19f3f0410f6d85d1e339a47fcc84646d552516c0f429dc8cd7f34b4069a golangci-lint-1.52.2-windows-armv6.zip
|
a1d1a149b34bf0f53965a237682c6da1140acabb131bf0e597240e4a140b0e5e go1.21.6.freebsd-386.tar.gz
|
||||||
1cc68baa226e186c15c5514a6e93b1cc8d47ff06aaf1a395b8266434cb01df29 golangci-lint-1.52.2-linux-386.rpm
|
de59e1217e4398b1522eed8dddabab2fa1b97aecbdca3af08e34832b4f0e3f81 go1.21.6.freebsd-amd64.tar.gz
|
||||||
1d23661087ae686563e40d3b1e33f309dd3b4ba7d1c7e571ca7723f77a52a9e4 golangci-lint-1.52.2-linux-s390x.rpm
|
05d09041b5a1193c14e4b2db3f7fcc649b236c567f5eb93305c537851b72dd95 go1.21.6.linux-386.tar.gz
|
||||||
227673a18d21b428f1768bb8ee46e38c36a0f002960bc6211ef6137b85d03f52 golangci-lint-1.52.2-freebsd-armv7.tar.gz
|
3f934f40ac360b9c01f616a9aa1796d227d8b0328bf64cb045c7b8c4ee9caea4 go1.21.6.linux-amd64.tar.gz
|
||||||
24f0272e5741c05c59e7162b7ff0258cfa6beb0d9265bd87c386fe80ac25135d golangci-lint-1.52.2-linux-mips64.deb
|
e2e8aa88e1b5170a0d495d7d9c766af2b2b6c6925a8f8956d834ad6b4cacbd9a go1.21.6.linux-arm64.tar.gz
|
||||||
3abc8ad30b336ccbe3c5e3c65fa146f5b12d8e81e644345fa8d51cdbaa8cb570 golangci-lint-1.52.2-netbsd-amd64.tar.gz
|
6a8eda6cc6a799ff25e74ce0c13fdc1a76c0983a0bb07c789a2a3454bf6ec9b2 go1.21.6.linux-armv6l.tar.gz
|
||||||
40a2645b4c7bd94c16618eb0f12b32cd54c17e5620f761cf477b256d3622f299 golangci-lint-1.52.2-windows-386.zip
|
e872b1e9a3f2f08fd4554615a32ca9123a4ba877ab6d19d36abc3424f86bc07f go1.21.6.linux-ppc64le.tar.gz
|
||||||
40b40002e07db81628d94108265525052c58fc9ce358bef26a36d27f0aea3d87 golangci-lint-1.52.2-windows-amd64.zip
|
92894d0f732d3379bc414ffdd617eaadad47e1d72610e10d69a1156db03fc052 go1.21.6.linux-s390x.tar.gz
|
||||||
41e936b62ba4fc66c02daf6fa9cf74213bc2220745c7a796acbe197c05ed26bb golangci-lint-1.52.2-netbsd-armv6.tar.gz
|
65b38857135cf45c80e1d267e0ce4f80fe149326c68835217da4f2da9b7943fe go1.21.6.windows-386.zip
|
||||||
4bcbb4cf34bf3c8ae1ca880d12516a999499189326621599f8362ededd6e4229 golangci-lint-1.52.2-linux-riscv64.tar.gz
|
27ac9dd6e66fb3fd0acfa6792ff053c86e7d2c055b022f4b5d53bfddec9e3301 go1.21.6.windows-amd64.zip
|
||||||
4edb83f1433f7c57f06f79a7fc30bf3f920c1f86c334e481661ac6627d80293f golangci-lint-1.52.2-linux-arm64.deb
|
b93aff8f3c882c764c66a39b7a1483b0460e051e9992bf3435479129e5051bcd go1.21.6.windows-arm64.zip
|
||||||
50d662e86d094dbad6634d086eca4f670ffa8ea7142508d8da357a2d750ac21a golangci-lint-1.52.2-linux-armv7.tar.gz
|
|
||||||
6891597bedbcd7e530d08ed198bab7eeb9b23f3f8161dc6e87505b783cb11593 golangci-lint-1.52.2-windows-arm64.zip
|
# version:golangci 1.55.2
|
||||||
6d79f4f3448b70e83952e746fcb9e251c6ba94ec2790a912806cc1704ade4d64 golangci-lint-1.52.2-linux-mips64.rpm
|
# https://github.com/golangci/golangci-lint/releases/
|
||||||
6de51ae05d39002421caf6049e0dd0014a2f10961471c5547c905d33d8e6adf1 golangci-lint-1.52.2-linux-armv6.deb
|
# https://github.com/golangci/golangci-lint/releases/download/v1.55.2/
|
||||||
715dc0f0cf3538c3b2c75f084dde8dcdc3485b3494f42a6d0d9c0dc61e62b5a8 golangci-lint-1.52.2-linux-s390x.tar.gz
|
632e96e6d5294fbbe7b2c410a49c8fa01c60712a0af85a567de85bcc1623ea21 golangci-lint-1.55.2-darwin-amd64.tar.gz
|
||||||
7c559332a97ee49b80427aba5a7122e17cac18c57e700f48e6db5ffcbbb61b2b golangci-lint-1.52.2-linux-arm64.rpm
|
234463f059249f82045824afdcdd5db5682d0593052f58f6a3039a0a1c3899f6 golangci-lint-1.55.2-darwin-arm64.tar.gz
|
||||||
81201bb5f19897fefb4380af2e187a0133dc5efda22254698c063cc36a601f43 golangci-lint-1.52.2-linux-386.deb
|
2bdd105e2d4e003a9058c33a22bb191a1e0f30fa0790acca0d8fbffac1d6247c golangci-lint-1.55.2-freebsd-386.tar.gz
|
||||||
89e523d45883903cfc472ab65621073f850abd4ffbb7720bbdd7ba66ee490bc8 golangci-lint-1.52.2-darwin-arm64.tar.gz
|
e75056e8b082386676ce23eba455cf893931a792c0d87e1e3743c0aec33c7fb5 golangci-lint-1.55.2-freebsd-amd64.tar.gz
|
||||||
8d60d63eee38f8de679e57b1a781de32987152f004f852f20cd47baa4c582209 golangci-lint-1.52.2-linux-mips64le.rpm
|
5789b933facaf6136bd23f1d50add67b79bbcf8dfdfc9069a37f729395940a66 golangci-lint-1.55.2-freebsd-armv6.tar.gz
|
||||||
9e22df0516cbd847910f353d92245e58eab2b6edacc669646bfa06eb032a65a3 golangci-lint-1.52.2-linux-riscv64.deb
|
7f21ab1008d05f32c954f99470fc86a83a059e530fe2add1d0b7d8ed4d8992a7 golangci-lint-1.55.2-freebsd-armv7.tar.gz
|
||||||
a1a74747a196d4ccd2394ea8a461508eb2edf1eb5a88010611debf572991961d golangci-lint-1.52.2-linux-loong64.tar.gz
|
33ab06139b9219a28251f10821da94423db30285cc2af97494cbb2a281927de9 golangci-lint-1.55.2-illumos-amd64.tar.gz
|
||||||
a7f076d0fb50e0f5bc24d0f3b2567f2cfe864441e6ad20323189b7fde7cc065d golangci-lint-1.52.2-freebsd-386.tar.gz
|
57ce6f8ce3ad6ee45d7cc3d9a047545a851c2547637834a3fcb086c7b40b1e6b golangci-lint-1.55.2-linux-386.tar.gz
|
||||||
abc100851a59cbcea2a7e9ff5ad2974a43270135520aeac9a302ca6c712a41e1 golangci-lint-1.52.2-linux-loong64.rpm
|
ca21c961a33be3bc15e4292dc40c98c8dcc5463a7b6768a3afc123761630c09c golangci-lint-1.55.2-linux-amd64.tar.gz
|
||||||
adf11a1f7f43b5a431c19cccea260e6205e2e2b42a2d2d450e31c287fec199f2 golangci-lint-1.52.2-linux-amd64.rpm
|
8eb0cee9b1dbf0eaa49871798c7f8a5b35f2960c52d776a5f31eb7d886b92746 golangci-lint-1.55.2-linux-arm64.tar.gz
|
||||||
b2249e43e1624486398f41700dbe4094a4222bf50b2b1b3a740323adb9a1b66f golangci-lint-1.52.2-linux-386.tar.gz
|
3195f3e0f37d353fd5bd415cabcd4e263f5c29d3d0ffb176c26ff3d2c75eb3bb golangci-lint-1.55.2-linux-armv6.tar.gz
|
||||||
b8e81bf979dc8bf226cb592eb78c1792f1018c3dea1bbeb11517efc4cc3301bb golangci-lint-1.52.2-windows-armv7.zip
|
c823ee36eb1a719e171de1f2f5ca3068033dce8d9817232fd10ed71fd6650406 golangci-lint-1.55.2-linux-armv7.tar.gz
|
||||||
bb9a6a0aabe39fb3d581cc200c639ce6598821a53b4d16ec59366c65f4cc2960 golangci-lint-1.52.2-source.tar.gz
|
758a5d2a356dc494bd13ed4c0d4bf5a54a4dc91267ea5ecdd87b86c7ca0624e7 golangci-lint-1.55.2-linux-loong64.tar.gz
|
||||||
c152280b2e61c202614c1c476cf4458922cda0d2781e4492be2c22d45655cae0 golangci-lint-1.52.2-freebsd-armv6.tar.gz
|
2c7b9abdce7cae802a67d583cd7c6dca520bff6d0e17c8535a918e2f2b437aa0 golangci-lint-1.55.2-linux-mips64.tar.gz
|
||||||
c8bf25c0bca142638ce4bfc921bf23d23038818d57658d69aa4a9947d514d48f golangci-lint-1.52.2-linux-ppc64le.rpm
|
024e0a15b85352cc27271285526e16a4ab66d3e67afbbe446c9808c06cb8dbed golangci-lint-1.55.2-linux-mips64le.tar.gz
|
||||||
c9cf72d12058a131746edd409ed94ccd578fbd178899d1ed41ceae3ce5f54501 golangci-lint-1.52.2-linux-amd64.tar.gz
|
6b00f89ba5506c1de1efdd9fa17c54093013a294fefd8b9b31534db626a672ee golangci-lint-1.55.2-linux-ppc64le.tar.gz
|
||||||
d03f2b331b5139eddea5db2b49066d10a90094747b08d72d7b2d61cf91c79a27 golangci-lint-1.52.2-linux-mips64le.tar.gz
|
0faa0d047d9bf7b703ed3ea65b6117043c93504f9ca1de25ae929d3901c73d4a golangci-lint-1.55.2-linux-riscv64.tar.gz
|
||||||
d609c1d49591d714148e1f8c8b5ae9f9565c601aeabc44a5a53ba44b0eb99f36 golangci-lint-1.52.2-linux-riscv64.rpm
|
30dec9b22e7d5bb4e9d5ccea96da20f71cd7db3c8cf30b8ddc7cb9174c4d742a golangci-lint-1.55.2-linux-s390x.tar.gz
|
||||||
d679adad29603ed7549372b64077cccad784e404deffe5c1e9495a06659cff33 golangci-lint-1.52.2-linux-mips64.tar.gz
|
5a0ede48f79ad707902fdb29be8cd2abd8302dc122b65ebae3fdfc86751c7698 golangci-lint-1.55.2-netbsd-386.tar.gz
|
||||||
d91e8cb60920cf0e46958ed917fcdd059738c00d162189c2e878424ffc8ada75 golangci-lint-1.52.2-linux-ppc64le.tar.gz
|
95af20a2e617126dd5b08122ece7819101070e1582a961067ce8c41172f901ad golangci-lint-1.55.2-netbsd-amd64.tar.gz
|
||||||
d9b5820b491e317fb1360775441d68bd3dc2f303439da5b6d536df23977e28c9 golangci-lint-1.52.2-freebsd-amd64.tar.gz
|
94fb7dacb7527847cc95d7120904e19a2a0a81a0d50d61766c9e0251da72ab9d golangci-lint-1.55.2-netbsd-armv6.tar.gz
|
||||||
ddeae781cf07c016898efd80eaed6853a91bfaf1f22c08fbbf5cf08a573b98c4 golangci-lint-1.52.2-linux-loong64.deb
|
ca906bce5fee9619400e4a321c56476fe4a4efb6ac4fc989d340eb5563348873 golangci-lint-1.55.2-netbsd-armv7.tar.gz
|
||||||
dfc5e755cfa95381f61f736780ff736a5b6c9cbccc88140348986c166d484f85 golangci-lint-1.52.2-linux-amd64.deb
|
45b442f69fc8915c4500201c0247b7f3f69544dbc9165403a61f9095f2c57355 golangci-lint-1.55.2-windows-386.zip
|
||||||
e57f2599de73c4da1d36d5255b9baec63f448b3d7fb726ebd3cd64dabbd3ee4a golangci-lint-1.52.2-darwin-amd64.tar.gz
|
f57d434d231d43417dfa631587522f8c1991220b43c8ffadb9c7bd279508bf81 golangci-lint-1.55.2-windows-amd64.zip
|
||||||
ebfb5b643ba73ef6007236b90f863ae49fc34fd366682c971b7d1308ab28f642 golangci-lint-1.52.2-netbsd-386.tar.gz
|
fd7dc8f4c6829ee6fafb252a4d81d2155cd35da7833665cbb25d53ce7cecd990 golangci-lint-1.55.2-windows-arm64.zip
|
||||||
f46b60a90fab5916a7de899ad9a3a4b3d77278c2e1737d070719d3ea27919557 golangci-lint-1.52.2-linux-armv7.deb
|
1892c3c24f9e7ef44b02f6750c703864b6dc350129f3ec39510300007b2376f1 golangci-lint-1.55.2-windows-armv6.zip
|
||||||
f6e39d0ac4691c2b9f49d6d5819594f48bb03e18692fd6d100e7114077f710e6 golangci-lint-1.52.2-linux-armv6.rpm
|
a5e68ae73d38748b5269fad36ac7575e3c162a5dc63ef58abdea03cc5da4522a golangci-lint-1.55.2-windows-armv7.zip
|
||||||
fa5da589075143628a49a0c123ccd76a8717bb6308fb3bdb6bf1df59435d921b golangci-lint-1.52.2-linux-mips64le.deb
|
|
||||||
fc09a97f8888809fab83a316f7da70c8ed74d4863b7eed7d872cec41911a55e8 golangci-lint-1.52.2-linux-arm64.tar.gz
|
|
||||||
|
|
||||||
# This is the builder on PPA that will build Go itself (inception-y), don't modify!
|
# This is the builder on PPA that will build Go itself (inception-y), don't modify!
|
||||||
|
#
|
||||||
|
# This version is fine to be old and full of security holes, we just use it
|
||||||
|
# to build the latest Go. Don't change it. If it ever becomes insufficient,
|
||||||
|
# we need to switch over to a recursive builder to jump across supported
|
||||||
|
# versions.
|
||||||
|
#
|
||||||
|
# version:ppa-builder 1.19.6
|
||||||
|
# https://go.dev/dl/
|
||||||
d7f0013f82e6d7f862cc6cb5c8cdb48eef5f2e239b35baa97e2f1a7466043767 go1.19.6.src.tar.gz
|
d7f0013f82e6d7f862cc6cb5c8cdb48eef5f2e239b35baa97e2f1a7466043767 go1.19.6.src.tar.gz
|
||||||
|
|||||||
89
build/ci.go
89
build/ci.go
@@ -120,15 +120,15 @@ var (
|
|||||||
// Distros for which packages are created.
|
// Distros for which packages are created.
|
||||||
// Note: vivid is unsupported because there is no golang-1.6 package for it.
|
// Note: vivid is unsupported because there is no golang-1.6 package for it.
|
||||||
// Note: the following Ubuntu releases have been officially deprecated on Launchpad:
|
// Note: the following Ubuntu releases have been officially deprecated on Launchpad:
|
||||||
// wily, yakkety, zesty, artful, cosmic, disco, eoan, groovy, hirsuite, impish
|
// wily, yakkety, zesty, artful, cosmic, disco, eoan, groovy, hirsuite, impish,
|
||||||
|
// kinetic, lunar
|
||||||
debDistroGoBoots = map[string]string{
|
debDistroGoBoots = map[string]string{
|
||||||
"trusty": "golang-1.11", // EOL: 04/2024
|
"trusty": "golang-1.11", // 14.04, EOL: 04/2024
|
||||||
"xenial": "golang-go", // EOL: 04/2026
|
"xenial": "golang-go", // 16.04, EOL: 04/2026
|
||||||
"bionic": "golang-go", // EOL: 04/2028
|
"bionic": "golang-go", // 18.04, EOL: 04/2028
|
||||||
"focal": "golang-go", // EOL: 04/2030
|
"focal": "golang-go", // 20.04, EOL: 04/2030
|
||||||
"jammy": "golang-go", // EOL: 04/2032
|
"jammy": "golang-go", // 22.04, EOL: 04/2032
|
||||||
"kinetic": "golang-go", // EOL: 07/2023
|
"mantic": "golang-go", // 23.10, EOL: 07/2024
|
||||||
"lunar": "golang-go", // EOL: 01/2024
|
|
||||||
}
|
}
|
||||||
|
|
||||||
debGoBootPaths = map[string]string{
|
debGoBootPaths = map[string]string{
|
||||||
@@ -136,18 +136,8 @@ var (
|
|||||||
"golang-go": "/usr/lib/go",
|
"golang-go": "/usr/lib/go",
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is the version of Go that will be downloaded by
|
// This is where the tests should be unpacked.
|
||||||
//
|
executionSpecTestsDir = "tests/spec-tests"
|
||||||
// go run ci.go install -dlgo
|
|
||||||
dlgoVersion = "1.20.7"
|
|
||||||
|
|
||||||
// This is the version of Go that will be used to bootstrap the PPA builder.
|
|
||||||
//
|
|
||||||
// This version is fine to be old and full of security holes, we just use it
|
|
||||||
// to build the latest Go. Don't change it. If it ever becomes insufficient,
|
|
||||||
// we need to switch over to a recursive builder to jumpt across supported
|
|
||||||
// versions.
|
|
||||||
gobootVersion = "1.19.6"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var GOBIN, _ = filepath.Abs(filepath.Join("build", "bin"))
|
var GOBIN, _ = filepath.Abs(filepath.Join("build", "bin"))
|
||||||
@@ -185,6 +175,8 @@ func main() {
|
|||||||
doWindowsInstaller(os.Args[2:])
|
doWindowsInstaller(os.Args[2:])
|
||||||
case "purge":
|
case "purge":
|
||||||
doPurge(os.Args[2:])
|
doPurge(os.Args[2:])
|
||||||
|
case "sanitycheck":
|
||||||
|
doSanityCheck()
|
||||||
default:
|
default:
|
||||||
log.Fatal("unknown command ", os.Args[1])
|
log.Fatal("unknown command ", os.Args[1])
|
||||||
}
|
}
|
||||||
@@ -207,9 +199,8 @@ func doInstall(cmdline []string) {
|
|||||||
tc := build.GoToolchain{GOARCH: *arch, CC: *cc}
|
tc := build.GoToolchain{GOARCH: *arch, CC: *cc}
|
||||||
if *dlgo {
|
if *dlgo {
|
||||||
csdb := build.MustLoadChecksums("build/checksums.txt")
|
csdb := build.MustLoadChecksums("build/checksums.txt")
|
||||||
tc.Root = build.DownloadGo(csdb, dlgoVersion)
|
tc.Root = build.DownloadGo(csdb)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Disable CLI markdown doc generation in release builds.
|
// Disable CLI markdown doc generation in release builds.
|
||||||
buildTags := []string{"urfave_cli_no_docs"}
|
buildTags := []string{"urfave_cli_no_docs"}
|
||||||
|
|
||||||
@@ -300,14 +291,19 @@ func doTest(cmdline []string) {
|
|||||||
verbose = flag.Bool("v", false, "Whether to log verbosely")
|
verbose = flag.Bool("v", false, "Whether to log verbosely")
|
||||||
timeout = flag.String("timeout", "10m", `Timeout of runing tests`)
|
timeout = flag.String("timeout", "10m", `Timeout of runing tests`)
|
||||||
race = flag.Bool("race", false, "Execute the race detector")
|
race = flag.Bool("race", false, "Execute the race detector")
|
||||||
|
short = flag.Bool("short", false, "Pass the 'short'-flag to go test")
|
||||||
|
cachedir = flag.String("cachedir", "./build/cache", "directory for caching downloads")
|
||||||
)
|
)
|
||||||
flag.CommandLine.Parse(cmdline)
|
flag.CommandLine.Parse(cmdline)
|
||||||
|
|
||||||
|
// Get test fixtures.
|
||||||
|
csdb := build.MustLoadChecksums("build/checksums.txt")
|
||||||
|
downloadSpecTestFixtures(csdb, *cachedir)
|
||||||
|
|
||||||
// Configure the toolchain.
|
// Configure the toolchain.
|
||||||
tc := build.GoToolchain{GOARCH: *arch, CC: *cc}
|
tc := build.GoToolchain{GOARCH: *arch, CC: *cc}
|
||||||
if *dlgo {
|
if *dlgo {
|
||||||
csdb := build.MustLoadChecksums("build/checksums.txt")
|
tc.Root = build.DownloadGo(csdb)
|
||||||
tc.Root = build.DownloadGo(csdb, dlgoVersion)
|
|
||||||
}
|
}
|
||||||
gotest := tc.Go("test")
|
gotest := tc.Go("test")
|
||||||
|
|
||||||
@@ -317,6 +313,9 @@ func doTest(cmdline []string) {
|
|||||||
// Enable CKZG backend in CI.
|
// Enable CKZG backend in CI.
|
||||||
gotest.Args = append(gotest.Args, "-tags=ckzg")
|
gotest.Args = append(gotest.Args, "-tags=ckzg")
|
||||||
|
|
||||||
|
// Enable integration-tests
|
||||||
|
gotest.Args = append(gotest.Args, "-tags=integrationtests")
|
||||||
|
|
||||||
// Test a single package at a time. CI builders are slow
|
// Test a single package at a time. CI builders are slow
|
||||||
// and some tests run into timeouts under load.
|
// and some tests run into timeouts under load.
|
||||||
gotest.Args = append(gotest.Args, "-p", "1")
|
gotest.Args = append(gotest.Args, "-p", "1")
|
||||||
@@ -332,6 +331,9 @@ func doTest(cmdline []string) {
|
|||||||
if *race {
|
if *race {
|
||||||
gotest.Args = append(gotest.Args, "-race")
|
gotest.Args = append(gotest.Args, "-race")
|
||||||
}
|
}
|
||||||
|
if *short {
|
||||||
|
gotest.Args = append(gotest.Args, "-short")
|
||||||
|
}
|
||||||
|
|
||||||
packages := []string{"./..."}
|
packages := []string{"./..."}
|
||||||
if len(flag.CommandLine.Args()) > 0 {
|
if len(flag.CommandLine.Args()) > 0 {
|
||||||
@@ -341,6 +343,25 @@ func doTest(cmdline []string) {
|
|||||||
build.MustRun(gotest)
|
build.MustRun(gotest)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// downloadSpecTestFixtures downloads and extracts the execution-spec-tests fixtures.
|
||||||
|
func downloadSpecTestFixtures(csdb *build.ChecksumDB, cachedir string) string {
|
||||||
|
executionSpecTestsVersion, err := build.Version(csdb, "spec-tests")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
ext := ".tar.gz"
|
||||||
|
base := "fixtures_develop" // TODO(MariusVanDerWijden) rename once the version becomes part of the filename
|
||||||
|
url := fmt.Sprintf("https://github.com/ethereum/execution-spec-tests/releases/download/v%s/%s%s", executionSpecTestsVersion, base, ext)
|
||||||
|
archivePath := filepath.Join(cachedir, base+ext)
|
||||||
|
if err := csdb.DownloadFile(url, archivePath); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
if err := build.ExtractArchive(archivePath, executionSpecTestsDir); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
return filepath.Join(cachedir, base)
|
||||||
|
}
|
||||||
|
|
||||||
// doLint runs golangci-lint on requested packages.
|
// doLint runs golangci-lint on requested packages.
|
||||||
func doLint(cmdline []string) {
|
func doLint(cmdline []string) {
|
||||||
var (
|
var (
|
||||||
@@ -354,15 +375,17 @@ func doLint(cmdline []string) {
|
|||||||
|
|
||||||
linter := downloadLinter(*cachedir)
|
linter := downloadLinter(*cachedir)
|
||||||
lflags := []string{"run", "--config", ".golangci.yml"}
|
lflags := []string{"run", "--config", ".golangci.yml"}
|
||||||
build.MustRunCommand(linter, append(lflags, packages...)...)
|
build.MustRunCommandWithOutput(linter, append(lflags, packages...)...)
|
||||||
fmt.Println("You have achieved perfection.")
|
fmt.Println("You have achieved perfection.")
|
||||||
}
|
}
|
||||||
|
|
||||||
// downloadLinter downloads and unpacks golangci-lint.
|
// downloadLinter downloads and unpacks golangci-lint.
|
||||||
func downloadLinter(cachedir string) string {
|
func downloadLinter(cachedir string) string {
|
||||||
const version = "1.52.2"
|
|
||||||
|
|
||||||
csdb := build.MustLoadChecksums("build/checksums.txt")
|
csdb := build.MustLoadChecksums("build/checksums.txt")
|
||||||
|
version, err := build.Version(csdb, "golangci")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
arch := runtime.GOARCH
|
arch := runtime.GOARCH
|
||||||
ext := ".tar.gz"
|
ext := ".tar.gz"
|
||||||
|
|
||||||
@@ -744,6 +767,10 @@ func doDebianSource(cmdline []string) {
|
|||||||
// to bootstrap the builder Go.
|
// to bootstrap the builder Go.
|
||||||
func downloadGoBootstrapSources(cachedir string) string {
|
func downloadGoBootstrapSources(cachedir string) string {
|
||||||
csdb := build.MustLoadChecksums("build/checksums.txt")
|
csdb := build.MustLoadChecksums("build/checksums.txt")
|
||||||
|
gobootVersion, err := build.Version(csdb, "ppa-builder")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
file := fmt.Sprintf("go%s.src.tar.gz", gobootVersion)
|
file := fmt.Sprintf("go%s.src.tar.gz", gobootVersion)
|
||||||
url := "https://dl.google.com/go/" + file
|
url := "https://dl.google.com/go/" + file
|
||||||
dst := filepath.Join(cachedir, file)
|
dst := filepath.Join(cachedir, file)
|
||||||
@@ -756,6 +783,10 @@ func downloadGoBootstrapSources(cachedir string) string {
|
|||||||
// downloadGoSources downloads the Go source tarball.
|
// downloadGoSources downloads the Go source tarball.
|
||||||
func downloadGoSources(cachedir string) string {
|
func downloadGoSources(cachedir string) string {
|
||||||
csdb := build.MustLoadChecksums("build/checksums.txt")
|
csdb := build.MustLoadChecksums("build/checksums.txt")
|
||||||
|
dlgoVersion, err := build.Version(csdb, "golang")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
file := fmt.Sprintf("go%s.src.tar.gz", dlgoVersion)
|
file := fmt.Sprintf("go%s.src.tar.gz", dlgoVersion)
|
||||||
url := "https://dl.google.com/go/" + file
|
url := "https://dl.google.com/go/" + file
|
||||||
dst := filepath.Join(cachedir, file)
|
dst := filepath.Join(cachedir, file)
|
||||||
@@ -1082,3 +1113,7 @@ func doPurge(cmdline []string) {
|
|||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func doSanityCheck() {
|
||||||
|
build.DownloadAndVerifyChecksums(build.MustLoadChecksums("build/checksums.txt"))
|
||||||
|
}
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
# - NSIS Large Strings build, http://nsis.sourceforge.net/Special_Builds
|
# - NSIS Large Strings build, http://nsis.sourceforge.net/Special_Builds
|
||||||
# - SFP, http://nsis.sourceforge.net/NSIS_Simple_Firewall_Plugin (put dll in NSIS\Plugins\x86-ansi)
|
# - SFP, http://nsis.sourceforge.net/NSIS_Simple_Firewall_Plugin (put dll in NSIS\Plugins\x86-ansi)
|
||||||
#
|
#
|
||||||
# After intalling NSIS extra the NSIS Large Strings build zip and replace the makensis.exe and the
|
# After installing NSIS extra the NSIS Large Strings build zip and replace the makensis.exe and the
|
||||||
# files found in Stub.
|
# files found in Stub.
|
||||||
#
|
#
|
||||||
# based on: http://nsis.sourceforge.net/A_simple_installer_with_start_menu_shortcut_and_uninstaller
|
# based on: http://nsis.sourceforge.net/A_simple_installer_with_start_menu_shortcut_and_uninstaller
|
||||||
|
|||||||
@@ -65,10 +65,8 @@ var (
|
|||||||
"vendor/", "tests/testdata/", "build/",
|
"vendor/", "tests/testdata/", "build/",
|
||||||
|
|
||||||
// don't relicense vendored sources
|
// don't relicense vendored sources
|
||||||
"cmd/internal/browser",
|
|
||||||
"common/bitutil/bitutil",
|
"common/bitutil/bitutil",
|
||||||
"common/prque/",
|
"common/prque/",
|
||||||
"consensus/ethash/xor.go",
|
|
||||||
"crypto/blake2b/",
|
"crypto/blake2b/",
|
||||||
"crypto/bn256/",
|
"crypto/bn256/",
|
||||||
"crypto/bls12381/",
|
"crypto/bls12381/",
|
||||||
@@ -78,6 +76,7 @@ var (
|
|||||||
"log/",
|
"log/",
|
||||||
"metrics/",
|
"metrics/",
|
||||||
"signer/rules/deps",
|
"signer/rules/deps",
|
||||||
|
"internal/reexec",
|
||||||
|
|
||||||
// skip special licenses
|
// skip special licenses
|
||||||
"crypto/secp256k1", // Relicensed to BSD-3 via https://github.com/ethereum/go-ethereum/pull/17225
|
"crypto/secp256k1", // Relicensed to BSD-3 via https://github.com/ethereum/go-ethereum/pull/17225
|
||||||
|
|||||||
@@ -232,7 +232,7 @@ func abigen(c *cli.Context) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
log.Root().SetHandler(log.LvlFilterHandler(log.LvlInfo, log.StreamHandler(os.Stderr, log.TerminalFormat(true))))
|
log.SetDefault(log.NewLogger(log.NewTerminalHandlerWithLevel(os.Stderr, log.LevelInfo, true)))
|
||||||
|
|
||||||
if err := app.Run(os.Args); err != nil {
|
if err := app.Run(os.Args); err != nil {
|
||||||
fmt.Fprintln(os.Stderr, err)
|
fmt.Fprintln(os.Stderr, err)
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestNameFilter(t *testing.T) {
|
func TestNameFilter(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
_, err := newNameFilter("Foo")
|
_, err := newNameFilter("Foo")
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
_, err = newNameFilter("too/many:colons:Foo")
|
_, err = newNameFilter("too/many:colons:Foo")
|
||||||
|
|||||||
@@ -54,10 +54,11 @@ func main() {
|
|||||||
)
|
)
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
glogger := log.NewGlogHandler(log.StreamHandler(os.Stderr, log.TerminalFormat(false)))
|
glogger := log.NewGlogHandler(log.NewTerminalHandler(os.Stderr, false))
|
||||||
glogger.Verbosity(log.Lvl(*verbosity))
|
slogVerbosity := log.FromLegacyLevel(*verbosity)
|
||||||
|
glogger.Verbosity(slogVerbosity)
|
||||||
glogger.Vmodule(*vmodule)
|
glogger.Vmodule(*vmodule)
|
||||||
log.Root().SetHandler(glogger)
|
log.SetDefault(log.NewLogger(glogger))
|
||||||
|
|
||||||
natm, err := nat.Parse(*natdesc)
|
natm, err := nat.Parse(*natdesc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
Clef can be used to sign transactions and data and is meant as a(n eventual) replacement for Geth's account management. This allows DApps to not depend on Geth's account management. When a DApp wants to sign data (or a transaction), it can send the content to Clef, which will then provide the user with context and asks for permission to sign the content. If the users grants the signing request, Clef will send the signature back to the DApp.
|
Clef can be used to sign transactions and data and is meant as a(n eventual) replacement for Geth's account management. This allows DApps to not depend on Geth's account management. When a DApp wants to sign data (or a transaction), it can send the content to Clef, which will then provide the user with context and asks for permission to sign the content. If the users grants the signing request, Clef will send the signature back to the DApp.
|
||||||
|
|
||||||
This setup allows a DApp to connect to a remote Ethereum node and send transactions that are locally signed. This can help in situations when a DApp is connected to an untrusted remote Ethereum node, because a local one is not available, not synchronised with the chain, or is a node that has no built-in (or limited) account management.
|
This setup allows a DApp to connect to a remote Ethereum node and send transactions that are locally signed. This can help in situations when a DApp is connected to an untrusted remote Ethereum node, because a local one is not available, not synchronized with the chain, or is a node that has no built-in (or limited) account management.
|
||||||
|
|
||||||
Clef can run as a daemon on the same machine, off a usb-stick like [USB armory](https://inversepath.com/usbarmory), or even a separate VM in a [QubesOS](https://www.qubes-os.org/) type setup.
|
Clef can run as a daemon on the same machine, off a usb-stick like [USB armory](https://inversepath.com/usbarmory), or even a separate VM in a [QubesOS](https://www.qubes-os.org/) type setup.
|
||||||
|
|
||||||
@@ -916,7 +916,7 @@ There are a couple of implementation for a UI. We'll try to keep this list up to
|
|||||||
|
|
||||||
| Name | Repo | UI type| No external resources| Blocky support| Verifies permissions | Hash information | No secondary storage | Statically linked| Can modify parameters|
|
| Name | Repo | UI type| No external resources| Blocky support| Verifies permissions | Hash information | No secondary storage | Statically linked| Can modify parameters|
|
||||||
| ---- | ---- | -------| ---- | ---- | ---- |---- | ---- | ---- | ---- |
|
| ---- | ---- | -------| ---- | ---- | ---- |---- | ---- | ---- | ---- |
|
||||||
| QtSigner| https://github.com/holiman/qtsigner/| Python3/QT-based| :+1:| :+1:| :+1:| :+1:| :+1:| :x: | :+1: (partially)|
|
| QtSigner| https://github.com/holiman/qtsigner/ | Python3/QT-based| :+1:| :+1:| :+1:| :+1:| :+1:| :x: | :+1: (partially)|
|
||||||
| GtkSigner| https://github.com/holiman/gtksigner| Python3/GTK-based| :+1:| :x:| :x:| :+1:| :+1:| :x: | :x: |
|
| GtkSigner| https://github.com/holiman/gtksigner | Python3/GTK-based| :+1:| :x:| :x:| :+1:| :+1:| :x: | :x: |
|
||||||
| Frame | https://github.com/floating/frame/commits/go-signer| Electron-based| :x:| :x:| :x:| :x:| ?| :x: | :x: |
|
| Frame | https://github.com/floating/frame/commits/go-signer | Electron-based| :x:| :x:| :x:| :x:| ?| :x: | :x: |
|
||||||
| Clef UI| https://github.com/ethereum/clef-ui| Golang/QT-based| :+1:| :+1:| :x:| :+1:| :+1:| :x: | :+1: (approve tx only)|
|
| Clef UI| https://github.com/ethereum/clef-ui | Golang/QT-based| :+1:| :+1:| :x:| :+1:| :+1:| :x: | :+1: (approve tx only)|
|
||||||
|
|||||||
@@ -26,12 +26,13 @@ import (
|
|||||||
|
|
||||||
// TestImportRaw tests clef --importraw
|
// TestImportRaw tests clef --importraw
|
||||||
func TestImportRaw(t *testing.T) {
|
func TestImportRaw(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
keyPath := filepath.Join(os.TempDir(), fmt.Sprintf("%v-tempkey.test", t.Name()))
|
keyPath := filepath.Join(os.TempDir(), fmt.Sprintf("%v-tempkey.test", t.Name()))
|
||||||
os.WriteFile(keyPath, []byte("0102030405060708090a0102030405060708090a0102030405060708090a0102"), 0777)
|
os.WriteFile(keyPath, []byte("0102030405060708090a0102030405060708090a0102030405060708090a0102"), 0777)
|
||||||
t.Cleanup(func() { os.Remove(keyPath) })
|
t.Cleanup(func() { os.Remove(keyPath) })
|
||||||
|
|
||||||
t.Parallel()
|
|
||||||
t.Run("happy-path", func(t *testing.T) {
|
t.Run("happy-path", func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
// Run clef importraw
|
// Run clef importraw
|
||||||
clef := runClef(t, "--suppress-bootwarn", "--lightkdf", "importraw", keyPath)
|
clef := runClef(t, "--suppress-bootwarn", "--lightkdf", "importraw", keyPath)
|
||||||
clef.input("myverylongpassword").input("myverylongpassword")
|
clef.input("myverylongpassword").input("myverylongpassword")
|
||||||
@@ -43,6 +44,7 @@ func TestImportRaw(t *testing.T) {
|
|||||||
})
|
})
|
||||||
// tests clef --importraw with mismatched passwords.
|
// tests clef --importraw with mismatched passwords.
|
||||||
t.Run("pw-mismatch", func(t *testing.T) {
|
t.Run("pw-mismatch", func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
// Run clef importraw
|
// Run clef importraw
|
||||||
clef := runClef(t, "--suppress-bootwarn", "--lightkdf", "importraw", keyPath)
|
clef := runClef(t, "--suppress-bootwarn", "--lightkdf", "importraw", keyPath)
|
||||||
clef.input("myverylongpassword1").input("myverylongpassword2").WaitExit()
|
clef.input("myverylongpassword1").input("myverylongpassword2").WaitExit()
|
||||||
@@ -52,6 +54,7 @@ func TestImportRaw(t *testing.T) {
|
|||||||
})
|
})
|
||||||
// tests clef --importraw with a too short password.
|
// tests clef --importraw with a too short password.
|
||||||
t.Run("short-pw", func(t *testing.T) {
|
t.Run("short-pw", func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
// Run clef importraw
|
// Run clef importraw
|
||||||
clef := runClef(t, "--suppress-bootwarn", "--lightkdf", "importraw", keyPath)
|
clef := runClef(t, "--suppress-bootwarn", "--lightkdf", "importraw", keyPath)
|
||||||
clef.input("shorty").input("shorty").WaitExit()
|
clef.input("shorty").input("shorty").WaitExit()
|
||||||
@@ -64,12 +67,13 @@ func TestImportRaw(t *testing.T) {
|
|||||||
|
|
||||||
// TestListAccounts tests clef --list-accounts
|
// TestListAccounts tests clef --list-accounts
|
||||||
func TestListAccounts(t *testing.T) {
|
func TestListAccounts(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
keyPath := filepath.Join(os.TempDir(), fmt.Sprintf("%v-tempkey.test", t.Name()))
|
keyPath := filepath.Join(os.TempDir(), fmt.Sprintf("%v-tempkey.test", t.Name()))
|
||||||
os.WriteFile(keyPath, []byte("0102030405060708090a0102030405060708090a0102030405060708090a0102"), 0777)
|
os.WriteFile(keyPath, []byte("0102030405060708090a0102030405060708090a0102030405060708090a0102"), 0777)
|
||||||
t.Cleanup(func() { os.Remove(keyPath) })
|
t.Cleanup(func() { os.Remove(keyPath) })
|
||||||
|
|
||||||
t.Parallel()
|
|
||||||
t.Run("no-accounts", func(t *testing.T) {
|
t.Run("no-accounts", func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
clef := runClef(t, "--suppress-bootwarn", "--lightkdf", "list-accounts")
|
clef := runClef(t, "--suppress-bootwarn", "--lightkdf", "list-accounts")
|
||||||
if out := string(clef.Output()); !strings.Contains(out, "The keystore is empty.") {
|
if out := string(clef.Output()); !strings.Contains(out, "The keystore is empty.") {
|
||||||
t.Logf("Output\n%v", out)
|
t.Logf("Output\n%v", out)
|
||||||
@@ -77,6 +81,7 @@ func TestListAccounts(t *testing.T) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
t.Run("one-account", func(t *testing.T) {
|
t.Run("one-account", func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
// First, we need to import
|
// First, we need to import
|
||||||
clef := runClef(t, "--suppress-bootwarn", "--lightkdf", "importraw", keyPath)
|
clef := runClef(t, "--suppress-bootwarn", "--lightkdf", "importraw", keyPath)
|
||||||
clef.input("myverylongpassword").input("myverylongpassword").WaitExit()
|
clef.input("myverylongpassword").input("myverylongpassword").WaitExit()
|
||||||
@@ -91,12 +96,13 @@ func TestListAccounts(t *testing.T) {
|
|||||||
|
|
||||||
// TestListWallets tests clef --list-wallets
|
// TestListWallets tests clef --list-wallets
|
||||||
func TestListWallets(t *testing.T) {
|
func TestListWallets(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
keyPath := filepath.Join(os.TempDir(), fmt.Sprintf("%v-tempkey.test", t.Name()))
|
keyPath := filepath.Join(os.TempDir(), fmt.Sprintf("%v-tempkey.test", t.Name()))
|
||||||
os.WriteFile(keyPath, []byte("0102030405060708090a0102030405060708090a0102030405060708090a0102"), 0777)
|
os.WriteFile(keyPath, []byte("0102030405060708090a0102030405060708090a0102030405060708090a0102"), 0777)
|
||||||
t.Cleanup(func() { os.Remove(keyPath) })
|
t.Cleanup(func() { os.Remove(keyPath) })
|
||||||
|
|
||||||
t.Parallel()
|
|
||||||
t.Run("no-accounts", func(t *testing.T) {
|
t.Run("no-accounts", func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
clef := runClef(t, "--suppress-bootwarn", "--lightkdf", "list-wallets")
|
clef := runClef(t, "--suppress-bootwarn", "--lightkdf", "list-wallets")
|
||||||
if out := string(clef.Output()); !strings.Contains(out, "There are no wallets.") {
|
if out := string(clef.Output()); !strings.Contains(out, "There are no wallets.") {
|
||||||
t.Logf("Output\n%v", out)
|
t.Logf("Output\n%v", out)
|
||||||
@@ -104,6 +110,7 @@ func TestListWallets(t *testing.T) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
t.Run("one-account", func(t *testing.T) {
|
t.Run("one-account", func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
// First, we need to import
|
// First, we need to import
|
||||||
clef := runClef(t, "--suppress-bootwarn", "--lightkdf", "importraw", keyPath)
|
clef := runClef(t, "--suppress-bootwarn", "--lightkdf", "importraw", keyPath)
|
||||||
clef.input("myverylongpassword").input("myverylongpassword").WaitExit()
|
clef.input("myverylongpassword").input("myverylongpassword").WaitExit()
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ Example:
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "Info",
|
"type": "Info",
|
||||||
"message": "User should see this aswell"
|
"message": "User should see this as well"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"meta": {
|
"meta": {
|
||||||
|
|||||||
@@ -492,7 +492,8 @@ func initialize(c *cli.Context) error {
|
|||||||
if usecolor {
|
if usecolor {
|
||||||
output = colorable.NewColorable(logOutput)
|
output = colorable.NewColorable(logOutput)
|
||||||
}
|
}
|
||||||
log.Root().SetHandler(log.LvlFilterHandler(log.Lvl(c.Int(logLevelFlag.Name)), log.StreamHandler(output, log.TerminalFormat(usecolor))))
|
verbosity := log.FromLegacyLevel(c.Int(logLevelFlag.Name))
|
||||||
|
log.SetDefault(log.NewLogger(log.NewTerminalHandlerWithLevel(output, verbosity, usecolor)))
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -581,6 +582,7 @@ func accountImport(c *cli.Context) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if first != second {
|
if first != second {
|
||||||
|
//lint:ignore ST1005 This is a message for the user
|
||||||
return errors.New("Passwords do not match")
|
return errors.New("Passwords do not match")
|
||||||
}
|
}
|
||||||
acc, err := internalApi.ImportRawKey(hex.EncodeToString(crypto.FromECDSA(pKey)), first)
|
acc, err := internalApi.ImportRawKey(hex.EncodeToString(crypto.FromECDSA(pKey)), first)
|
||||||
@@ -702,6 +704,7 @@ func signer(c *cli.Context) error {
|
|||||||
log.Info("Starting signer", "chainid", chainId, "keystore", ksLoc,
|
log.Info("Starting signer", "chainid", chainId, "keystore", ksLoc,
|
||||||
"light-kdf", lightKdf, "advanced", advanced)
|
"light-kdf", lightKdf, "advanced", advanced)
|
||||||
am := core.StartClefAccountManager(ksLoc, nousb, lightKdf, scpath)
|
am := core.StartClefAccountManager(ksLoc, nousb, lightKdf, scpath)
|
||||||
|
defer am.Close()
|
||||||
apiImpl := core.NewSignerAPI(am, chainId, nousb, ui, db, advanced, pwStorage)
|
apiImpl := core.NewSignerAPI(am, chainId, nousb, ui, db, advanced, pwStorage)
|
||||||
|
|
||||||
// Establish the bidirectional communication, by creating a new UI backend and registering
|
// Establish the bidirectional communication, by creating a new UI backend and registering
|
||||||
@@ -1206,7 +1209,7 @@ func GenDoc(ctx *cli.Context) error {
|
|||||||
URL: accounts.URL{Path: ".. ignored .."},
|
URL: accounts.URL{Path: ".. ignored .."},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Address: common.HexToAddress("0xffffffffffffffffffffffffffffffffffffffff"),
|
Address: common.MaxAddress,
|
||||||
},
|
},
|
||||||
}})
|
}})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ class StdIOHandler:
|
|||||||
{"jsonrpc":"2.0","id":20,"method":"ui_approveTx","params":[{"transaction":{"from":"0xDEADbEeF000000000000000000000000DeaDbeEf","to":"0xDEADbEeF000000000000000000000000DeaDbeEf","gas":"0x3e8","gasPrice":"0x5","maxFeePerGas":null,"maxPriorityFeePerGas":null,"value":"0x6","nonce":"0x1","data":"0x"},"call_info":null,"meta":{"remote":"clef binary","local":"main","scheme":"in-proc","User-Agent":"","Origin":""}}]}
|
{"jsonrpc":"2.0","id":20,"method":"ui_approveTx","params":[{"transaction":{"from":"0xDEADbEeF000000000000000000000000DeaDbeEf","to":"0xDEADbEeF000000000000000000000000DeaDbeEf","gas":"0x3e8","gasPrice":"0x5","maxFeePerGas":null,"maxPriorityFeePerGas":null,"value":"0x6","nonce":"0x1","data":"0x"},"call_info":null,"meta":{"remote":"clef binary","local":"main","scheme":"in-proc","User-Agent":"","Origin":""}}]}
|
||||||
|
|
||||||
:param transaction: transaction info
|
:param transaction: transaction info
|
||||||
:param call_info: info abou the call, e.g. if ABI info could not be
|
:param call_info: info about the call, e.g. if ABI info could not be
|
||||||
:param meta: metadata about the request, e.g. where the call comes from
|
:param meta: metadata about the request, e.g. where the call comes from
|
||||||
:return:
|
:return:
|
||||||
""" # noqa: E501
|
""" # noqa: E501
|
||||||
|
|||||||
@@ -21,8 +21,8 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/docker/docker/pkg/reexec"
|
|
||||||
"github.com/ethereum/go-ethereum/internal/cmdtest"
|
"github.com/ethereum/go-ethereum/internal/cmdtest"
|
||||||
|
"github.com/ethereum/go-ethereum/internal/reexec"
|
||||||
)
|
)
|
||||||
|
|
||||||
const registeredName = "clef-test"
|
const registeredName = "clef-test"
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ set to standard output. The following filters are supported:
|
|||||||
- `-limit <N>` limits the output set to N entries, taking the top N nodes by score
|
- `-limit <N>` limits the output set to N entries, taking the top N nodes by score
|
||||||
- `-ip <CIDR>` filters nodes by IP subnet
|
- `-ip <CIDR>` filters nodes by IP subnet
|
||||||
- `-min-age <duration>` filters nodes by 'first seen' time
|
- `-min-age <duration>` filters nodes by 'first seen' time
|
||||||
- `-eth-network <mainnet/goerli/sepolia>` filters nodes by "eth" ENR entry
|
- `-eth-network <mainnet/goerli/sepolia/holesky>` filters nodes by "eth" ENR entry
|
||||||
- `-les-server` filters nodes by LES server support
|
- `-les-server` filters nodes by LES server support
|
||||||
- `-snap` filters nodes by snap protocol support
|
- `-snap` filters nodes by snap protocol support
|
||||||
|
|
||||||
@@ -108,31 +108,32 @@ Start the test by running `devp2p discv5 test -listen1 127.0.0.1 -listen2 127.0.
|
|||||||
|
|
||||||
The Eth Protocol test suite is a conformance test suite for the [eth protocol][eth].
|
The Eth Protocol test suite is a conformance test suite for the [eth protocol][eth].
|
||||||
|
|
||||||
To run the eth protocol test suite against your implementation, the node needs to be initialized as such:
|
To run the eth protocol test suite against your implementation, the node needs to be initialized
|
||||||
|
with our test chain. The chain files are located in `./cmd/devp2p/internal/ethtest/testdata`.
|
||||||
|
|
||||||
1. initialize the geth node with the `genesis.json` file contained in the `testdata` directory
|
1. initialize the geth node with the `genesis.json` file
|
||||||
2. import the `halfchain.rlp` file in the `testdata` directory
|
2. import blocks from `chain.rlp`
|
||||||
3. run geth with the following flags:
|
3. run the client using the resulting database. For geth, use a command like the one below:
|
||||||
```
|
|
||||||
geth --datadir <datadir> --nodiscover --nat=none --networkid 19763 --verbosity 5
|
|
||||||
```
|
|
||||||
|
|
||||||
Then, run the following command, replacing `<enode>` with the enode of the geth node:
|
geth \
|
||||||
```
|
--datadir <datadir> \
|
||||||
devp2p rlpx eth-test <enode> cmd/devp2p/internal/ethtest/testdata/chain.rlp cmd/devp2p/internal/ethtest/testdata/genesis.json
|
--nodiscover \
|
||||||
```
|
--nat=none \
|
||||||
|
--networkid 3503995874084926 \
|
||||||
|
--verbosity 5 \
|
||||||
|
--authrpc.jwtsecret 0x7365637265747365637265747365637265747365637265747365637265747365
|
||||||
|
|
||||||
|
Note that the tests also require access to the engine API.
|
||||||
|
The test suite can now be executed using the devp2p tool.
|
||||||
|
|
||||||
|
devp2p rlpx eth-test \
|
||||||
|
--chain internal/ethtest/testdata \
|
||||||
|
--node enode://.... \
|
||||||
|
--engineapi http://127.0.0.1:8551 \
|
||||||
|
--jwtsecret 0x7365637265747365637265747365637265747365637265747365637265747365
|
||||||
|
|
||||||
Repeat the above process (re-initialising the node) in order to run the Eth Protocol test suite again.
|
Repeat the above process (re-initialising the node) in order to run the Eth Protocol test suite again.
|
||||||
|
|
||||||
#### Eth66 Test Suite
|
|
||||||
|
|
||||||
The Eth66 test suite is also a conformance test suite for the eth 66 protocol version specifically.
|
|
||||||
To run the eth66 protocol test suite, initialize a geth node as described above and run the following command,
|
|
||||||
replacing `<enode>` with the enode of the geth node:
|
|
||||||
|
|
||||||
```
|
|
||||||
devp2p rlpx eth66-test <enode> cmd/devp2p/internal/ethtest/testdata/chain.rlp cmd/devp2p/internal/ethtest/testdata/genesis.json
|
|
||||||
```
|
|
||||||
|
|
||||||
[eth]: https://github.com/ethereum/devp2p/blob/master/caps/eth.md
|
[eth]: https://github.com/ethereum/devp2p/blob/master/caps/eth.md
|
||||||
[dns-tutorial]: https://geth.ethereum.org/docs/developers/geth-developer/dns-discovery-setup
|
[dns-tutorial]: https://geth.ethereum.org/docs/developers/geth-developer/dns-discovery-setup
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
@@ -51,7 +52,14 @@ type resolver interface {
|
|||||||
RequestENR(*enode.Node) (*enode.Node, error)
|
RequestENR(*enode.Node) (*enode.Node, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func newCrawler(input nodeSet, disc resolver, iters ...enode.Iterator) *crawler {
|
func newCrawler(input nodeSet, bootnodes []*enode.Node, disc resolver, iters ...enode.Iterator) (*crawler, error) {
|
||||||
|
if len(input) == 0 {
|
||||||
|
input.add(bootnodes...)
|
||||||
|
}
|
||||||
|
if len(input) == 0 {
|
||||||
|
return nil, errors.New("no input nodes to start crawling")
|
||||||
|
}
|
||||||
|
|
||||||
c := &crawler{
|
c := &crawler{
|
||||||
input: input,
|
input: input,
|
||||||
output: make(nodeSet, len(input)),
|
output: make(nodeSet, len(input)),
|
||||||
@@ -67,7 +75,7 @@ func newCrawler(input nodeSet, disc resolver, iters ...enode.Iterator) *crawler
|
|||||||
for id, n := range input {
|
for id, n := range input {
|
||||||
c.output[id] = n
|
c.output[id] = n
|
||||||
}
|
}
|
||||||
return c
|
return c, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *crawler) run(timeout time.Duration, nthreads int) nodeSet {
|
func (c *crawler) run(timeout time.Duration, nthreads int) nodeSet {
|
||||||
|
|||||||
@@ -143,7 +143,7 @@ var discoveryNodeFlags = []cli.Flag{
|
|||||||
|
|
||||||
func discv4Ping(ctx *cli.Context) error {
|
func discv4Ping(ctx *cli.Context) error {
|
||||||
n := getNodeArg(ctx)
|
n := getNodeArg(ctx)
|
||||||
disc := startV4(ctx)
|
disc, _ := startV4(ctx)
|
||||||
defer disc.Close()
|
defer disc.Close()
|
||||||
|
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
@@ -156,7 +156,7 @@ func discv4Ping(ctx *cli.Context) error {
|
|||||||
|
|
||||||
func discv4RequestRecord(ctx *cli.Context) error {
|
func discv4RequestRecord(ctx *cli.Context) error {
|
||||||
n := getNodeArg(ctx)
|
n := getNodeArg(ctx)
|
||||||
disc := startV4(ctx)
|
disc, _ := startV4(ctx)
|
||||||
defer disc.Close()
|
defer disc.Close()
|
||||||
|
|
||||||
respN, err := disc.RequestENR(n)
|
respN, err := disc.RequestENR(n)
|
||||||
@@ -169,7 +169,7 @@ func discv4RequestRecord(ctx *cli.Context) error {
|
|||||||
|
|
||||||
func discv4Resolve(ctx *cli.Context) error {
|
func discv4Resolve(ctx *cli.Context) error {
|
||||||
n := getNodeArg(ctx)
|
n := getNodeArg(ctx)
|
||||||
disc := startV4(ctx)
|
disc, _ := startV4(ctx)
|
||||||
defer disc.Close()
|
defer disc.Close()
|
||||||
|
|
||||||
fmt.Println(disc.Resolve(n).String())
|
fmt.Println(disc.Resolve(n).String())
|
||||||
@@ -196,10 +196,13 @@ func discv4ResolveJSON(ctx *cli.Context) error {
|
|||||||
nodeargs = append(nodeargs, n)
|
nodeargs = append(nodeargs, n)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run the crawler.
|
disc, config := startV4(ctx)
|
||||||
disc := startV4(ctx)
|
|
||||||
defer disc.Close()
|
defer disc.Close()
|
||||||
c := newCrawler(inputSet, disc, enode.IterNodes(nodeargs))
|
|
||||||
|
c, err := newCrawler(inputSet, config.Bootnodes, disc, enode.IterNodes(nodeargs))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
c.revalidateInterval = 0
|
c.revalidateInterval = 0
|
||||||
output := c.run(0, 1)
|
output := c.run(0, 1)
|
||||||
writeNodesJSON(nodesFile, output)
|
writeNodesJSON(nodesFile, output)
|
||||||
@@ -211,14 +214,18 @@ func discv4Crawl(ctx *cli.Context) error {
|
|||||||
return errors.New("need nodes file as argument")
|
return errors.New("need nodes file as argument")
|
||||||
}
|
}
|
||||||
nodesFile := ctx.Args().First()
|
nodesFile := ctx.Args().First()
|
||||||
var inputSet nodeSet
|
inputSet := make(nodeSet)
|
||||||
if common.FileExist(nodesFile) {
|
if common.FileExist(nodesFile) {
|
||||||
inputSet = loadNodesJSON(nodesFile)
|
inputSet = loadNodesJSON(nodesFile)
|
||||||
}
|
}
|
||||||
|
|
||||||
disc := startV4(ctx)
|
disc, config := startV4(ctx)
|
||||||
defer disc.Close()
|
defer disc.Close()
|
||||||
c := newCrawler(inputSet, disc, disc.RandomNodes())
|
|
||||||
|
c, err := newCrawler(inputSet, config.Bootnodes, disc, disc.RandomNodes())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
c.revalidateInterval = 10 * time.Minute
|
c.revalidateInterval = 10 * time.Minute
|
||||||
output := c.run(ctx.Duration(crawlTimeoutFlag.Name), ctx.Int(crawlParallelismFlag.Name))
|
output := c.run(ctx.Duration(crawlTimeoutFlag.Name), ctx.Int(crawlParallelismFlag.Name))
|
||||||
writeNodesJSON(nodesFile, output)
|
writeNodesJSON(nodesFile, output)
|
||||||
@@ -229,7 +236,7 @@ func discv4Crawl(ctx *cli.Context) error {
|
|||||||
func discv4Test(ctx *cli.Context) error {
|
func discv4Test(ctx *cli.Context) error {
|
||||||
// Configure test package globals.
|
// Configure test package globals.
|
||||||
if !ctx.IsSet(remoteEnodeFlag.Name) {
|
if !ctx.IsSet(remoteEnodeFlag.Name) {
|
||||||
return fmt.Errorf("Missing -%v", remoteEnodeFlag.Name)
|
return fmt.Errorf("missing -%v", remoteEnodeFlag.Name)
|
||||||
}
|
}
|
||||||
v4test.Remote = ctx.String(remoteEnodeFlag.Name)
|
v4test.Remote = ctx.String(remoteEnodeFlag.Name)
|
||||||
v4test.Listen1 = ctx.String(testListen1Flag.Name)
|
v4test.Listen1 = ctx.String(testListen1Flag.Name)
|
||||||
@@ -238,14 +245,14 @@ func discv4Test(ctx *cli.Context) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// startV4 starts an ephemeral discovery V4 node.
|
// startV4 starts an ephemeral discovery V4 node.
|
||||||
func startV4(ctx *cli.Context) *discover.UDPv4 {
|
func startV4(ctx *cli.Context) (*discover.UDPv4, discover.Config) {
|
||||||
ln, config := makeDiscoveryConfig(ctx)
|
ln, config := makeDiscoveryConfig(ctx)
|
||||||
socket := listen(ctx, ln)
|
socket := listen(ctx, ln)
|
||||||
disc, err := discover.ListenV4(socket, ln, config)
|
disc, err := discover.ListenV4(socket, ln, config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
exit(err)
|
exit(err)
|
||||||
}
|
}
|
||||||
return disc
|
return disc, config
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeDiscoveryConfig(ctx *cli.Context) (*enode.LocalNode, discover.Config) {
|
func makeDiscoveryConfig(ctx *cli.Context) (*enode.LocalNode, discover.Config) {
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ var (
|
|||||||
|
|
||||||
func discv5Ping(ctx *cli.Context) error {
|
func discv5Ping(ctx *cli.Context) error {
|
||||||
n := getNodeArg(ctx)
|
n := getNodeArg(ctx)
|
||||||
disc := startV5(ctx)
|
disc, _ := startV5(ctx)
|
||||||
defer disc.Close()
|
defer disc.Close()
|
||||||
|
|
||||||
fmt.Println(disc.Ping(n))
|
fmt.Println(disc.Ping(n))
|
||||||
@@ -90,7 +90,7 @@ func discv5Ping(ctx *cli.Context) error {
|
|||||||
|
|
||||||
func discv5Resolve(ctx *cli.Context) error {
|
func discv5Resolve(ctx *cli.Context) error {
|
||||||
n := getNodeArg(ctx)
|
n := getNodeArg(ctx)
|
||||||
disc := startV5(ctx)
|
disc, _ := startV5(ctx)
|
||||||
defer disc.Close()
|
defer disc.Close()
|
||||||
|
|
||||||
fmt.Println(disc.Resolve(n))
|
fmt.Println(disc.Resolve(n))
|
||||||
@@ -102,14 +102,18 @@ func discv5Crawl(ctx *cli.Context) error {
|
|||||||
return errors.New("need nodes file as argument")
|
return errors.New("need nodes file as argument")
|
||||||
}
|
}
|
||||||
nodesFile := ctx.Args().First()
|
nodesFile := ctx.Args().First()
|
||||||
var inputSet nodeSet
|
inputSet := make(nodeSet)
|
||||||
if common.FileExist(nodesFile) {
|
if common.FileExist(nodesFile) {
|
||||||
inputSet = loadNodesJSON(nodesFile)
|
inputSet = loadNodesJSON(nodesFile)
|
||||||
}
|
}
|
||||||
|
|
||||||
disc := startV5(ctx)
|
disc, config := startV5(ctx)
|
||||||
defer disc.Close()
|
defer disc.Close()
|
||||||
c := newCrawler(inputSet, disc, disc.RandomNodes())
|
|
||||||
|
c, err := newCrawler(inputSet, config.Bootnodes, disc, disc.RandomNodes())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
c.revalidateInterval = 10 * time.Minute
|
c.revalidateInterval = 10 * time.Minute
|
||||||
output := c.run(ctx.Duration(crawlTimeoutFlag.Name), ctx.Int(crawlParallelismFlag.Name))
|
output := c.run(ctx.Duration(crawlTimeoutFlag.Name), ctx.Int(crawlParallelismFlag.Name))
|
||||||
writeNodesJSON(nodesFile, output)
|
writeNodesJSON(nodesFile, output)
|
||||||
@@ -127,7 +131,7 @@ func discv5Test(ctx *cli.Context) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func discv5Listen(ctx *cli.Context) error {
|
func discv5Listen(ctx *cli.Context) error {
|
||||||
disc := startV5(ctx)
|
disc, _ := startV5(ctx)
|
||||||
defer disc.Close()
|
defer disc.Close()
|
||||||
|
|
||||||
fmt.Println(disc.Self())
|
fmt.Println(disc.Self())
|
||||||
@@ -135,12 +139,12 @@ func discv5Listen(ctx *cli.Context) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// startV5 starts an ephemeral discovery v5 node.
|
// startV5 starts an ephemeral discovery v5 node.
|
||||||
func startV5(ctx *cli.Context) *discover.UDPv5 {
|
func startV5(ctx *cli.Context) (*discover.UDPv5, discover.Config) {
|
||||||
ln, config := makeDiscoveryConfig(ctx)
|
ln, config := makeDiscoveryConfig(ctx)
|
||||||
socket := listen(ctx, ln)
|
socket := listen(ctx, ln)
|
||||||
disc, err := discover.ListenV5(socket, ln, config)
|
disc, err := discover.ListenV5(socket, ln, config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
exit(err)
|
exit(err)
|
||||||
}
|
}
|
||||||
return disc
|
return disc, config
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -114,7 +114,7 @@ func (c *cloudflareClient) uploadRecords(name string, records map[string]string)
|
|||||||
records = lrecords
|
records = lrecords
|
||||||
|
|
||||||
log.Info(fmt.Sprintf("Retrieving existing TXT records on %s", name))
|
log.Info(fmt.Sprintf("Retrieving existing TXT records on %s", name))
|
||||||
entries, err := c.DNSRecords(context.Background(), c.zoneID, cloudflare.DNSRecord{Type: "TXT"})
|
entries, _, err := c.ListDNSRecords(context.Background(), cloudflare.ZoneIdentifier(c.zoneID), cloudflare.ListDNSRecordsParams{Type: "TXT"})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -141,14 +141,25 @@ func (c *cloudflareClient) uploadRecords(name string, records map[string]string)
|
|||||||
if path != name {
|
if path != name {
|
||||||
ttl = treeNodeTTLCloudflare // Max TTL permitted by Cloudflare
|
ttl = treeNodeTTLCloudflare // Max TTL permitted by Cloudflare
|
||||||
}
|
}
|
||||||
record := cloudflare.DNSRecord{Type: "TXT", Name: path, Content: val, TTL: ttl}
|
record := cloudflare.CreateDNSRecordParams{Type: "TXT", Name: path, Content: val, TTL: ttl}
|
||||||
_, err = c.CreateDNSRecord(context.Background(), c.zoneID, record)
|
_, err = c.CreateDNSRecord(context.Background(), cloudflare.ZoneIdentifier(c.zoneID), record)
|
||||||
} else if old.Content != val {
|
} else if old.Content != val {
|
||||||
// Entry already exists, only change its content.
|
// Entry already exists, only change its content.
|
||||||
log.Info(fmt.Sprintf("Updating %s from %q to %q", path, old.Content, val))
|
log.Info(fmt.Sprintf("Updating %s from %q to %q", path, old.Content, val))
|
||||||
updated++
|
updated++
|
||||||
old.Content = val
|
|
||||||
err = c.UpdateDNSRecord(context.Background(), c.zoneID, old.ID, old)
|
record := cloudflare.UpdateDNSRecordParams{
|
||||||
|
Type: old.Type,
|
||||||
|
Name: old.Name,
|
||||||
|
Content: val,
|
||||||
|
Data: old.Data,
|
||||||
|
ID: old.ID,
|
||||||
|
Priority: old.Priority,
|
||||||
|
TTL: old.TTL,
|
||||||
|
Proxied: old.Proxied,
|
||||||
|
Tags: old.Tags,
|
||||||
|
}
|
||||||
|
_, err = c.UpdateDNSRecord(context.Background(), cloudflare.ZoneIdentifier(c.zoneID), record)
|
||||||
} else {
|
} else {
|
||||||
skipped++
|
skipped++
|
||||||
log.Debug(fmt.Sprintf("Skipping %s = %q", path, val))
|
log.Debug(fmt.Sprintf("Skipping %s = %q", path, val))
|
||||||
@@ -168,7 +179,7 @@ func (c *cloudflareClient) uploadRecords(name string, records map[string]string)
|
|||||||
// Stale entry, nuke it.
|
// Stale entry, nuke it.
|
||||||
log.Debug(fmt.Sprintf("Deleting %s = %q", path, entry.Content))
|
log.Debug(fmt.Sprintf("Deleting %s = %q", path, entry.Content))
|
||||||
deleted++
|
deleted++
|
||||||
if err := c.DeleteDNSRecord(context.Background(), c.zoneID, entry.ID); err != nil {
|
if err := c.DeleteDNSRecord(context.Background(), cloudflare.ZoneIdentifier(c.zoneID), entry.ID); err != nil {
|
||||||
return fmt.Errorf("failed to delete %s: %v", path, err)
|
return fmt.Errorf("failed to delete %s: %v", path, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import (
|
|||||||
// This test checks that computeChanges/splitChanges create DNS changes in
|
// This test checks that computeChanges/splitChanges create DNS changes in
|
||||||
// leaf-added -> root-changed -> leaf-deleted order.
|
// leaf-added -> root-changed -> leaf-deleted order.
|
||||||
func TestRoute53ChangeSort(t *testing.T) {
|
func TestRoute53ChangeSort(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
testTree0 := map[string]recordSet{
|
testTree0 := map[string]recordSet{
|
||||||
"2kfjogvxdqtxxugbh7gs7naaai.n": {ttl: 3333, values: []string{
|
"2kfjogvxdqtxxugbh7gs7naaai.n": {ttl: 3333, values: []string{
|
||||||
`"enr:-HW4QO1ml1DdXLeZLsUxewnthhUy8eROqkDyoMTyavfks9JlYQIlMFEUoM78PovJDPQrAkrb3LRJ-""vtrymDguKCOIAWAgmlkgnY0iXNlY3AyNTZrMaEDffaGfJzgGhUif1JqFruZlYmA31HzathLSWxfbq_QoQ4"`,
|
`"enr:-HW4QO1ml1DdXLeZLsUxewnthhUy8eROqkDyoMTyavfks9JlYQIlMFEUoM78PovJDPQrAkrb3LRJ-""vtrymDguKCOIAWAgmlkgnY0iXNlY3AyNTZrMaEDffaGfJzgGhUif1JqFruZlYmA31HzathLSWxfbq_QoQ4"`,
|
||||||
@@ -164,6 +165,7 @@ func TestRoute53ChangeSort(t *testing.T) {
|
|||||||
|
|
||||||
// This test checks that computeChanges compares the quoted value of the records correctly.
|
// This test checks that computeChanges compares the quoted value of the records correctly.
|
||||||
func TestRoute53NoChange(t *testing.T) {
|
func TestRoute53NoChange(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
// Existing record set.
|
// Existing record set.
|
||||||
testTree0 := map[string]recordSet{
|
testTree0 := map[string]recordSet{
|
||||||
"n": {ttl: rootTTL, values: []string{
|
"n": {ttl: rootTTL, values: []string{
|
||||||
|
|||||||
@@ -17,27 +17,118 @@
|
|||||||
package ethtest
|
package ethtest
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"compress/gzip"
|
"compress/gzip"
|
||||||
|
"crypto/ecdsa"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"math/big"
|
"math/big"
|
||||||
"os"
|
"os"
|
||||||
|
"path"
|
||||||
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core"
|
||||||
"github.com/ethereum/go-ethereum/core/forkid"
|
"github.com/ethereum/go-ethereum/core/forkid"
|
||||||
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
|
"github.com/ethereum/go-ethereum/eth/protocols/eth"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
|
"golang.org/x/exp/slices"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Chain is a lightweight blockchain-like store which can read a hivechain
|
||||||
|
// created chain.
|
||||||
type Chain struct {
|
type Chain struct {
|
||||||
genesis core.Genesis
|
genesis core.Genesis
|
||||||
blocks []*types.Block
|
blocks []*types.Block
|
||||||
chainConfig *params.ChainConfig
|
state map[common.Address]state.DumpAccount // state of head block
|
||||||
|
senders map[common.Address]*senderInfo
|
||||||
|
config *params.ChainConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewChain takes the given chain.rlp file, and decodes and returns
|
||||||
|
// the blocks from the file.
|
||||||
|
func NewChain(dir string) (*Chain, error) {
|
||||||
|
gen, err := loadGenesis(path.Join(dir, "genesis.json"))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
gblock := gen.ToBlock()
|
||||||
|
|
||||||
|
blocks, err := blocksFromFile(path.Join(dir, "chain.rlp"), gblock)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
state, err := readState(path.Join(dir, "headstate.json"))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
accounts, err := readAccounts(path.Join(dir, "accounts.json"))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &Chain{
|
||||||
|
genesis: gen,
|
||||||
|
blocks: blocks,
|
||||||
|
state: state,
|
||||||
|
senders: accounts,
|
||||||
|
config: gen.Config,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// senderInfo is an account record as output in the "accounts.json" file from
|
||||||
|
// hivechain.
|
||||||
|
type senderInfo struct {
|
||||||
|
Key *ecdsa.PrivateKey `json:"key"`
|
||||||
|
Nonce uint64 `json:"nonce"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Head returns the chain head.
|
||||||
|
func (c *Chain) Head() *types.Block {
|
||||||
|
return c.blocks[c.Len()-1]
|
||||||
|
}
|
||||||
|
|
||||||
|
// AccountsInHashOrder returns all accounts of the head state, ordered by hash of address.
|
||||||
|
func (c *Chain) AccountsInHashOrder() []state.DumpAccount {
|
||||||
|
list := make([]state.DumpAccount, len(c.state))
|
||||||
|
i := 0
|
||||||
|
for addr, acc := range c.state {
|
||||||
|
addr := addr
|
||||||
|
list[i] = acc
|
||||||
|
list[i].Address = &addr
|
||||||
|
if len(acc.AddressHash) != 32 {
|
||||||
|
panic(fmt.Errorf("missing/invalid SecureKey in dump account %v", addr))
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
slices.SortFunc(list, func(x, y state.DumpAccount) int {
|
||||||
|
return bytes.Compare(x.AddressHash, y.AddressHash)
|
||||||
|
})
|
||||||
|
return list
|
||||||
|
}
|
||||||
|
|
||||||
|
// CodeHashes returns all bytecode hashes contained in the head state.
|
||||||
|
func (c *Chain) CodeHashes() []common.Hash {
|
||||||
|
var hashes []common.Hash
|
||||||
|
seen := make(map[common.Hash]struct{})
|
||||||
|
seen[types.EmptyCodeHash] = struct{}{}
|
||||||
|
for _, acc := range c.state {
|
||||||
|
h := common.BytesToHash(acc.CodeHash)
|
||||||
|
if _, ok := seen[h]; ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
hashes = append(hashes, h)
|
||||||
|
seen[h] = struct{}{}
|
||||||
|
}
|
||||||
|
slices.SortFunc(hashes, (common.Hash).Cmp)
|
||||||
|
return hashes
|
||||||
}
|
}
|
||||||
|
|
||||||
// Len returns the length of the chain.
|
// Len returns the length of the chain.
|
||||||
@@ -45,6 +136,11 @@ func (c *Chain) Len() int {
|
|||||||
return len(c.blocks)
|
return len(c.blocks)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ForkID gets the fork id of the chain.
|
||||||
|
func (c *Chain) ForkID() forkid.ID {
|
||||||
|
return forkid.NewID(c.config, c.blocks[0], uint64(c.Len()), c.blocks[c.Len()-1].Time())
|
||||||
|
}
|
||||||
|
|
||||||
// TD calculates the total difficulty of the chain at the
|
// TD calculates the total difficulty of the chain at the
|
||||||
// chain head.
|
// chain head.
|
||||||
func (c *Chain) TD() *big.Int {
|
func (c *Chain) TD() *big.Int {
|
||||||
@@ -55,19 +151,12 @@ func (c *Chain) TD() *big.Int {
|
|||||||
return sum
|
return sum
|
||||||
}
|
}
|
||||||
|
|
||||||
// TotalDifficultyAt calculates the total difficulty of the chain
|
// GetBlock returns the block at the specified number.
|
||||||
// at the given block height.
|
func (c *Chain) GetBlock(number int) *types.Block {
|
||||||
func (c *Chain) TotalDifficultyAt(height int) *big.Int {
|
return c.blocks[number]
|
||||||
sum := new(big.Int)
|
|
||||||
if height >= c.Len() {
|
|
||||||
return sum
|
|
||||||
}
|
|
||||||
for _, block := range c.blocks[:height+1] {
|
|
||||||
sum.Add(sum, block.Difficulty())
|
|
||||||
}
|
|
||||||
return sum
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RootAt returns the state root for the block at the given height.
|
||||||
func (c *Chain) RootAt(height int) common.Hash {
|
func (c *Chain) RootAt(height int) common.Hash {
|
||||||
if height < c.Len() {
|
if height < c.Len() {
|
||||||
return c.blocks[height].Root()
|
return c.blocks[height].Root()
|
||||||
@@ -75,37 +164,56 @@ func (c *Chain) RootAt(height int) common.Hash {
|
|||||||
return common.Hash{}
|
return common.Hash{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ForkID gets the fork id of the chain.
|
// GetSender returns the address associated with account at the index in the
|
||||||
func (c *Chain) ForkID() forkid.ID {
|
// pre-funded accounts list.
|
||||||
return forkid.NewID(c.chainConfig, c.blocks[0].Hash(), uint64(c.Len()), c.blocks[0].Time())
|
func (c *Chain) GetSender(idx int) (common.Address, uint64) {
|
||||||
}
|
var accounts Addresses
|
||||||
|
for addr := range c.senders {
|
||||||
// Shorten returns a copy chain of a desired height from the imported
|
accounts = append(accounts, addr)
|
||||||
func (c *Chain) Shorten(height int) *Chain {
|
|
||||||
blocks := make([]*types.Block, height)
|
|
||||||
copy(blocks, c.blocks[:height])
|
|
||||||
|
|
||||||
config := *c.chainConfig
|
|
||||||
return &Chain{
|
|
||||||
blocks: blocks,
|
|
||||||
chainConfig: &config,
|
|
||||||
}
|
}
|
||||||
|
sort.Sort(accounts)
|
||||||
|
addr := accounts[idx]
|
||||||
|
return addr, c.senders[addr].Nonce
|
||||||
}
|
}
|
||||||
|
|
||||||
// Head returns the chain head.
|
// IncNonce increases the specified signing account's pending nonce.
|
||||||
func (c *Chain) Head() *types.Block {
|
func (c *Chain) IncNonce(addr common.Address, amt uint64) {
|
||||||
return c.blocks[c.Len()-1]
|
if _, ok := c.senders[addr]; !ok {
|
||||||
|
panic("nonce increment for non-signer")
|
||||||
|
}
|
||||||
|
c.senders[addr].Nonce += amt
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Chain) GetHeaders(req *GetBlockHeaders) ([]*types.Header, error) {
|
// Balance returns the balance of an account at the head of the chain.
|
||||||
|
func (c *Chain) Balance(addr common.Address) *big.Int {
|
||||||
|
bal := new(big.Int)
|
||||||
|
if acc, ok := c.state[addr]; ok {
|
||||||
|
bal, _ = bal.SetString(acc.Balance, 10)
|
||||||
|
}
|
||||||
|
return bal
|
||||||
|
}
|
||||||
|
|
||||||
|
// SignTx signs a transaction for the specified from account, so long as that
|
||||||
|
// account was in the hivechain accounts dump.
|
||||||
|
func (c *Chain) SignTx(from common.Address, tx *types.Transaction) (*types.Transaction, error) {
|
||||||
|
signer := types.LatestSigner(c.config)
|
||||||
|
acc, ok := c.senders[from]
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("account not available for signing: %s", from)
|
||||||
|
}
|
||||||
|
return types.SignTx(tx, signer, acc.Key)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetHeaders returns the headers base on an ethGetPacketHeadersPacket.
|
||||||
|
func (c *Chain) GetHeaders(req *eth.GetBlockHeadersPacket) ([]*types.Header, error) {
|
||||||
if req.Amount < 1 {
|
if req.Amount < 1 {
|
||||||
return nil, errors.New("no block headers requested")
|
return nil, errors.New("no block headers requested")
|
||||||
}
|
}
|
||||||
|
var (
|
||||||
headers := make([]*types.Header, req.Amount)
|
headers = make([]*types.Header, req.Amount)
|
||||||
var blockNumber uint64
|
blockNumber uint64
|
||||||
|
)
|
||||||
// range over blocks to check if our chain has the requested header
|
// Range over blocks to check if our chain has the requested header.
|
||||||
for _, block := range c.blocks {
|
for _, block := range c.blocks {
|
||||||
if block.Hash() == req.Origin.Hash || block.Number().Uint64() == req.Origin.Number {
|
if block.Hash() == req.Origin.Hash || block.Number().Uint64() == req.Origin.Number {
|
||||||
headers[0] = block.Header()
|
headers[0] = block.Header()
|
||||||
@@ -115,40 +223,30 @@ func (c *Chain) GetHeaders(req *GetBlockHeaders) ([]*types.Header, error) {
|
|||||||
if headers[0] == nil {
|
if headers[0] == nil {
|
||||||
return nil, fmt.Errorf("no headers found for given origin number %v, hash %v", req.Origin.Number, req.Origin.Hash)
|
return nil, fmt.Errorf("no headers found for given origin number %v, hash %v", req.Origin.Number, req.Origin.Hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
if req.Reverse {
|
if req.Reverse {
|
||||||
for i := 1; i < int(req.Amount); i++ {
|
for i := 1; i < int(req.Amount); i++ {
|
||||||
blockNumber -= (1 - req.Skip)
|
blockNumber -= (1 - req.Skip)
|
||||||
headers[i] = c.blocks[blockNumber].Header()
|
headers[i] = c.blocks[blockNumber].Header()
|
||||||
}
|
}
|
||||||
|
|
||||||
return headers, nil
|
return headers, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := 1; i < int(req.Amount); i++ {
|
for i := 1; i < int(req.Amount); i++ {
|
||||||
blockNumber += (1 + req.Skip)
|
blockNumber += (1 + req.Skip)
|
||||||
headers[i] = c.blocks[blockNumber].Header()
|
headers[i] = c.blocks[blockNumber].Header()
|
||||||
}
|
}
|
||||||
|
|
||||||
return headers, nil
|
return headers, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// loadChain takes the given chain.rlp file, and decodes and returns
|
// Shorten returns a copy chain of a desired height from the imported
|
||||||
// the blocks from the file.
|
func (c *Chain) Shorten(height int) *Chain {
|
||||||
func loadChain(chainfile string, genesis string) (*Chain, error) {
|
blocks := make([]*types.Block, height)
|
||||||
gen, err := loadGenesis(genesis)
|
copy(blocks, c.blocks[:height])
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
gblock := gen.ToBlock()
|
|
||||||
|
|
||||||
blocks, err := blocksFromFile(chainfile, gblock)
|
config := *c.config
|
||||||
if err != nil {
|
return &Chain{
|
||||||
return nil, err
|
blocks: blocks,
|
||||||
|
config: &config,
|
||||||
}
|
}
|
||||||
|
|
||||||
c := &Chain{genesis: gen, blocks: blocks, chainConfig: gen.Config}
|
|
||||||
return c, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadGenesis(genesisFile string) (core.Genesis, error) {
|
func loadGenesis(genesisFile string) (core.Genesis, error) {
|
||||||
@@ -163,6 +261,22 @@ func loadGenesis(genesisFile string) (core.Genesis, error) {
|
|||||||
return gen, nil
|
return gen, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Addresses []common.Address
|
||||||
|
|
||||||
|
func (a Addresses) Len() int {
|
||||||
|
return len(a)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a Addresses) Less(i, j int) bool {
|
||||||
|
return bytes.Compare(a[i][:], a[j][:]) < 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a Addresses) Swap(i, j int) {
|
||||||
|
tmp := a[i]
|
||||||
|
a[i] = a[j]
|
||||||
|
a[j] = tmp
|
||||||
|
}
|
||||||
|
|
||||||
func blocksFromFile(chainfile string, gblock *types.Block) ([]*types.Block, error) {
|
func blocksFromFile(chainfile string, gblock *types.Block) ([]*types.Block, error) {
|
||||||
// Load chain.rlp.
|
// Load chain.rlp.
|
||||||
fh, err := os.Open(chainfile)
|
fh, err := os.Open(chainfile)
|
||||||
@@ -193,3 +307,47 @@ func blocksFromFile(chainfile string, gblock *types.Block) ([]*types.Block, erro
|
|||||||
}
|
}
|
||||||
return blocks, nil
|
return blocks, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func readState(file string) (map[common.Address]state.DumpAccount, error) {
|
||||||
|
f, err := os.ReadFile(file)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("unable to read state: %v", err)
|
||||||
|
}
|
||||||
|
var dump state.Dump
|
||||||
|
if err := json.Unmarshal(f, &dump); err != nil {
|
||||||
|
return nil, fmt.Errorf("unable to unmarshal state: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
state := make(map[common.Address]state.DumpAccount)
|
||||||
|
for key, acct := range dump.Accounts {
|
||||||
|
var addr common.Address
|
||||||
|
if err := addr.UnmarshalText([]byte(key)); err != nil {
|
||||||
|
return nil, fmt.Errorf("invalid address %q", key)
|
||||||
|
}
|
||||||
|
state[addr] = acct
|
||||||
|
}
|
||||||
|
return state, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func readAccounts(file string) (map[common.Address]*senderInfo, error) {
|
||||||
|
f, err := os.ReadFile(file)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("unable to read state: %v", err)
|
||||||
|
}
|
||||||
|
type account struct {
|
||||||
|
Key hexutil.Bytes `json:"key"`
|
||||||
|
}
|
||||||
|
keys := make(map[common.Address]account)
|
||||||
|
if err := json.Unmarshal(f, &keys); err != nil {
|
||||||
|
return nil, fmt.Errorf("unable to unmarshal accounts: %v", err)
|
||||||
|
}
|
||||||
|
accounts := make(map[common.Address]*senderInfo)
|
||||||
|
for addr, acc := range keys {
|
||||||
|
pk, err := crypto.HexToECDSA(common.Bytes2Hex(acc.Key))
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("unable to read private key for %s: %v", err, addr)
|
||||||
|
}
|
||||||
|
accounts[addr] = &senderInfo{Key: pk, Nonce: 0}
|
||||||
|
}
|
||||||
|
return accounts, nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ import (
|
|||||||
// TestEthProtocolNegotiation tests whether the test suite
|
// TestEthProtocolNegotiation tests whether the test suite
|
||||||
// can negotiate the highest eth protocol in a status message exchange
|
// can negotiate the highest eth protocol in a status message exchange
|
||||||
func TestEthProtocolNegotiation(t *testing.T) {
|
func TestEthProtocolNegotiation(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
var tests = []struct {
|
var tests = []struct {
|
||||||
conn *Conn
|
conn *Conn
|
||||||
caps []p2p.Cap
|
caps []p2p.Cap
|
||||||
@@ -122,30 +123,27 @@ func TestEthProtocolNegotiation(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestChain_GetHeaders tests whether the test suite can correctly
|
// TestChainGetHeaders tests whether the test suite can correctly
|
||||||
// respond to a GetBlockHeaders request from a node.
|
// respond to a GetBlockHeaders request from a node.
|
||||||
func TestChain_GetHeaders(t *testing.T) {
|
func TestChainGetHeaders(t *testing.T) {
|
||||||
chainFile, err := filepath.Abs("./testdata/chain.rlp")
|
t.Parallel()
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
genesisFile, err := filepath.Abs("./testdata/genesis.json")
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
chain, err := loadChain(chainFile, genesisFile)
|
dir, err := filepath.Abs("./testdata")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
chain, err := NewChain(dir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
var tests = []struct {
|
var tests = []struct {
|
||||||
req GetBlockHeaders
|
req eth.GetBlockHeadersPacket
|
||||||
expected []*types.Header
|
expected []*types.Header
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
req: GetBlockHeaders{
|
req: eth.GetBlockHeadersPacket{
|
||||||
GetBlockHeadersPacket: ð.GetBlockHeadersPacket{
|
GetBlockHeadersRequest: ð.GetBlockHeadersRequest{
|
||||||
Origin: eth.HashOrNumber{Number: uint64(2)},
|
Origin: eth.HashOrNumber{Number: uint64(2)},
|
||||||
Amount: uint64(5),
|
Amount: uint64(5),
|
||||||
Skip: 1,
|
Skip: 1,
|
||||||
@@ -161,8 +159,8 @@ func TestChain_GetHeaders(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
req: GetBlockHeaders{
|
req: eth.GetBlockHeadersPacket{
|
||||||
GetBlockHeadersPacket: ð.GetBlockHeadersPacket{
|
GetBlockHeadersRequest: ð.GetBlockHeadersRequest{
|
||||||
Origin: eth.HashOrNumber{Number: uint64(chain.Len() - 1)},
|
Origin: eth.HashOrNumber{Number: uint64(chain.Len() - 1)},
|
||||||
Amount: uint64(3),
|
Amount: uint64(3),
|
||||||
Skip: 0,
|
Skip: 0,
|
||||||
@@ -176,8 +174,8 @@ func TestChain_GetHeaders(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
req: GetBlockHeaders{
|
req: eth.GetBlockHeadersPacket{
|
||||||
GetBlockHeadersPacket: ð.GetBlockHeadersPacket{
|
GetBlockHeadersRequest: ð.GetBlockHeadersRequest{
|
||||||
Origin: eth.HashOrNumber{Hash: chain.Head().Hash()},
|
Origin: eth.HashOrNumber{Hash: chain.Head().Hash()},
|
||||||
Amount: uint64(1),
|
Amount: uint64(1),
|
||||||
Skip: 0,
|
Skip: 0,
|
||||||
|
|||||||
370
cmd/devp2p/internal/ethtest/conn.go
Normal file
370
cmd/devp2p/internal/ethtest/conn.go
Normal file
@@ -0,0 +1,370 @@
|
|||||||
|
// Copyright 2023 The go-ethereum Authors
|
||||||
|
// This file is part of go-ethereum.
|
||||||
|
//
|
||||||
|
// go-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.
|
||||||
|
//
|
||||||
|
// go-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 go-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package ethtest
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/ecdsa"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"reflect"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/davecgh/go-spew/spew"
|
||||||
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
|
"github.com/ethereum/go-ethereum/eth/protocols/eth"
|
||||||
|
"github.com/ethereum/go-ethereum/eth/protocols/snap"
|
||||||
|
"github.com/ethereum/go-ethereum/p2p"
|
||||||
|
"github.com/ethereum/go-ethereum/p2p/rlpx"
|
||||||
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
pretty = spew.ConfigState{
|
||||||
|
Indent: " ",
|
||||||
|
DisableCapacities: true,
|
||||||
|
DisablePointerAddresses: true,
|
||||||
|
SortKeys: true,
|
||||||
|
}
|
||||||
|
timeout = 2 * time.Second
|
||||||
|
)
|
||||||
|
|
||||||
|
// dial attempts to dial the given node and perform a handshake, returning the
|
||||||
|
// created Conn if successful.
|
||||||
|
func (s *Suite) dial() (*Conn, error) {
|
||||||
|
key, _ := crypto.GenerateKey()
|
||||||
|
return s.dialAs(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
// dialAs attempts to dial a given node and perform a handshake using the given
|
||||||
|
// private key.
|
||||||
|
func (s *Suite) dialAs(key *ecdsa.PrivateKey) (*Conn, error) {
|
||||||
|
fd, err := net.Dial("tcp", fmt.Sprintf("%v:%d", s.Dest.IP(), s.Dest.TCP()))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
conn := Conn{Conn: rlpx.NewConn(fd, s.Dest.Pubkey())}
|
||||||
|
conn.ourKey = key
|
||||||
|
_, err = conn.Handshake(conn.ourKey)
|
||||||
|
if err != nil {
|
||||||
|
conn.Close()
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
conn.caps = []p2p.Cap{
|
||||||
|
{Name: "eth", Version: 67},
|
||||||
|
{Name: "eth", Version: 68},
|
||||||
|
}
|
||||||
|
conn.ourHighestProtoVersion = 68
|
||||||
|
return &conn, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// dialSnap creates a connection with snap/1 capability.
|
||||||
|
func (s *Suite) dialSnap() (*Conn, error) {
|
||||||
|
conn, err := s.dial()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("dial failed: %v", err)
|
||||||
|
}
|
||||||
|
conn.caps = append(conn.caps, p2p.Cap{Name: "snap", Version: 1})
|
||||||
|
conn.ourHighestSnapProtoVersion = 1
|
||||||
|
return conn, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Conn represents an individual connection with a peer
|
||||||
|
type Conn struct {
|
||||||
|
*rlpx.Conn
|
||||||
|
ourKey *ecdsa.PrivateKey
|
||||||
|
negotiatedProtoVersion uint
|
||||||
|
negotiatedSnapProtoVersion uint
|
||||||
|
ourHighestProtoVersion uint
|
||||||
|
ourHighestSnapProtoVersion uint
|
||||||
|
caps []p2p.Cap
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read reads a packet from the connection.
|
||||||
|
func (c *Conn) Read() (uint64, []byte, error) {
|
||||||
|
c.SetReadDeadline(time.Now().Add(timeout))
|
||||||
|
code, data, _, err := c.Conn.Read()
|
||||||
|
if err != nil {
|
||||||
|
return 0, nil, err
|
||||||
|
}
|
||||||
|
return code, data, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadMsg attempts to read a devp2p message with a specific code.
|
||||||
|
func (c *Conn) ReadMsg(proto Proto, code uint64, msg any) error {
|
||||||
|
c.SetReadDeadline(time.Now().Add(timeout))
|
||||||
|
for {
|
||||||
|
got, data, err := c.Read()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if protoOffset(proto)+code == got {
|
||||||
|
return rlp.DecodeBytes(data, msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write writes a eth packet to the connection.
|
||||||
|
func (c *Conn) Write(proto Proto, code uint64, msg any) error {
|
||||||
|
c.SetWriteDeadline(time.Now().Add(timeout))
|
||||||
|
payload, err := rlp.EncodeToBytes(msg)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, err = c.Conn.Write(protoOffset(proto)+code, payload)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadEth reads an Eth sub-protocol wire message.
|
||||||
|
func (c *Conn) ReadEth() (any, error) {
|
||||||
|
c.SetReadDeadline(time.Now().Add(timeout))
|
||||||
|
for {
|
||||||
|
code, data, _, err := c.Conn.Read()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if code == pingMsg {
|
||||||
|
c.Write(baseProto, pongMsg, []byte{})
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if getProto(code) != ethProto {
|
||||||
|
// Read until eth message.
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
code -= baseProtoLen
|
||||||
|
|
||||||
|
var msg any
|
||||||
|
switch int(code) {
|
||||||
|
case eth.StatusMsg:
|
||||||
|
msg = new(eth.StatusPacket)
|
||||||
|
case eth.GetBlockHeadersMsg:
|
||||||
|
msg = new(eth.GetBlockHeadersPacket)
|
||||||
|
case eth.BlockHeadersMsg:
|
||||||
|
msg = new(eth.BlockHeadersPacket)
|
||||||
|
case eth.GetBlockBodiesMsg:
|
||||||
|
msg = new(eth.GetBlockBodiesPacket)
|
||||||
|
case eth.BlockBodiesMsg:
|
||||||
|
msg = new(eth.BlockBodiesPacket)
|
||||||
|
case eth.NewBlockMsg:
|
||||||
|
msg = new(eth.NewBlockPacket)
|
||||||
|
case eth.NewBlockHashesMsg:
|
||||||
|
msg = new(eth.NewBlockHashesPacket)
|
||||||
|
case eth.TransactionsMsg:
|
||||||
|
msg = new(eth.TransactionsPacket)
|
||||||
|
case eth.NewPooledTransactionHashesMsg:
|
||||||
|
msg = new(eth.NewPooledTransactionHashesPacket)
|
||||||
|
case eth.GetPooledTransactionsMsg:
|
||||||
|
msg = new(eth.GetPooledTransactionsPacket)
|
||||||
|
case eth.PooledTransactionsMsg:
|
||||||
|
msg = new(eth.PooledTransactionsPacket)
|
||||||
|
default:
|
||||||
|
panic(fmt.Sprintf("unhandled eth msg code %d", code))
|
||||||
|
}
|
||||||
|
if err := rlp.DecodeBytes(data, msg); err != nil {
|
||||||
|
return nil, fmt.Errorf("unable to decode eth msg: %v", err)
|
||||||
|
}
|
||||||
|
return msg, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadSnap reads a snap/1 response with the given id from the connection.
|
||||||
|
func (c *Conn) ReadSnap() (any, error) {
|
||||||
|
c.SetReadDeadline(time.Now().Add(timeout))
|
||||||
|
for {
|
||||||
|
code, data, _, err := c.Conn.Read()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if getProto(code) != snapProto {
|
||||||
|
// Read until snap message.
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
code -= baseProtoLen + ethProtoLen
|
||||||
|
|
||||||
|
var msg any
|
||||||
|
switch int(code) {
|
||||||
|
case snap.GetAccountRangeMsg:
|
||||||
|
msg = new(snap.GetAccountRangePacket)
|
||||||
|
case snap.AccountRangeMsg:
|
||||||
|
msg = new(snap.AccountRangePacket)
|
||||||
|
case snap.GetStorageRangesMsg:
|
||||||
|
msg = new(snap.GetStorageRangesPacket)
|
||||||
|
case snap.StorageRangesMsg:
|
||||||
|
msg = new(snap.StorageRangesPacket)
|
||||||
|
case snap.GetByteCodesMsg:
|
||||||
|
msg = new(snap.GetByteCodesPacket)
|
||||||
|
case snap.ByteCodesMsg:
|
||||||
|
msg = new(snap.ByteCodesPacket)
|
||||||
|
case snap.GetTrieNodesMsg:
|
||||||
|
msg = new(snap.GetTrieNodesPacket)
|
||||||
|
case snap.TrieNodesMsg:
|
||||||
|
msg = new(snap.TrieNodesPacket)
|
||||||
|
default:
|
||||||
|
panic(fmt.Errorf("unhandled snap code: %d", code))
|
||||||
|
}
|
||||||
|
if err := rlp.DecodeBytes(data, msg); err != nil {
|
||||||
|
return nil, fmt.Errorf("could not rlp decode message: %v", err)
|
||||||
|
}
|
||||||
|
return msg, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// peer performs both the protocol handshake and the status message
|
||||||
|
// exchange with the node in order to peer with it.
|
||||||
|
func (c *Conn) peer(chain *Chain, status *eth.StatusPacket) error {
|
||||||
|
if err := c.handshake(); err != nil {
|
||||||
|
return fmt.Errorf("handshake failed: %v", err)
|
||||||
|
}
|
||||||
|
if err := c.statusExchange(chain, status); err != nil {
|
||||||
|
return fmt.Errorf("status exchange failed: %v", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// handshake performs a protocol handshake with the node.
|
||||||
|
func (c *Conn) handshake() error {
|
||||||
|
// Write hello to client.
|
||||||
|
pub0 := crypto.FromECDSAPub(&c.ourKey.PublicKey)[1:]
|
||||||
|
ourHandshake := &protoHandshake{
|
||||||
|
Version: 5,
|
||||||
|
Caps: c.caps,
|
||||||
|
ID: pub0,
|
||||||
|
}
|
||||||
|
if err := c.Write(baseProto, handshakeMsg, ourHandshake); err != nil {
|
||||||
|
return fmt.Errorf("write to connection failed: %v", err)
|
||||||
|
}
|
||||||
|
// Read hello from client.
|
||||||
|
code, data, err := c.Read()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("erroring reading handshake: %v", err)
|
||||||
|
}
|
||||||
|
switch code {
|
||||||
|
case handshakeMsg:
|
||||||
|
msg := new(protoHandshake)
|
||||||
|
if err := rlp.DecodeBytes(data, &msg); err != nil {
|
||||||
|
return fmt.Errorf("error decoding handshake msg: %v", err)
|
||||||
|
}
|
||||||
|
// Set snappy if version is at least 5.
|
||||||
|
if msg.Version >= 5 {
|
||||||
|
c.SetSnappy(true)
|
||||||
|
}
|
||||||
|
c.negotiateEthProtocol(msg.Caps)
|
||||||
|
if c.negotiatedProtoVersion == 0 {
|
||||||
|
return fmt.Errorf("could not negotiate eth protocol (remote caps: %v, local eth version: %v)", msg.Caps, c.ourHighestProtoVersion)
|
||||||
|
}
|
||||||
|
// If we require snap, verify that it was negotiated.
|
||||||
|
if c.ourHighestSnapProtoVersion != c.negotiatedSnapProtoVersion {
|
||||||
|
return fmt.Errorf("could not negotiate snap protocol (remote caps: %v, local snap version: %v)", msg.Caps, c.ourHighestSnapProtoVersion)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("bad handshake: got msg code %d", code)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// negotiateEthProtocol sets the Conn's eth protocol version to highest
|
||||||
|
// advertised capability from peer.
|
||||||
|
func (c *Conn) negotiateEthProtocol(caps []p2p.Cap) {
|
||||||
|
var highestEthVersion uint
|
||||||
|
var highestSnapVersion uint
|
||||||
|
for _, capability := range caps {
|
||||||
|
switch capability.Name {
|
||||||
|
case "eth":
|
||||||
|
if capability.Version > highestEthVersion && capability.Version <= c.ourHighestProtoVersion {
|
||||||
|
highestEthVersion = capability.Version
|
||||||
|
}
|
||||||
|
case "snap":
|
||||||
|
if capability.Version > highestSnapVersion && capability.Version <= c.ourHighestSnapProtoVersion {
|
||||||
|
highestSnapVersion = capability.Version
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
c.negotiatedProtoVersion = highestEthVersion
|
||||||
|
c.negotiatedSnapProtoVersion = highestSnapVersion
|
||||||
|
}
|
||||||
|
|
||||||
|
// statusExchange performs a `Status` message exchange with the given node.
|
||||||
|
func (c *Conn) statusExchange(chain *Chain, status *eth.StatusPacket) error {
|
||||||
|
loop:
|
||||||
|
for {
|
||||||
|
code, data, err := c.Read()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to read from connection: %w", err)
|
||||||
|
}
|
||||||
|
switch code {
|
||||||
|
case eth.StatusMsg + protoOffset(ethProto):
|
||||||
|
msg := new(eth.StatusPacket)
|
||||||
|
if err := rlp.DecodeBytes(data, &msg); err != nil {
|
||||||
|
return fmt.Errorf("error decoding status packet: %w", err)
|
||||||
|
}
|
||||||
|
if have, want := msg.Head, chain.blocks[chain.Len()-1].Hash(); have != want {
|
||||||
|
return fmt.Errorf("wrong head block in status, want: %#x (block %d) have %#x",
|
||||||
|
want, chain.blocks[chain.Len()-1].NumberU64(), have)
|
||||||
|
}
|
||||||
|
if have, want := msg.TD.Cmp(chain.TD()), 0; have != want {
|
||||||
|
return fmt.Errorf("wrong TD in status: have %v want %v", have, want)
|
||||||
|
}
|
||||||
|
if have, want := msg.ForkID, chain.ForkID(); !reflect.DeepEqual(have, want) {
|
||||||
|
return fmt.Errorf("wrong fork ID in status: have %v, want %v", have, want)
|
||||||
|
}
|
||||||
|
if have, want := msg.ProtocolVersion, c.ourHighestProtoVersion; have != uint32(want) {
|
||||||
|
return fmt.Errorf("wrong protocol version: have %v, want %v", have, want)
|
||||||
|
}
|
||||||
|
// make sure eth protocol version is set for negotiation
|
||||||
|
if c.negotiatedProtoVersion == 0 {
|
||||||
|
return errors.New("eth protocol version must be set in Conn")
|
||||||
|
}
|
||||||
|
if status == nil {
|
||||||
|
// default status message
|
||||||
|
status = ð.StatusPacket{
|
||||||
|
ProtocolVersion: uint32(c.negotiatedProtoVersion),
|
||||||
|
NetworkID: chain.config.ChainID.Uint64(),
|
||||||
|
TD: chain.TD(),
|
||||||
|
Head: chain.blocks[chain.Len()-1].Hash(),
|
||||||
|
Genesis: chain.blocks[0].Hash(),
|
||||||
|
ForkID: chain.ForkID(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err := c.Write(ethProto, eth.StatusMsg, status); err != nil {
|
||||||
|
return fmt.Errorf("write to connection failed: %v", err)
|
||||||
|
}
|
||||||
|
case eth.UpgradeStatusMsg + protoOffset(ethProto):
|
||||||
|
msg := new(eth.UpgradeStatusPacket)
|
||||||
|
if err := rlp.DecodeBytes(data, &msg); err != nil {
|
||||||
|
return fmt.Errorf("error decoding status packet: %w", err)
|
||||||
|
}
|
||||||
|
if err := c.Write(ethProto, eth.UpgradeStatusMsg, msg); err != nil {
|
||||||
|
return fmt.Errorf("write to connection failed: %v", err)
|
||||||
|
}
|
||||||
|
break loop
|
||||||
|
case discMsg:
|
||||||
|
var msg []p2p.DiscReason
|
||||||
|
if rlp.DecodeBytes(data, &msg); len(msg) == 0 {
|
||||||
|
return errors.New("invalid disconnect message")
|
||||||
|
}
|
||||||
|
return fmt.Errorf("disconnect received: %v", pretty.Sdump(msg))
|
||||||
|
case pingMsg:
|
||||||
|
// TODO (renaynay): in the future, this should be an error
|
||||||
|
// (PINGs should not be a response upon fresh connection)
|
||||||
|
c.Write(baseProto, pongMsg, nil)
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("bad status message: code %d", code)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
69
cmd/devp2p/internal/ethtest/engine.go
Normal file
69
cmd/devp2p/internal/ethtest/engine.go
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
// Copyright 2023 The go-ethereum Authors
|
||||||
|
// This file is part of go-ethereum.
|
||||||
|
//
|
||||||
|
// go-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.
|
||||||
|
//
|
||||||
|
// go-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 go-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package ethtest
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/golang-jwt/jwt/v4"
|
||||||
|
)
|
||||||
|
|
||||||
|
// EngineClient is a wrapper around engine-related data.
|
||||||
|
type EngineClient struct {
|
||||||
|
url string
|
||||||
|
jwt [32]byte
|
||||||
|
headfcu []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewEngineClient creates a new engine client.
|
||||||
|
func NewEngineClient(dir, url, jwt string) (*EngineClient, error) {
|
||||||
|
headfcu, err := os.ReadFile(path.Join(dir, "headfcu.json"))
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to read headfcu: %w", err)
|
||||||
|
}
|
||||||
|
return &EngineClient{url, common.HexToHash(jwt), headfcu}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// token returns the jwt claim token for authorization.
|
||||||
|
func (ec *EngineClient) token() string {
|
||||||
|
claims := jwt.RegisteredClaims{IssuedAt: jwt.NewNumericDate(time.Now())}
|
||||||
|
token, _ := jwt.NewWithClaims(jwt.SigningMethodHS256, claims).SignedString(ec.jwt[:])
|
||||||
|
return token
|
||||||
|
}
|
||||||
|
|
||||||
|
// sendForkchoiceUpdated sends an fcu for the head of the generated chain.
|
||||||
|
func (ec *EngineClient) sendForkchoiceUpdated() error {
|
||||||
|
var (
|
||||||
|
req, _ = http.NewRequest(http.MethodPost, ec.url, io.NopCloser(bytes.NewReader(ec.headfcu)))
|
||||||
|
header = make(http.Header)
|
||||||
|
)
|
||||||
|
// Set header
|
||||||
|
header.Set("accept", "application/json")
|
||||||
|
header.Set("content-type", "application/json")
|
||||||
|
header.Set("Authorization", fmt.Sprintf("Bearer %v", ec.token()))
|
||||||
|
req.Header = header
|
||||||
|
|
||||||
|
_, err := new(http.Client).Do(req)
|
||||||
|
return err
|
||||||
|
}
|
||||||
@@ -1,675 +0,0 @@
|
|||||||
// Copyright 2021 The go-ethereum Authors
|
|
||||||
// This file is part of go-ethereum.
|
|
||||||
//
|
|
||||||
// go-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.
|
|
||||||
//
|
|
||||||
// go-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 go-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
package ethtest
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"net"
|
|
||||||
"reflect"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/davecgh/go-spew/spew"
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
|
||||||
"github.com/ethereum/go-ethereum/eth/protocols/eth"
|
|
||||||
"github.com/ethereum/go-ethereum/internal/utesting"
|
|
||||||
"github.com/ethereum/go-ethereum/log"
|
|
||||||
"github.com/ethereum/go-ethereum/p2p"
|
|
||||||
"github.com/ethereum/go-ethereum/p2p/rlpx"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
pretty = spew.ConfigState{
|
|
||||||
Indent: " ",
|
|
||||||
DisableCapacities: true,
|
|
||||||
DisablePointerAddresses: true,
|
|
||||||
SortKeys: true,
|
|
||||||
}
|
|
||||||
timeout = 20 * time.Second
|
|
||||||
)
|
|
||||||
|
|
||||||
// dial attempts to dial the given node and perform a handshake,
|
|
||||||
// returning the created Conn if successful.
|
|
||||||
func (s *Suite) dial() (*Conn, error) {
|
|
||||||
// dial
|
|
||||||
fd, err := net.Dial("tcp", fmt.Sprintf("%v:%d", s.Dest.IP(), s.Dest.TCP()))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
conn := Conn{Conn: rlpx.NewConn(fd, s.Dest.Pubkey())}
|
|
||||||
// do encHandshake
|
|
||||||
conn.ourKey, _ = crypto.GenerateKey()
|
|
||||||
_, err = conn.Handshake(conn.ourKey)
|
|
||||||
if err != nil {
|
|
||||||
conn.Close()
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
// set default p2p capabilities
|
|
||||||
conn.caps = []p2p.Cap{
|
|
||||||
{Name: "eth", Version: 66},
|
|
||||||
{Name: "eth", Version: 67},
|
|
||||||
{Name: "eth", Version: 68},
|
|
||||||
}
|
|
||||||
conn.ourHighestProtoVersion = 68
|
|
||||||
return &conn, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// dialSnap creates a connection with snap/1 capability.
|
|
||||||
func (s *Suite) dialSnap() (*Conn, error) {
|
|
||||||
conn, err := s.dial()
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("dial failed: %v", err)
|
|
||||||
}
|
|
||||||
conn.caps = append(conn.caps, p2p.Cap{Name: "snap", Version: 1})
|
|
||||||
conn.ourHighestSnapProtoVersion = 1
|
|
||||||
return conn, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// peer performs both the protocol handshake and the status message
|
|
||||||
// exchange with the node in order to peer with it.
|
|
||||||
func (c *Conn) peer(chain *Chain, status *Status) error {
|
|
||||||
if err := c.handshake(); err != nil {
|
|
||||||
return fmt.Errorf("handshake failed: %v", err)
|
|
||||||
}
|
|
||||||
if _, err := c.statusExchange(chain, status); err != nil {
|
|
||||||
return fmt.Errorf("status exchange failed: %v", err)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// handshake performs a protocol handshake with the node.
|
|
||||||
func (c *Conn) handshake() error {
|
|
||||||
defer c.SetDeadline(time.Time{})
|
|
||||||
c.SetDeadline(time.Now().Add(10 * time.Second))
|
|
||||||
// write hello to client
|
|
||||||
pub0 := crypto.FromECDSAPub(&c.ourKey.PublicKey)[1:]
|
|
||||||
ourHandshake := &Hello{
|
|
||||||
Version: 5,
|
|
||||||
Caps: c.caps,
|
|
||||||
ID: pub0,
|
|
||||||
}
|
|
||||||
if err := c.Write(ourHandshake); err != nil {
|
|
||||||
return fmt.Errorf("write to connection failed: %v", err)
|
|
||||||
}
|
|
||||||
// read hello from client
|
|
||||||
switch msg := c.Read().(type) {
|
|
||||||
case *Hello:
|
|
||||||
// set snappy if version is at least 5
|
|
||||||
if msg.Version >= 5 {
|
|
||||||
c.SetSnappy(true)
|
|
||||||
}
|
|
||||||
c.negotiateEthProtocol(msg.Caps)
|
|
||||||
if c.negotiatedProtoVersion == 0 {
|
|
||||||
return fmt.Errorf("could not negotiate eth protocol (remote caps: %v, local eth version: %v)", msg.Caps, c.ourHighestProtoVersion)
|
|
||||||
}
|
|
||||||
// If we require snap, verify that it was negotiated
|
|
||||||
if c.ourHighestSnapProtoVersion != c.negotiatedSnapProtoVersion {
|
|
||||||
return fmt.Errorf("could not negotiate snap protocol (remote caps: %v, local snap version: %v)", msg.Caps, c.ourHighestSnapProtoVersion)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
default:
|
|
||||||
return fmt.Errorf("bad handshake: %#v", msg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// negotiateEthProtocol sets the Conn's eth protocol version to highest
|
|
||||||
// advertised capability from peer.
|
|
||||||
func (c *Conn) negotiateEthProtocol(caps []p2p.Cap) {
|
|
||||||
var highestEthVersion uint
|
|
||||||
var highestSnapVersion uint
|
|
||||||
for _, capability := range caps {
|
|
||||||
switch capability.Name {
|
|
||||||
case "eth":
|
|
||||||
if capability.Version > highestEthVersion && capability.Version <= c.ourHighestProtoVersion {
|
|
||||||
highestEthVersion = capability.Version
|
|
||||||
}
|
|
||||||
case "snap":
|
|
||||||
if capability.Version > highestSnapVersion && capability.Version <= c.ourHighestSnapProtoVersion {
|
|
||||||
highestSnapVersion = capability.Version
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
c.negotiatedProtoVersion = highestEthVersion
|
|
||||||
c.negotiatedSnapProtoVersion = highestSnapVersion
|
|
||||||
}
|
|
||||||
|
|
||||||
// statusExchange performs a `Status` message exchange with the given node.
|
|
||||||
func (c *Conn) statusExchange(chain *Chain, status *Status) (Message, error) {
|
|
||||||
defer c.SetDeadline(time.Time{})
|
|
||||||
c.SetDeadline(time.Now().Add(20 * time.Second))
|
|
||||||
|
|
||||||
// read status message from client
|
|
||||||
var message Message
|
|
||||||
loop:
|
|
||||||
for {
|
|
||||||
switch msg := c.Read().(type) {
|
|
||||||
case *Status:
|
|
||||||
if have, want := msg.Head, chain.blocks[chain.Len()-1].Hash(); have != want {
|
|
||||||
return nil, fmt.Errorf("wrong head block in status, want: %#x (block %d) have %#x",
|
|
||||||
want, chain.blocks[chain.Len()-1].NumberU64(), have)
|
|
||||||
}
|
|
||||||
if have, want := msg.TD.Cmp(chain.TD()), 0; have != want {
|
|
||||||
return nil, fmt.Errorf("wrong TD in status: have %v want %v", have, want)
|
|
||||||
}
|
|
||||||
if have, want := msg.ForkID, chain.ForkID(); !reflect.DeepEqual(have, want) {
|
|
||||||
return nil, fmt.Errorf("wrong fork ID in status: have %v, want %v", have, want)
|
|
||||||
}
|
|
||||||
if have, want := msg.ProtocolVersion, c.ourHighestProtoVersion; have != uint32(want) {
|
|
||||||
return nil, fmt.Errorf("wrong protocol version: have %v, want %v", have, want)
|
|
||||||
}
|
|
||||||
message = msg
|
|
||||||
break loop
|
|
||||||
case *Disconnect:
|
|
||||||
return nil, fmt.Errorf("disconnect received: %v", msg.Reason)
|
|
||||||
case *Ping:
|
|
||||||
c.Write(&Pong{}) // TODO (renaynay): in the future, this should be an error
|
|
||||||
// (PINGs should not be a response upon fresh connection)
|
|
||||||
default:
|
|
||||||
return nil, fmt.Errorf("bad status message: %s", pretty.Sdump(msg))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// make sure eth protocol version is set for negotiation
|
|
||||||
if c.negotiatedProtoVersion == 0 {
|
|
||||||
return nil, errors.New("eth protocol version must be set in Conn")
|
|
||||||
}
|
|
||||||
if status == nil {
|
|
||||||
// default status message
|
|
||||||
status = &Status{
|
|
||||||
ProtocolVersion: uint32(c.negotiatedProtoVersion),
|
|
||||||
NetworkID: chain.chainConfig.ChainID.Uint64(),
|
|
||||||
TD: chain.TD(),
|
|
||||||
Head: chain.blocks[chain.Len()-1].Hash(),
|
|
||||||
Genesis: chain.blocks[0].Hash(),
|
|
||||||
ForkID: chain.ForkID(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if err := c.Write(status); err != nil {
|
|
||||||
return nil, fmt.Errorf("write to connection failed: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// exchange UpgradeStatus
|
|
||||||
if c.negotiatedProtoVersion >= eth.ETH67 {
|
|
||||||
extensionRaw, _ := (ð.UpgradeStatusExtension{}).Encode()
|
|
||||||
upgradeStatus := UpgradeStatus{
|
|
||||||
Extension: extensionRaw,
|
|
||||||
}
|
|
||||||
if err := c.Write(upgradeStatus); err != nil {
|
|
||||||
return nil, fmt.Errorf("write to connection failed: %v", err)
|
|
||||||
}
|
|
||||||
switch msg := c.Read().(type) {
|
|
||||||
case *UpgradeStatus:
|
|
||||||
log.Debug("receive UpgradeStatus")
|
|
||||||
case *Disconnect:
|
|
||||||
return nil, fmt.Errorf("disconnect received: %v", msg.Reason)
|
|
||||||
case *Ping:
|
|
||||||
c.Write(&Pong{}) // TODO (renaynay): in the future, this should be an error
|
|
||||||
// (PINGs should not be a response upon fresh connection)
|
|
||||||
default:
|
|
||||||
return nil, fmt.Errorf("bad status message: %s", pretty.Sdump(msg))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return message, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// createSendAndRecvConns creates two connections, one for sending messages to the
|
|
||||||
// node, and one for receiving messages from the node.
|
|
||||||
func (s *Suite) createSendAndRecvConns() (*Conn, *Conn, error) {
|
|
||||||
sendConn, err := s.dial()
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, fmt.Errorf("dial failed: %v", err)
|
|
||||||
}
|
|
||||||
recvConn, err := s.dial()
|
|
||||||
if err != nil {
|
|
||||||
sendConn.Close()
|
|
||||||
return nil, nil, fmt.Errorf("dial failed: %v", err)
|
|
||||||
}
|
|
||||||
return sendConn, recvConn, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// readAndServe serves GetBlockHeaders requests while waiting
|
|
||||||
// on another message from the node.
|
|
||||||
func (c *Conn) readAndServe(chain *Chain, timeout time.Duration) Message {
|
|
||||||
start := time.Now()
|
|
||||||
for time.Since(start) < timeout {
|
|
||||||
c.SetReadDeadline(time.Now().Add(10 * time.Second))
|
|
||||||
|
|
||||||
msg := c.Read()
|
|
||||||
switch msg := msg.(type) {
|
|
||||||
case *Ping:
|
|
||||||
c.Write(&Pong{})
|
|
||||||
case *GetBlockHeaders:
|
|
||||||
headers, err := chain.GetHeaders(msg)
|
|
||||||
if err != nil {
|
|
||||||
return errorf("could not get headers for inbound header request: %v", err)
|
|
||||||
}
|
|
||||||
resp := &BlockHeaders{
|
|
||||||
RequestId: msg.ReqID(),
|
|
||||||
BlockHeadersPacket: eth.BlockHeadersPacket(headers),
|
|
||||||
}
|
|
||||||
if err := c.Write(resp); err != nil {
|
|
||||||
return errorf("could not write to connection: %v", err)
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return msg
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return errorf("no message received within %v", timeout)
|
|
||||||
}
|
|
||||||
|
|
||||||
// headersRequest executes the given `GetBlockHeaders` request.
|
|
||||||
func (c *Conn) headersRequest(request *GetBlockHeaders, chain *Chain, reqID uint64) ([]*types.Header, error) {
|
|
||||||
defer c.SetReadDeadline(time.Time{})
|
|
||||||
c.SetReadDeadline(time.Now().Add(20 * time.Second))
|
|
||||||
|
|
||||||
// write request
|
|
||||||
request.RequestId = reqID
|
|
||||||
if err := c.Write(request); err != nil {
|
|
||||||
return nil, fmt.Errorf("could not write to connection: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// wait for response
|
|
||||||
msg := c.waitForResponse(chain, timeout, request.RequestId)
|
|
||||||
resp, ok := msg.(*BlockHeaders)
|
|
||||||
if !ok {
|
|
||||||
return nil, fmt.Errorf("unexpected message received: %s", pretty.Sdump(msg))
|
|
||||||
}
|
|
||||||
headers := []*types.Header(resp.BlockHeadersPacket)
|
|
||||||
return headers, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Conn) snapRequest(msg Message, id uint64, chain *Chain) (Message, error) {
|
|
||||||
defer c.SetReadDeadline(time.Time{})
|
|
||||||
c.SetReadDeadline(time.Now().Add(5 * time.Second))
|
|
||||||
if err := c.Write(msg); err != nil {
|
|
||||||
return nil, fmt.Errorf("could not write to connection: %v", err)
|
|
||||||
}
|
|
||||||
return c.ReadSnap(id)
|
|
||||||
}
|
|
||||||
|
|
||||||
// headersMatch returns whether the received headers match the given request
|
|
||||||
func headersMatch(expected []*types.Header, headers []*types.Header) bool {
|
|
||||||
return reflect.DeepEqual(expected, headers)
|
|
||||||
}
|
|
||||||
|
|
||||||
// waitForResponse reads from the connection until a response with the expected
|
|
||||||
// request ID is received.
|
|
||||||
func (c *Conn) waitForResponse(chain *Chain, timeout time.Duration, requestID uint64) Message {
|
|
||||||
for {
|
|
||||||
msg := c.readAndServe(chain, timeout)
|
|
||||||
if msg.ReqID() == requestID {
|
|
||||||
return msg
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// sendNextBlock broadcasts the next block in the chain and waits
|
|
||||||
// for the node to propagate the block and import it into its chain.
|
|
||||||
func (s *Suite) sendNextBlock() error {
|
|
||||||
// set up sending and receiving connections
|
|
||||||
sendConn, recvConn, err := s.createSendAndRecvConns()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer sendConn.Close()
|
|
||||||
defer recvConn.Close()
|
|
||||||
if err = sendConn.peer(s.chain, nil); err != nil {
|
|
||||||
return fmt.Errorf("peering failed: %v", err)
|
|
||||||
}
|
|
||||||
if err = recvConn.peer(s.chain, nil); err != nil {
|
|
||||||
return fmt.Errorf("peering failed: %v", err)
|
|
||||||
}
|
|
||||||
// create new block announcement
|
|
||||||
nextBlock := s.fullChain.blocks[s.chain.Len()]
|
|
||||||
blockAnnouncement := &NewBlock{
|
|
||||||
Block: nextBlock,
|
|
||||||
TD: s.fullChain.TotalDifficultyAt(s.chain.Len()),
|
|
||||||
}
|
|
||||||
// send announcement and wait for node to request the header
|
|
||||||
if err = s.testAnnounce(sendConn, recvConn, blockAnnouncement); err != nil {
|
|
||||||
return fmt.Errorf("failed to announce block: %v", err)
|
|
||||||
}
|
|
||||||
// wait for client to update its chain
|
|
||||||
if err = s.waitForBlockImport(recvConn, nextBlock); err != nil {
|
|
||||||
return fmt.Errorf("failed to receive confirmation of block import: %v", err)
|
|
||||||
}
|
|
||||||
// update test suite chain
|
|
||||||
s.chain.blocks = append(s.chain.blocks, nextBlock)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// testAnnounce writes a block announcement to the node and waits for the node
|
|
||||||
// to propagate it.
|
|
||||||
func (s *Suite) testAnnounce(sendConn, receiveConn *Conn, blockAnnouncement *NewBlock) error {
|
|
||||||
if err := sendConn.Write(blockAnnouncement); err != nil {
|
|
||||||
return fmt.Errorf("could not write to connection: %v", err)
|
|
||||||
}
|
|
||||||
return s.waitAnnounce(receiveConn, blockAnnouncement)
|
|
||||||
}
|
|
||||||
|
|
||||||
// waitAnnounce waits for a NewBlock or NewBlockHashes announcement from the node.
|
|
||||||
func (s *Suite) waitAnnounce(conn *Conn, blockAnnouncement *NewBlock) error {
|
|
||||||
for {
|
|
||||||
switch msg := conn.readAndServe(s.chain, timeout).(type) {
|
|
||||||
case *NewBlock:
|
|
||||||
if !reflect.DeepEqual(blockAnnouncement.Block.Header(), msg.Block.Header()) {
|
|
||||||
return fmt.Errorf("wrong header in block announcement: \nexpected %v "+
|
|
||||||
"\ngot %v", blockAnnouncement.Block.Header(), msg.Block.Header())
|
|
||||||
}
|
|
||||||
if !reflect.DeepEqual(blockAnnouncement.TD, msg.TD) {
|
|
||||||
return fmt.Errorf("wrong TD in announcement: expected %v, got %v", blockAnnouncement.TD, msg.TD)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
case *NewBlockHashes:
|
|
||||||
hashes := *msg
|
|
||||||
if blockAnnouncement.Block.Hash() != hashes[0].Hash {
|
|
||||||
return fmt.Errorf("wrong block hash in announcement: expected %v, got %v", blockAnnouncement.Block.Hash(), hashes[0].Hash)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
|
|
||||||
// ignore tx announcements from previous tests
|
|
||||||
case *NewPooledTransactionHashes66:
|
|
||||||
continue
|
|
||||||
case *NewPooledTransactionHashes:
|
|
||||||
continue
|
|
||||||
case *Transactions:
|
|
||||||
continue
|
|
||||||
|
|
||||||
default:
|
|
||||||
return fmt.Errorf("unexpected: %s", pretty.Sdump(msg))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Suite) waitForBlockImport(conn *Conn, block *types.Block) error {
|
|
||||||
defer conn.SetReadDeadline(time.Time{})
|
|
||||||
conn.SetReadDeadline(time.Now().Add(20 * time.Second))
|
|
||||||
// create request
|
|
||||||
req := &GetBlockHeaders{
|
|
||||||
GetBlockHeadersPacket: ð.GetBlockHeadersPacket{
|
|
||||||
Origin: eth.HashOrNumber{Hash: block.Hash()},
|
|
||||||
Amount: 1,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
// loop until BlockHeaders response contains desired block, confirming the
|
|
||||||
// node imported the block
|
|
||||||
for {
|
|
||||||
requestID := uint64(54)
|
|
||||||
headers, err := conn.headersRequest(req, s.chain, requestID)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("GetBlockHeader request failed: %v", err)
|
|
||||||
}
|
|
||||||
// if headers response is empty, node hasn't imported block yet, try again
|
|
||||||
if len(headers) == 0 {
|
|
||||||
time.Sleep(100 * time.Millisecond)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if !reflect.DeepEqual(block.Header(), headers[0]) {
|
|
||||||
return fmt.Errorf("wrong header returned: wanted %v, got %v", block.Header(), headers[0])
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Suite) oldAnnounce() error {
|
|
||||||
sendConn, receiveConn, err := s.createSendAndRecvConns()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer sendConn.Close()
|
|
||||||
defer receiveConn.Close()
|
|
||||||
if err := sendConn.peer(s.chain, nil); err != nil {
|
|
||||||
return fmt.Errorf("peering failed: %v", err)
|
|
||||||
}
|
|
||||||
if err := receiveConn.peer(s.chain, nil); err != nil {
|
|
||||||
return fmt.Errorf("peering failed: %v", err)
|
|
||||||
}
|
|
||||||
// create old block announcement
|
|
||||||
oldBlockAnnounce := &NewBlock{
|
|
||||||
Block: s.chain.blocks[len(s.chain.blocks)/2],
|
|
||||||
TD: s.chain.blocks[len(s.chain.blocks)/2].Difficulty(),
|
|
||||||
}
|
|
||||||
if err := sendConn.Write(oldBlockAnnounce); err != nil {
|
|
||||||
return fmt.Errorf("could not write to connection: %v", err)
|
|
||||||
}
|
|
||||||
// wait to see if the announcement is propagated
|
|
||||||
switch msg := receiveConn.readAndServe(s.chain, time.Second*8).(type) {
|
|
||||||
case *NewBlock:
|
|
||||||
block := *msg
|
|
||||||
if block.Block.Hash() == oldBlockAnnounce.Block.Hash() {
|
|
||||||
return fmt.Errorf("unexpected: block propagated: %s", pretty.Sdump(msg))
|
|
||||||
}
|
|
||||||
case *NewBlockHashes:
|
|
||||||
hashes := *msg
|
|
||||||
for _, hash := range hashes {
|
|
||||||
if hash.Hash == oldBlockAnnounce.Block.Hash() {
|
|
||||||
return fmt.Errorf("unexpected: block announced: %s", pretty.Sdump(msg))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case *Error:
|
|
||||||
errMsg := *msg
|
|
||||||
// check to make sure error is timeout (propagation didn't come through == test successful)
|
|
||||||
if !strings.Contains(errMsg.String(), "timeout") {
|
|
||||||
return fmt.Errorf("unexpected error: %v", pretty.Sdump(msg))
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return fmt.Errorf("unexpected: %s", pretty.Sdump(msg))
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Suite) maliciousHandshakes(t *utesting.T) error {
|
|
||||||
conn, err := s.dial()
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("dial failed: %v", err)
|
|
||||||
}
|
|
||||||
defer conn.Close()
|
|
||||||
|
|
||||||
// write hello to client
|
|
||||||
pub0 := crypto.FromECDSAPub(&conn.ourKey.PublicKey)[1:]
|
|
||||||
handshakes := []*Hello{
|
|
||||||
{
|
|
||||||
Version: 5,
|
|
||||||
Caps: []p2p.Cap{
|
|
||||||
{Name: largeString(2), Version: 64},
|
|
||||||
},
|
|
||||||
ID: pub0,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Version: 5,
|
|
||||||
Caps: []p2p.Cap{
|
|
||||||
{Name: "eth", Version: 64},
|
|
||||||
{Name: "eth", Version: 65},
|
|
||||||
},
|
|
||||||
ID: append(pub0, byte(0)),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Version: 5,
|
|
||||||
Caps: []p2p.Cap{
|
|
||||||
{Name: "eth", Version: 64},
|
|
||||||
{Name: "eth", Version: 65},
|
|
||||||
},
|
|
||||||
ID: append(pub0, pub0...),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Version: 5,
|
|
||||||
Caps: []p2p.Cap{
|
|
||||||
{Name: "eth", Version: 64},
|
|
||||||
{Name: "eth", Version: 65},
|
|
||||||
},
|
|
||||||
ID: largeBuffer(2),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Version: 5,
|
|
||||||
Caps: []p2p.Cap{
|
|
||||||
{Name: largeString(2), Version: 64},
|
|
||||||
},
|
|
||||||
ID: largeBuffer(2),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for i, handshake := range handshakes {
|
|
||||||
t.Logf("Testing malicious handshake %v\n", i)
|
|
||||||
if err := conn.Write(handshake); err != nil {
|
|
||||||
return fmt.Errorf("could not write to connection: %v", err)
|
|
||||||
}
|
|
||||||
// check that the peer disconnected
|
|
||||||
for i := 0; i < 2; i++ {
|
|
||||||
switch msg := conn.readAndServe(s.chain, 20*time.Second).(type) {
|
|
||||||
case *Disconnect:
|
|
||||||
case *Error:
|
|
||||||
case *Hello:
|
|
||||||
// Discard one hello as Hello's are sent concurrently
|
|
||||||
continue
|
|
||||||
default:
|
|
||||||
return fmt.Errorf("unexpected: %s", pretty.Sdump(msg))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// dial for the next round
|
|
||||||
conn, err = s.dial()
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("dial failed: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Suite) maliciousStatus(conn *Conn) error {
|
|
||||||
if err := conn.handshake(); err != nil {
|
|
||||||
return fmt.Errorf("handshake failed: %v", err)
|
|
||||||
}
|
|
||||||
status := &Status{
|
|
||||||
ProtocolVersion: uint32(conn.negotiatedProtoVersion),
|
|
||||||
NetworkID: s.chain.chainConfig.ChainID.Uint64(),
|
|
||||||
TD: largeNumber(2),
|
|
||||||
Head: s.chain.blocks[s.chain.Len()-1].Hash(),
|
|
||||||
Genesis: s.chain.blocks[0].Hash(),
|
|
||||||
ForkID: s.chain.ForkID(),
|
|
||||||
}
|
|
||||||
|
|
||||||
// get status
|
|
||||||
msg, err := conn.statusExchange(s.chain, status)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("status exchange failed: %v", err)
|
|
||||||
}
|
|
||||||
switch msg := msg.(type) {
|
|
||||||
case *Status:
|
|
||||||
default:
|
|
||||||
return fmt.Errorf("expected status, got: %#v ", msg)
|
|
||||||
}
|
|
||||||
|
|
||||||
// wait for disconnect
|
|
||||||
switch msg := conn.readAndServe(s.chain, timeout).(type) {
|
|
||||||
case *Disconnect:
|
|
||||||
return nil
|
|
||||||
case *Error:
|
|
||||||
return nil
|
|
||||||
default:
|
|
||||||
return fmt.Errorf("expected disconnect, got: %s", pretty.Sdump(msg))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Suite) hashAnnounce() error {
|
|
||||||
// create connections
|
|
||||||
sendConn, recvConn, err := s.createSendAndRecvConns()
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to create connections: %v", err)
|
|
||||||
}
|
|
||||||
defer sendConn.Close()
|
|
||||||
defer recvConn.Close()
|
|
||||||
if err := sendConn.peer(s.chain, nil); err != nil {
|
|
||||||
return fmt.Errorf("peering failed: %v", err)
|
|
||||||
}
|
|
||||||
if err := recvConn.peer(s.chain, nil); err != nil {
|
|
||||||
return fmt.Errorf("peering failed: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// create NewBlockHashes announcement
|
|
||||||
type anno struct {
|
|
||||||
Hash common.Hash // Hash of one particular block being announced
|
|
||||||
Number uint64 // Number of one particular block being announced
|
|
||||||
}
|
|
||||||
nextBlock := s.fullChain.blocks[s.chain.Len()]
|
|
||||||
announcement := anno{Hash: nextBlock.Hash(), Number: nextBlock.Number().Uint64()}
|
|
||||||
newBlockHash := &NewBlockHashes{announcement}
|
|
||||||
if err := sendConn.Write(newBlockHash); err != nil {
|
|
||||||
return fmt.Errorf("failed to write to connection: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Announcement sent, now wait for a header request
|
|
||||||
msg := sendConn.Read()
|
|
||||||
blockHeaderReq, ok := msg.(*GetBlockHeaders)
|
|
||||||
if !ok {
|
|
||||||
return fmt.Errorf("unexpected %s", pretty.Sdump(msg))
|
|
||||||
}
|
|
||||||
if blockHeaderReq.Amount != 1 {
|
|
||||||
return fmt.Errorf("unexpected number of block headers requested: %v", blockHeaderReq.Amount)
|
|
||||||
}
|
|
||||||
if blockHeaderReq.Origin.Hash != announcement.Hash {
|
|
||||||
return fmt.Errorf("unexpected block header requested. Announced:\n %v\n Remote request:\n%v",
|
|
||||||
pretty.Sdump(announcement),
|
|
||||||
pretty.Sdump(blockHeaderReq))
|
|
||||||
}
|
|
||||||
err = sendConn.Write(&BlockHeaders{
|
|
||||||
RequestId: blockHeaderReq.ReqID(),
|
|
||||||
BlockHeadersPacket: eth.BlockHeadersPacket{nextBlock.Header()},
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to write to connection: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// wait for block announcement
|
|
||||||
msg = recvConn.readAndServe(s.chain, timeout)
|
|
||||||
switch msg := msg.(type) {
|
|
||||||
case *NewBlockHashes:
|
|
||||||
hashes := *msg
|
|
||||||
if len(hashes) != 1 {
|
|
||||||
return fmt.Errorf("unexpected new block hash announcement: wanted 1 announcement, got %d", len(hashes))
|
|
||||||
}
|
|
||||||
if nextBlock.Hash() != hashes[0].Hash {
|
|
||||||
return fmt.Errorf("unexpected block hash announcement, wanted %v, got %v", nextBlock.Hash(),
|
|
||||||
hashes[0].Hash)
|
|
||||||
}
|
|
||||||
|
|
||||||
case *NewBlock:
|
|
||||||
// node should only propagate NewBlock without having requested the body if the body is empty
|
|
||||||
nextBlockBody := nextBlock.Body()
|
|
||||||
if len(nextBlockBody.Transactions) != 0 || len(nextBlockBody.Uncles) != 0 {
|
|
||||||
return fmt.Errorf("unexpected non-empty new block propagated: %s", pretty.Sdump(msg))
|
|
||||||
}
|
|
||||||
if msg.Block.Hash() != nextBlock.Hash() {
|
|
||||||
return fmt.Errorf("mismatched hash of propagated new block: wanted %v, got %v",
|
|
||||||
nextBlock.Hash(), msg.Block.Hash())
|
|
||||||
}
|
|
||||||
// check to make sure header matches header that was sent to the node
|
|
||||||
if !reflect.DeepEqual(nextBlock.Header(), msg.Block.Header()) {
|
|
||||||
return fmt.Errorf("incorrect header received: wanted %v, got %v", nextBlock.Header(), msg.Block.Header())
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return fmt.Errorf("unexpected: %s", pretty.Sdump(msg))
|
|
||||||
}
|
|
||||||
// confirm node imported block
|
|
||||||
if err := s.waitForBlockImport(recvConn, nextBlock); err != nil {
|
|
||||||
return fmt.Errorf("error waiting for node to import new block: %v", err)
|
|
||||||
}
|
|
||||||
// update the chain
|
|
||||||
s.chain.blocks = append(s.chain.blocks, nextBlock)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
@@ -1,80 +0,0 @@
|
|||||||
// Copyright 2020 The go-ethereum Authors
|
|
||||||
// This file is part of go-ethereum.
|
|
||||||
//
|
|
||||||
// go-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.
|
|
||||||
//
|
|
||||||
// go-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 go-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
package ethtest
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/rand"
|
|
||||||
"math/big"
|
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
|
||||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
|
||||||
)
|
|
||||||
|
|
||||||
// largeNumber returns a very large big.Int.
|
|
||||||
func largeNumber(megabytes int) *big.Int {
|
|
||||||
buf := make([]byte, megabytes*1024*1024)
|
|
||||||
rand.Read(buf)
|
|
||||||
bigint := new(big.Int)
|
|
||||||
bigint.SetBytes(buf)
|
|
||||||
return bigint
|
|
||||||
}
|
|
||||||
|
|
||||||
// largeBuffer returns a very large buffer.
|
|
||||||
func largeBuffer(megabytes int) []byte {
|
|
||||||
buf := make([]byte, megabytes*1024*1024)
|
|
||||||
rand.Read(buf)
|
|
||||||
return buf
|
|
||||||
}
|
|
||||||
|
|
||||||
// largeString returns a very large string.
|
|
||||||
func largeString(megabytes int) string {
|
|
||||||
buf := make([]byte, megabytes*1024*1024)
|
|
||||||
rand.Read(buf)
|
|
||||||
return hexutil.Encode(buf)
|
|
||||||
}
|
|
||||||
|
|
||||||
func largeBlock() *types.Block {
|
|
||||||
return types.NewBlockWithHeader(largeHeader())
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns a random hash
|
|
||||||
func randHash() common.Hash {
|
|
||||||
var h common.Hash
|
|
||||||
rand.Read(h[:])
|
|
||||||
return h
|
|
||||||
}
|
|
||||||
|
|
||||||
func largeHeader() *types.Header {
|
|
||||||
return &types.Header{
|
|
||||||
MixDigest: randHash(),
|
|
||||||
ReceiptHash: randHash(),
|
|
||||||
TxHash: randHash(),
|
|
||||||
Nonce: types.BlockNonce{},
|
|
||||||
Extra: []byte{},
|
|
||||||
Bloom: types.Bloom{},
|
|
||||||
GasUsed: 0,
|
|
||||||
Coinbase: common.Address{},
|
|
||||||
GasLimit: 0,
|
|
||||||
UncleHash: types.EmptyUncleHash,
|
|
||||||
Time: 1337,
|
|
||||||
ParentHash: randHash(),
|
|
||||||
Root: randHash(),
|
|
||||||
Number: largeNumber(2),
|
|
||||||
Difficulty: largeNumber(2),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
9
cmd/devp2p/internal/ethtest/mkchain.sh
Normal file
9
cmd/devp2p/internal/ethtest/mkchain.sh
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
hivechain generate \
|
||||||
|
--fork-interval 6 \
|
||||||
|
--tx-interval 1 \
|
||||||
|
--length 500 \
|
||||||
|
--outdir testdata \
|
||||||
|
--lastfork cancun \
|
||||||
|
--outputs accounts,genesis,chain,headstate,txinfo,headblock,headfcu,newpayload,forkenv
|
||||||
87
cmd/devp2p/internal/ethtest/protocol.go
Normal file
87
cmd/devp2p/internal/ethtest/protocol.go
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
// Copyright 2023 The go-ethereum Authors
|
||||||
|
// This file is part of go-ethereum.
|
||||||
|
//
|
||||||
|
// go-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.
|
||||||
|
//
|
||||||
|
// go-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 go-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
package ethtest
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/ethereum/go-ethereum/p2p"
|
||||||
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Unexported devp2p message codes from p2p/peer.go.
|
||||||
|
const (
|
||||||
|
handshakeMsg = 0x00
|
||||||
|
discMsg = 0x01
|
||||||
|
pingMsg = 0x02
|
||||||
|
pongMsg = 0x03
|
||||||
|
)
|
||||||
|
|
||||||
|
// Unexported devp2p protocol lengths from p2p package.
|
||||||
|
const (
|
||||||
|
baseProtoLen = 16
|
||||||
|
ethProtoLen = 17
|
||||||
|
snapProtoLen = 8
|
||||||
|
)
|
||||||
|
|
||||||
|
// Unexported handshake structure from p2p/peer.go.
|
||||||
|
type protoHandshake struct {
|
||||||
|
Version uint64
|
||||||
|
Name string
|
||||||
|
Caps []p2p.Cap
|
||||||
|
ListenPort uint64
|
||||||
|
ID []byte
|
||||||
|
Rest []rlp.RawValue `rlp:"tail"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Hello = protoHandshake
|
||||||
|
|
||||||
|
// Proto is an enum representing devp2p protocol types.
|
||||||
|
type Proto int
|
||||||
|
|
||||||
|
const (
|
||||||
|
baseProto Proto = iota
|
||||||
|
ethProto
|
||||||
|
snapProto
|
||||||
|
)
|
||||||
|
|
||||||
|
// getProto returns the protocol a certain message code is associated with
|
||||||
|
// (assuming the negotiated capabilities are exactly {eth,snap})
|
||||||
|
func getProto(code uint64) Proto {
|
||||||
|
switch {
|
||||||
|
case code < baseProtoLen:
|
||||||
|
return baseProto
|
||||||
|
case code < baseProtoLen+ethProtoLen:
|
||||||
|
return ethProto
|
||||||
|
case code < baseProtoLen+ethProtoLen+snapProtoLen:
|
||||||
|
return snapProto
|
||||||
|
default:
|
||||||
|
panic("unhandled msg code beyond last protocol")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// protoOffset will return the offset at which the specified protocol's messages
|
||||||
|
// begin.
|
||||||
|
func protoOffset(proto Proto) uint64 {
|
||||||
|
switch proto {
|
||||||
|
case baseProto:
|
||||||
|
return 0
|
||||||
|
case ethProto:
|
||||||
|
return baseProtoLen
|
||||||
|
case snapProto:
|
||||||
|
return baseProtoLen + ethProtoLen
|
||||||
|
default:
|
||||||
|
panic("unhandled protocol")
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,60 +0,0 @@
|
|||||||
// Copyright 2022 The go-ethereum Authors
|
|
||||||
// This file is part of go-ethereum.
|
|
||||||
//
|
|
||||||
// go-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.
|
|
||||||
//
|
|
||||||
// go-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 go-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
package ethtest
|
|
||||||
|
|
||||||
import "github.com/ethereum/go-ethereum/eth/protocols/snap"
|
|
||||||
|
|
||||||
// GetAccountRange represents an account range query.
|
|
||||||
type GetAccountRange snap.GetAccountRangePacket
|
|
||||||
|
|
||||||
func (msg GetAccountRange) Code() int { return 33 }
|
|
||||||
func (msg GetAccountRange) ReqID() uint64 { return msg.ID }
|
|
||||||
|
|
||||||
type AccountRange snap.AccountRangePacket
|
|
||||||
|
|
||||||
func (msg AccountRange) Code() int { return 34 }
|
|
||||||
func (msg AccountRange) ReqID() uint64 { return msg.ID }
|
|
||||||
|
|
||||||
type GetStorageRanges snap.GetStorageRangesPacket
|
|
||||||
|
|
||||||
func (msg GetStorageRanges) Code() int { return 35 }
|
|
||||||
func (msg GetStorageRanges) ReqID() uint64 { return msg.ID }
|
|
||||||
|
|
||||||
type StorageRanges snap.StorageRangesPacket
|
|
||||||
|
|
||||||
func (msg StorageRanges) Code() int { return 36 }
|
|
||||||
func (msg StorageRanges) ReqID() uint64 { return msg.ID }
|
|
||||||
|
|
||||||
type GetByteCodes snap.GetByteCodesPacket
|
|
||||||
|
|
||||||
func (msg GetByteCodes) Code() int { return 37 }
|
|
||||||
func (msg GetByteCodes) ReqID() uint64 { return msg.ID }
|
|
||||||
|
|
||||||
type ByteCodes snap.ByteCodesPacket
|
|
||||||
|
|
||||||
func (msg ByteCodes) Code() int { return 38 }
|
|
||||||
func (msg ByteCodes) ReqID() uint64 { return msg.ID }
|
|
||||||
|
|
||||||
type GetTrieNodes snap.GetTrieNodesPacket
|
|
||||||
|
|
||||||
func (msg GetTrieNodes) Code() int { return 39 }
|
|
||||||
func (msg GetTrieNodes) ReqID() uint64 { return msg.ID }
|
|
||||||
|
|
||||||
type TrieNodes snap.TrieNodesPacket
|
|
||||||
|
|
||||||
func (msg TrieNodes) Code() int { return 40 }
|
|
||||||
func (msg TrieNodes) ReqID() uint64 { return msg.ID }
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user