Compare commits
722 commits
notary-att
...
master
Author | SHA1 | Date | |
---|---|---|---|
|
b66cea5ccc | ||
|
e5eb20bbae | ||
|
cf4d4a2611 | ||
|
7a7a5d0322 | ||
|
4d6333866d | ||
|
4a5e8f8592 | ||
|
b4fdf8c3c9 | ||
|
3c471f0b7e | ||
|
41109f442a | ||
|
5c408f7fe4 | ||
|
cd525a1df5 | ||
|
836183ecb6 | ||
|
3c1c650ddf | ||
|
45b8af359d | ||
|
4945145b09 | ||
|
f48e992a78 | ||
|
0b136c1c9c | ||
|
f4aeaa6387 | ||
|
0ae5e7ea83 | ||
|
228052360e | ||
|
5cbfe215a4 | ||
|
72161fe902 | ||
|
aceaabe9d6 | ||
|
9ba532ce9c | ||
|
2aa3c93acd | ||
|
aa5a0cb49b | ||
|
7868578571 | ||
|
6a5833759c | ||
|
6be757af3e | ||
|
67b6d5da31 | ||
|
b5bb605651 | ||
|
d91a0945df | ||
|
c90f6785b9 | ||
|
c30e7ec8d7 | ||
|
ce442a1942 | ||
|
e92606a7ae | ||
|
df1ed68d98 | ||
|
82a7c1bd9c | ||
|
c43cfae24c | ||
|
2d4993a837 | ||
|
647b8c7fb1 | ||
|
0b69901d1e | ||
|
502f024e7c | ||
|
b1bb12df48 | ||
|
31a99d44eb | ||
|
dc8b2f639a | ||
|
2ad4c86712 | ||
|
9a1075d332 | ||
|
58a086ea91 | ||
|
59c98c4d09 | ||
|
f4731eab91 | ||
|
13020ccd02 | ||
|
bce94dfa66 | ||
|
244ca6f438 | ||
|
a32217fac8 | ||
|
0435551eee | ||
|
0a3bf01a8f | ||
|
0aecddea10 | ||
|
02ecbeb519 | ||
|
e275495850 | ||
|
6e0926e59f | ||
|
988440949b | ||
|
701ea8d5f3 | ||
|
3d1e33a502 | ||
|
5053a073f9 | ||
|
71aa32406d | ||
|
3acb132e9a | ||
|
bd2f9c75e1 | ||
|
34eef47a18 | ||
|
7995229f6b | ||
|
b21db99747 | ||
|
bc158eed51 | ||
|
ac70f069ff | ||
|
b54fcbcdd9 | ||
|
8da7c0a671 | ||
|
956fd08adb | ||
|
1292a00ef9 | ||
|
7c8d2c3ec5 | ||
|
df2a56908b | ||
|
198af7f3ae | ||
|
874ed1ac2e | ||
|
4a8a43b983 | ||
|
6cf785ce54 | ||
|
9b8d579bce | ||
|
36e128516b | ||
|
4ca2686583 | ||
|
235f4398c6 | ||
|
ec6fc54bc6 | ||
|
2d3d52e3d0 | ||
|
82993dab2b | ||
|
5c75ee13d0 | ||
|
3a2e301267 | ||
|
d74dc368e0 | ||
|
73c742a466 | ||
|
d62fad1268 | ||
|
a13dc59bd9 | ||
|
678c1982f9 | ||
|
c84adf856a | ||
|
7345dbcab4 | ||
|
fbe514ca91 | ||
|
83fdcc8568 | ||
|
4b9024fa45 | ||
|
9b688a9ee9 | ||
|
1786136a23 | ||
|
d3993ad54c | ||
|
db37101e34 | ||
|
567f9f9c6e | ||
|
fb4a4f074f | ||
|
97a19df6f0 | ||
|
c5dbecb754 | ||
|
fc79d38ad2 | ||
|
ae3515e819 | ||
|
8913542f93 | ||
|
69bcd4b7d9 | ||
|
51537dfd29 | ||
|
ee1ee56f97 | ||
|
8c1d061446 | ||
|
a28e5b24b2 | ||
|
7aa5983543 | ||
|
fcbfc3b807 | ||
|
cf49e8c4c8 | ||
|
78cefca5c9 | ||
|
f2bb4d455b | ||
|
f553f77d20 | ||
|
700a550973 | ||
|
f84f072a29 | ||
|
927dbb6dc4 | ||
|
e5c919f701 | ||
|
22af33a14e | ||
|
ef3ec190d0 | ||
|
b1a986fba8 | ||
|
f6901806a8 | ||
|
686c77aeea | ||
|
89ef26164c | ||
|
4c288720cd | ||
|
f8c2d269fe | ||
|
698bdc7eea | ||
|
0280ceefe6 | ||
|
b6a9c64c55 | ||
|
be1b97d04e | ||
|
29deba45ca | ||
|
c81ed22698 | ||
|
c5ba53986f | ||
|
fff25bd85c | ||
|
182762af5a | ||
|
e7a0ded65e | ||
|
7202518fcf | ||
|
e0e7fdf810 | ||
|
f95004ad83 | ||
|
309016561d | ||
|
65dbd537ec | ||
|
b947d09552 | ||
|
5c995e71b5 | ||
|
5b30d15f8e | ||
|
57d82c1281 | ||
|
e341e64684 | ||
|
cd215fe096 | ||
|
d7ab7634ef | ||
|
00ac38b545 | ||
|
56e6119f78 | ||
|
d3c8916827 | ||
|
86f16bb931 | ||
|
e27a822d4b | ||
|
687a724d2c | ||
|
8d0d5cb7cd | ||
|
627a0abb57 | ||
|
beee2605a3 | ||
|
708b439f4a | ||
|
3e6dfff503 | ||
|
f8ca51db93 | ||
|
85a2a9a989 | ||
|
37d7a3a2d5 | ||
|
c090628ea5 | ||
|
6d1a22dcb3 | ||
|
1840c057bd | ||
|
fa1c07e7e6 | ||
|
d5a5e4c125 | ||
|
f8ebed2da4 | ||
|
72484a33eb | ||
|
e0328cc1f8 | ||
|
900ef462df | ||
|
d80e14dcbb | ||
|
f409fc36e2 | ||
|
b028c772f2 | ||
|
308475f746 | ||
|
31548dc28f | ||
|
7c2575568d | ||
|
270515de6a | ||
|
a81dc5c795 | ||
|
da4e80e7a0 | ||
|
1a3a494459 | ||
|
7e12cc11e4 | ||
|
27f79b8c63 | ||
|
445ab97906 | ||
|
82e52c4f6d | ||
|
335550fb1e | ||
|
a6f52a7180 | ||
|
bfc3aa6b67 | ||
|
0e6fbadfd5 | ||
|
9c83beffbb | ||
|
37d4012306 | ||
|
67d39177d8 | ||
|
1679b162b8 | ||
|
45c6a7dcd7 | ||
|
077b4f9097 | ||
|
b015c7b05d | ||
|
57d828c4ab | ||
|
b78b715259 | ||
|
86faf7b343 | ||
|
319880e201 | ||
|
0016b6b630 | ||
|
b12ef701f0 | ||
|
588d7c6418 | ||
|
0e47d662b5 | ||
|
54c53cf6ca | ||
|
025bf228a2 | ||
|
bdcc036073 | ||
|
d31b01d4b1 | ||
|
ee39b5ca18 | ||
|
46f2da0fb1 | ||
|
b7efccc040 | ||
|
a256eac619 | ||
|
261b389e24 | ||
|
9e99e35a63 | ||
|
b2936e602c | ||
|
d65b1fd66d | ||
|
72ebcbec72 | ||
|
d2a7162217 | ||
|
49edf9e498 | ||
|
8162e9033d | ||
|
b030c331b0 | ||
|
1560df6913 | ||
|
0c6627f13d | ||
|
13ff95a3d3 | ||
|
5485cf60da | ||
|
3f772c2711 | ||
|
c660a6e8f3 | ||
|
90db72abc9 | ||
|
8d67f17943 | ||
|
46a3ff3348 | ||
|
9525bc7785 | ||
|
685d095fa4 | ||
|
1f4e1922ee | ||
|
2404145133 | ||
|
e1e2b5304f | ||
|
9d7357c9fd | ||
|
132531fabe | ||
|
6a560b9a95 | ||
|
630bd29b8d | ||
|
5fcae176b8 | ||
|
cc38221d77 | ||
|
5cf0c75744 | ||
|
5bb7c6b715 | ||
|
9b540770cd | ||
|
775c56e87e | ||
|
4715e523e0 | ||
|
f8dc5ec44f | ||
|
224808975b | ||
|
8ab08c6221 | ||
|
e55809f198 | ||
|
a81804e296 | ||
|
9d3258495f | ||
|
e09fc00188 | ||
|
be17924ef8 | ||
|
6147bf452a | ||
|
327e766cd9 | ||
|
b6a65e4d80 | ||
|
00a1a8da56 | ||
|
07b2de73cd | ||
|
f94df6c013 | ||
|
5128b84e1d | ||
|
5d425a6e45 | ||
|
71fb759c0d | ||
|
588e911ad6 | ||
|
5fe4778b2e | ||
|
939631c3f9 | ||
|
51ac153a7b | ||
|
9d95a2691b | ||
|
57aa05add3 | ||
|
000109bfd1 | ||
|
36b89215ab | ||
|
a19f85ba34 | ||
|
161b83fd7f | ||
|
9b7eff18c0 | ||
|
a22a7177e3 | ||
|
b90c0ece87 | ||
|
ef99a7a9e3 | ||
|
5f745dff72 | ||
|
ed73628100 | ||
|
d20775dd30 | ||
|
d428cfc4f1 | ||
|
32fab1adf1 | ||
|
2c0c111fd5 | ||
|
ef9f75547a | ||
|
f9a82ae45f | ||
|
db2e214f7e | ||
|
baac738ec3 | ||
|
188a5e6a8f | ||
|
d901697615 | ||
|
2da728d176 | ||
|
012da4501d | ||
|
d8320372b8 | ||
|
f5b1bd3978 | ||
|
7c9b1d05d2 | ||
|
1ca7b0bbeb | ||
|
0ffa24932b | ||
|
0d3f749b5e | ||
|
78050e8b2c | ||
|
4b7b71ce25 | ||
|
402a73b7f3 | ||
|
ba1417397f | ||
|
4f5e3f363a | ||
|
4c6dca876c | ||
|
28f1beff64 | ||
|
3176f72878 | ||
|
cc06674253 | ||
|
275e814271 | ||
|
3283fda790 | ||
|
6c88fccc64 | ||
|
1237c719e3 | ||
|
9015215228 | ||
|
5d514538cf | ||
|
56d32a010e | ||
|
a872c200b0 | ||
|
47aefad7ea | ||
|
d7d850ac7d | ||
|
b62541b6a3 | ||
|
c8ff44560e | ||
|
962b161652 | ||
|
de98b39a95 | ||
|
2df0ba7c10 | ||
|
bcee8c268c | ||
|
0baa35ed77 | ||
|
ad122aec41 | ||
|
ead5b3dc09 | ||
|
3766206f44 | ||
|
2012c56031 | ||
|
a5a87a72c2 | ||
|
d5dee8fc94 | ||
|
6f3a219d67 | ||
|
bbbb12af20 | ||
|
3fd48a743e | ||
|
afca64f164 | ||
|
21ccb1a02a | ||
|
44e21c9a8e | ||
|
8bdbac3c5e | ||
|
d7cab3b82c | ||
|
f93e2fbba4 | ||
|
441eb8aa86 | ||
|
af0d1fe3c9 | ||
|
cab358dba1 | ||
|
0639cedd05 | ||
|
9a270ae30c | ||
|
7b53a0c239 | ||
|
6c0c2a6a98 | ||
|
26f96fe7ee | ||
|
daa2b3b920 | ||
|
b31d39836a | ||
|
34be76efb7 | ||
|
90e18ec743 | ||
|
e3aa6bba4d | ||
|
81a439a0d6 | ||
|
6fdda0f15d | ||
|
8e8936912d | ||
|
76261f1605 | ||
|
42b84ad905 | ||
|
98de5b9ccb | ||
|
b637048122 | ||
|
e8e964e3da | ||
|
d7b84c0b47 | ||
|
29f344fd9b | ||
|
2f9b4a2dbf | ||
|
2eab743a5b | ||
|
a159054f10 | ||
|
b35f351f0b | ||
|
fd7b7ffc13 | ||
|
a9803b3477 | ||
|
7179efec35 | ||
|
fc77754098 | ||
|
7a2eb32c42 | ||
|
20a57d8337 | ||
|
7a1bf77585 | ||
|
15b4e0a8cd | ||
|
11ec0db350 | ||
|
4216efbe6c | ||
|
626f1ee198 | ||
|
5d1e0192f1 | ||
|
1f84756c21 | ||
|
61d5b6eb0c | ||
|
f457d50773 | ||
|
d511f6e5a9 | ||
|
802d8d24b9 | ||
|
195bb742ca | ||
|
251b8c57b9 | ||
|
62b710868b | ||
|
7362fd94e6 | ||
|
341d978e5b | ||
|
22c654b200 | ||
|
2f6ba1fded | ||
|
25ef2c7f16 | ||
|
910d53b27b | ||
|
1d189fd90c | ||
|
6824bd9f40 | ||
|
387c411da0 | ||
|
00c6a811ab | ||
|
e21664cd7d | ||
|
23e553f647 | ||
|
4c9cd438f8 | ||
|
eade327b9b | ||
|
8aeb30e019 | ||
|
fced6a27ba | ||
|
5370034955 | ||
|
a5d041a1ac | ||
|
7f9e2e5047 | ||
|
2ae44e074d | ||
|
ff958706f4 | ||
|
28ee1621b8 | ||
|
58102a9a80 | ||
|
4d8601297d | ||
|
64b5ba24e9 | ||
|
3b11f98cd0 | ||
|
c6d259b285 | ||
|
0493ddbd70 | ||
|
474225d425 | ||
|
82cb2e718d | ||
|
80fcf81102 | ||
|
8e5a724f5d | ||
|
59baecd39b | ||
|
f10d2d2be7 | ||
|
63de821ff4 | ||
|
a4779de375 | ||
|
0fef119f5f | ||
|
16b7a83f30 | ||
|
406c9f8b92 | ||
|
b5cf3f592f | ||
|
f6cb698cd1 | ||
|
7fb077e999 | ||
|
48bd8057dd | ||
|
90705e37e9 | ||
|
06c99fb2af | ||
|
e63a93b8a0 | ||
|
2fba04490a | ||
|
90b01bcea6 | ||
|
14d98811a5 | ||
|
b2205940fa | ||
|
fdcc369d60 | ||
|
dd48f810cc | ||
|
f88df92925 | ||
|
de2a445088 | ||
|
5e220754d7 | ||
|
b0cdae4666 | ||
|
963a22e280 | ||
|
dbd647e3a6 | ||
|
ed4610f8b4 | ||
|
7045d3bd63 | ||
|
f8d8b03f64 | ||
|
fca7eb35a1 | ||
|
b4866bd69e | ||
|
c5e284c117 | ||
|
ba4c58780c | ||
|
de38163f89 | ||
|
bbbc6805a8 | ||
|
91c8aa21cc | ||
|
8ed6d97085 | ||
|
c9803f5448 | ||
|
9de9320d55 | ||
|
b9297a4b2c | ||
|
a755a2be30 | ||
|
0e458f473f | ||
|
d89c8801d6 | ||
|
dffd87c6c8 | ||
|
1605496002 | ||
|
7a6b908cae | ||
|
c3955f87d1 | ||
|
3544d65ecd | ||
|
6e0af5ac90 | ||
|
39ce3a9d1d | ||
|
c93658b1c1 | ||
|
890f64007a | ||
|
8cc32a91b6 | ||
|
065bd3f0be | ||
|
1815bc8a32 | ||
|
61a74ab331 | ||
|
04d778612e | ||
|
cb0ef2de3d | ||
|
3353599b38 | ||
|
6476241b3a | ||
|
1841d818ec | ||
|
ef2bc7ca04 | ||
|
6a706d5c5a | ||
|
c42486587d | ||
|
d24579748e | ||
|
19cfbc8d85 | ||
|
b1ad19864f | ||
|
0bd618bee4 | ||
|
38f77c39d0 | ||
|
1aabdc9672 | ||
|
545dbbc668 | ||
|
ff19189937 | ||
|
a9a848a306 | ||
|
69a0104d05 | ||
|
f31e3f70aa | ||
|
c8ed629b5d | ||
|
645076d04f | ||
|
3c13a3d74d | ||
|
e06051e14c | ||
|
3aa858a69f | ||
|
241d5f593e | ||
|
dc3d1300dd | ||
|
7ca4ce0f79 | ||
|
9cd5c88077 | ||
|
45dcf38563 | ||
|
995d774ff8 | ||
|
e6b4fbc999 | ||
|
6e9ac29d5c | ||
|
b284b902d6 | ||
|
32bfed4741 | ||
|
fce98a0af8 | ||
|
2f747dd8d9 | ||
|
8fcf1eecfa | ||
|
bb9b8368a8 | ||
|
460362ab2e | ||
|
9f7b19f886 | ||
|
6865848ca7 | ||
|
de69560c7d | ||
|
a59afa8ea3 | ||
|
eb995c8600 | ||
|
413caac941 | ||
|
d9644204ee | ||
|
f78f915071 | ||
|
27dddb4d50 | ||
|
794658b54c | ||
|
312534af7c | ||
|
07e1bc7cd7 | ||
|
96449d803a | ||
|
19c59c3a59 | ||
|
eeb439f548 | ||
|
cef70091f6 | ||
|
f1c6b9fe8f | ||
|
b78bea17c0 | ||
|
32eb1e2606 | ||
|
96ee2e2b2d | ||
|
d27d2a8561 | ||
|
91c928e8d3 | ||
|
fc6e87af2f | ||
|
a2d28272ef | ||
|
b5a75b1485 | ||
|
1745b21142 | ||
|
e2abb5cb7c | ||
|
ca71bd51d3 | ||
|
b7e019e7ef | ||
|
8c46517522 | ||
|
ff260a6a9b | ||
|
03951c94b0 | ||
|
9e74fc5b47 | ||
|
0a3260c22c | ||
|
4598f3d3c2 | ||
|
49a44b0b9d | ||
|
fd2774ea91 | ||
|
3628b824e1 | ||
|
2581146a01 | ||
|
f66abd020d | ||
|
fda0e8364f | ||
|
eb571a1356 | ||
|
a0f9743515 | ||
|
0f57ad4a12 | ||
|
2d88ed9fe5 | ||
|
31cc349725 | ||
|
eb9735750c | ||
|
26c97a58ed | ||
|
ee12520cbd | ||
|
a703e54563 | ||
|
9bdf66a5e0 | ||
|
98b946dcd3 | ||
|
c6850b49d9 | ||
|
4c015b30d5 | ||
|
2f54f176fb | ||
|
7cedcb9197 | ||
|
e9d582f525 | ||
|
fff7e91709 | ||
|
f3c1283ac6 | ||
|
a59fd50844 | ||
|
259cbc3356 | ||
|
5180305240 | ||
|
cb1432233b | ||
|
59f72429b4 | ||
|
acd821948f | ||
|
0d30c834d5 | ||
|
7afa950eb7 | ||
|
d06f135792 | ||
|
9e31e42bd9 | ||
|
d285342d54 | ||
|
1e6ef0c0e6 | ||
|
edf21e0b79 | ||
|
e83916cef1 | ||
|
abb35ad6fd | ||
|
f330aaf313 | ||
|
c80702cc4a | ||
|
5463a91edc | ||
|
4a648692a2 | ||
|
ad24aad9c0 | ||
|
c63289a564 | ||
|
2d4e1b598f | ||
|
0b67fa9bca | ||
|
1863b79c5c | ||
|
b89078c42a | ||
|
f5b0489d74 | ||
|
dd7c762ff9 | ||
|
aeb7ee1021 | ||
|
97a57de82d | ||
|
b4dff7b040 | ||
|
5d3938ae23 | ||
|
7d75526c20 | ||
|
7b64b693bd | ||
|
c7d5ee0898 | ||
|
1fb0c96e2c | ||
|
97d523ceed | ||
|
617c628c24 | ||
|
87e4b6beaa | ||
|
b9e957a05a | ||
|
124c3df2ff | ||
|
227b0c5480 | ||
|
66a80017d3 | ||
|
c5d9bf6e39 | ||
|
bb2a99d451 | ||
|
ed2c4b0319 | ||
|
2872c1c668 | ||
|
35c3b65c8a | ||
|
380de580a7 | ||
|
1b1b454ce4 | ||
|
415d44792a | ||
|
87aaaf1a67 | ||
|
60795a899f | ||
|
5c6a111d00 | ||
|
90f1b0fd17 | ||
|
f3760c1a98 | ||
|
f557959c24 | ||
|
2598257628 | ||
|
1e6372e6d9 | ||
|
d3fe92de14 | ||
|
3b29720298 | ||
|
3178c8ff78 | ||
|
31ceb568cb | ||
|
3abddc78c0 | ||
|
9fb154a376 | ||
|
d1fe64470d | ||
|
4e61e8238a | ||
|
16d1d1e5eb | ||
|
b4c0fcfaad | ||
|
b2f84c83b3 | ||
|
1356721862 | ||
|
11c0f13d06 | ||
|
624f193f94 | ||
|
d90608ddbf | ||
|
562293c74b | ||
|
3608314c15 | ||
|
158d8e69a4 | ||
|
5b12be2ac7 | ||
|
de43b39c2a | ||
|
11bb733f1a | ||
|
e7f77e052f | ||
|
2493400525 | ||
|
c39153756a | ||
|
25f61b45dd | ||
|
50ee241377 | ||
|
bd937bc500 | ||
|
6c1240d023 | ||
|
5fc61be5f6 | ||
|
4e6b1c4a38 | ||
|
b5f17215db | ||
|
afa4530c7d | ||
|
e82fcb48c4 | ||
|
50a77f3fae | ||
|
7e867aefc4 | ||
|
18c42f7993 | ||
|
80fdb1c90c | ||
|
e2c6bbb6b1 | ||
|
8d5a41de6e | ||
|
6615cce81d | ||
|
c0abc61613 | ||
|
bf871760c6 | ||
|
96aa10bb80 | ||
|
8db997c58a | ||
|
e30e262e66 | ||
|
ebe4c4ce2b | ||
|
b560475e67 | ||
|
4383832aa2 | ||
|
6abf5f6388 | ||
|
d560395985 | ||
|
2c984e2393 | ||
|
d0718a680f | ||
|
97b93c6833 | ||
|
288dee8871 | ||
|
08b273266b | ||
|
ab64f7cfe4 | ||
|
6e990f39de | ||
|
465d3f43d2 | ||
|
f8227aa5f7 | ||
|
758c455c7e | ||
|
c880873105 | ||
|
d5f964f181 | ||
|
6cd0f78649 | ||
|
56b93d279e | ||
|
7028930bd6 | ||
|
eeab9c1b2e | ||
|
01a5816f04 | ||
|
03b9b4a4a1 | ||
|
4be692193e | ||
|
3bbb21bf8f | ||
|
e57967b11c | ||
|
081f9d3ac5 | ||
|
ee4b8f883b | ||
|
7a7d0a06ce | ||
|
0d17273476 | ||
|
0a2be89964 | ||
|
c926d53869 | ||
|
862c2e4ed3 | ||
|
35ebdc1c91 | ||
|
966111f4a8 | ||
|
8253025c90 | ||
|
165525b7e9 | ||
|
9f69522ff5 |
494 changed files with 21035 additions and 11282 deletions
|
@ -16,7 +16,7 @@
|
||||||
"deployed": false
|
"deployed": false
|
||||||
},
|
},
|
||||||
"lock": false,
|
"lock": false,
|
||||||
"isdefault": false
|
"isDefault": false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"address": "NVTiAjNgagDkTr5HTzDmQP9kPwPHN5BgVq",
|
"address": "NVTiAjNgagDkTr5HTzDmQP9kPwPHN5BgVq",
|
||||||
|
@ -41,7 +41,7 @@
|
||||||
"deployed": false
|
"deployed": false
|
||||||
},
|
},
|
||||||
"lock": false,
|
"lock": false,
|
||||||
"isdefault": false
|
"isDefault": false
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"scrypt": {
|
"scrypt": {
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
"deployed": false
|
"deployed": false
|
||||||
},
|
},
|
||||||
"lock": false,
|
"lock": false,
|
||||||
"isdefault": false
|
"isDefault": false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"address": "NVTiAjNgagDkTr5HTzDmQP9kPwPHN5BgVq",
|
"address": "NVTiAjNgagDkTr5HTzDmQP9kPwPHN5BgVq",
|
||||||
|
@ -41,7 +41,7 @@
|
||||||
"deployed": false
|
"deployed": false
|
||||||
},
|
},
|
||||||
"lock": false,
|
"lock": false,
|
||||||
"isdefault": false
|
"isDefault": false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"address": "NfgHwwTi3wHAS8aFAN243C5vGbkYDpqLHP",
|
"address": "NfgHwwTi3wHAS8aFAN243C5vGbkYDpqLHP",
|
||||||
|
@ -58,7 +58,7 @@
|
||||||
"deployed": false
|
"deployed": false
|
||||||
},
|
},
|
||||||
"lock": false,
|
"lock": false,
|
||||||
"isdefault": false
|
"isDefault": false
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"scrypt": {
|
"scrypt": {
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
"deployed": false
|
"deployed": false
|
||||||
},
|
},
|
||||||
"lock": false,
|
"lock": false,
|
||||||
"isdefault": false
|
"isDefault": false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"address": "NVTiAjNgagDkTr5HTzDmQP9kPwPHN5BgVq",
|
"address": "NVTiAjNgagDkTr5HTzDmQP9kPwPHN5BgVq",
|
||||||
|
@ -41,7 +41,7 @@
|
||||||
"deployed": false
|
"deployed": false
|
||||||
},
|
},
|
||||||
"lock": false,
|
"lock": false,
|
||||||
"isdefault": false
|
"isDefault": false
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"scrypt": {
|
"scrypt": {
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
"deployed": false
|
"deployed": false
|
||||||
},
|
},
|
||||||
"lock": false,
|
"lock": false,
|
||||||
"isdefault": false
|
"isDefault": false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"address": "NVTiAjNgagDkTr5HTzDmQP9kPwPHN5BgVq",
|
"address": "NVTiAjNgagDkTr5HTzDmQP9kPwPHN5BgVq",
|
||||||
|
@ -41,7 +41,7 @@
|
||||||
"deployed": false
|
"deployed": false
|
||||||
},
|
},
|
||||||
"lock": false,
|
"lock": false,
|
||||||
"isdefault": false
|
"isDefault": false
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"scrypt": {
|
"scrypt": {
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
"deployed": false
|
"deployed": false
|
||||||
},
|
},
|
||||||
"lock": false,
|
"lock": false,
|
||||||
"isdefault": false
|
"isDefault": false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"address": "NVTiAjNgagDkTr5HTzDmQP9kPwPHN5BgVq",
|
"address": "NVTiAjNgagDkTr5HTzDmQP9kPwPHN5BgVq",
|
||||||
|
@ -41,7 +41,7 @@
|
||||||
"deployed": false
|
"deployed": false
|
||||||
},
|
},
|
||||||
"lock": false,
|
"lock": false,
|
||||||
"isdefault": false
|
"isDefault": false
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"scrypt": {
|
"scrypt": {
|
||||||
|
|
2
.github/CODEOWNERS
vendored
2
.github/CODEOWNERS
vendored
|
@ -1 +1 @@
|
||||||
* @AnnaShaleva @roman-khimov @fyrchik
|
* @AnnaShaleva @roman-khimov
|
||||||
|
|
37
.github/workflows/build.yml
vendored
37
.github/workflows/build.yml
vendored
|
@ -37,29 +37,23 @@ jobs:
|
||||||
runs-on: ${{matrix.os.name}}
|
runs-on: ${{matrix.os.name}}
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
os: [{ name: ubuntu-20.04, bin-name: linux }, { name: windows-2022, bin-name: windows }, { name: macos-12, bin-name: darwin }]
|
os: [{ name: ubuntu-22.04, bin-name: linux }, { name: windows-2022, bin-name: windows }, { name: macos-12, bin-name: darwin }]
|
||||||
arch: [amd64, arm64]
|
arch: [amd64, arm64]
|
||||||
exclude:
|
exclude:
|
||||||
- os: { name: windows-2022, bin-name: windows }
|
- os: { name: windows-2022, bin-name: windows }
|
||||||
arch: 'arm64'
|
arch: 'arm64'
|
||||||
- os: { name: macos-12, bin-name: darwin }
|
|
||||||
arch: 'amd64'
|
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
ref: ${{ github.event.inputs.ref }}
|
ref: ${{ github.event.inputs.ref }}
|
||||||
# Allows to fetch all history for all branches and tags. Need this for proper versioning.
|
# Allows to fetch all history for all branches and tags. Need this for proper versioning.
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
- name: Set up Go
|
- name: Set up Go
|
||||||
uses: actions/setup-go@v4
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: '1.20'
|
go-version: '1.22'
|
||||||
cache: true
|
|
||||||
|
|
||||||
- name: Update Go modules
|
|
||||||
run: go mod download -json
|
|
||||||
|
|
||||||
- name: Build CLI
|
- name: Build CLI
|
||||||
run: make build
|
run: make build
|
||||||
|
@ -70,7 +64,7 @@ jobs:
|
||||||
run: mv ./bin/neo-go* ./bin/neo-go-${{ matrix.os.bin-name }}-${{ matrix.arch }}${{ (matrix.os.bin-name == 'windows' && '.exe') || '' }}
|
run: mv ./bin/neo-go* ./bin/neo-go-${{ matrix.os.bin-name }}-${{ matrix.arch }}${{ (matrix.os.bin-name == 'windows' && '.exe') || '' }}
|
||||||
|
|
||||||
- name: Upload artifact
|
- name: Upload artifact
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: neo-go-${{ matrix.os.bin-name }}-${{ matrix.arch }}
|
name: neo-go-${{ matrix.os.bin-name }}-${{ matrix.arch }}
|
||||||
path: ./bin/neo-go*
|
path: ./bin/neo-go*
|
||||||
|
@ -85,23 +79,23 @@ jobs:
|
||||||
build_image:
|
build_image:
|
||||||
needs: build_cli
|
needs: build_cli
|
||||||
name: Build and push docker image
|
name: Build and push docker image
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-22.04
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
ref: ${{ github.event.inputs.ref }}
|
ref: ${{ github.event.inputs.ref }}
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
- name: Set up QEMU
|
- name: Set up QEMU
|
||||||
uses: docker/setup-qemu-action@v2
|
uses: docker/setup-qemu-action@v3
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v2
|
uses: docker/setup-buildx-action@v3
|
||||||
|
|
||||||
- name: Login to DockerHub
|
- name: Login to DockerHub
|
||||||
if: ${{ github.event_name == 'release' || (github.event_name == 'workflow_dispatch' && github.event.inputs.push_image == 'true') }}
|
if: ${{ github.event_name == 'release' || (github.event_name == 'workflow_dispatch' && github.event.inputs.push_image == 'true') }}
|
||||||
uses: docker/login-action@v2
|
uses: docker/login-action@v3
|
||||||
with:
|
with:
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
password: ${{ secrets.DOCKERHUB_PASSWORD }}
|
password: ${{ secrets.DOCKERHUB_PASSWORD }}
|
||||||
|
@ -116,7 +110,7 @@ jobs:
|
||||||
run: echo "latest=,${{ steps.setvars.outputs.repo }}:latest" >> $GITHUB_OUTPUT
|
run: echo "latest=,${{ steps.setvars.outputs.repo }}:latest" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- name: Build and push
|
- name: Build and push
|
||||||
uses: docker/build-push-action@v3
|
uses: docker/build-push-action@v5
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
push: ${{ github.event_name == 'release' || (github.event_name == 'workflow_dispatch' && github.event.inputs.push_image == 'true') }}
|
push: ${{ github.event_name == 'release' || (github.event_name == 'workflow_dispatch' && github.event.inputs.push_image == 'true') }}
|
||||||
|
@ -132,21 +126,20 @@ jobs:
|
||||||
runs-on: windows-2022
|
runs-on: windows-2022
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
ref: ${{ github.event.inputs.ref }}
|
ref: ${{ github.event.inputs.ref }}
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
# For proper `deps` make target execution.
|
# For proper `deps` make target execution.
|
||||||
- name: Set up Go
|
- name: Set up Go
|
||||||
uses: actions/setup-go@v4
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: '1.20'
|
go-version: '1.22'
|
||||||
cache: true
|
|
||||||
|
|
||||||
- name: Login to DockerHub
|
- name: Login to DockerHub
|
||||||
if: ${{ github.event_name == 'release' || (github.event_name == 'workflow_dispatch' && github.event.inputs.push_image == 'true') }}
|
if: ${{ github.event_name == 'release' || (github.event_name == 'workflow_dispatch' && github.event.inputs.push_image == 'true') }}
|
||||||
uses: docker/login-action@v2
|
uses: docker/login-action@v3
|
||||||
with:
|
with:
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
password: ${{ secrets.DOCKERHUB_PASSWORD }}
|
password: ${{ secrets.DOCKERHUB_PASSWORD }}
|
||||||
|
|
11
.github/workflows/contribution_guidelines.yml
vendored
Normal file
11
.github/workflows/contribution_guidelines.yml
vendored
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
name: Contribution guidelines
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
commits_check_job:
|
||||||
|
name: DCO check
|
||||||
|
uses: nspcc-dev/.github/.github/workflows/dco.yml@master
|
21
.github/workflows/dco.yml
vendored
21
.github/workflows/dco.yml
vendored
|
@ -1,21 +0,0 @@
|
||||||
name: DCO check
|
|
||||||
|
|
||||||
on:
|
|
||||||
pull_request:
|
|
||||||
branches:
|
|
||||||
- master
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
commits_check_job:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
name: Commits Check
|
|
||||||
steps:
|
|
||||||
- name: Get PR Commits
|
|
||||||
id: 'get-pr-commits'
|
|
||||||
uses: tim-actions/get-pr-commits@master
|
|
||||||
with:
|
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
- name: DCO Check
|
|
||||||
uses: tim-actions/dco@master
|
|
||||||
with:
|
|
||||||
commits: ${{ steps.get-pr-commits.outputs.commits }}
|
|
|
@ -8,7 +8,7 @@ on:
|
||||||
- master
|
- master
|
||||||
types: [opened, synchronize]
|
types: [opened, synchronize]
|
||||||
paths-ignore:
|
paths-ignore:
|
||||||
- 'scripts/**'
|
- 'scripts/*.sh'
|
||||||
- '**/*.md'
|
- '**/*.md'
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
|
@ -18,26 +18,61 @@ jobs:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/setup-go@v4
|
- uses: actions/checkout@v4
|
||||||
|
- uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: '1.18'
|
go-version-file: 'go.mod'
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- name: golangci-lint
|
- name: golangci-lint
|
||||||
uses: golangci/golangci-lint-action@v3
|
uses: golangci/golangci-lint-action@v4
|
||||||
with:
|
with:
|
||||||
version: latest
|
version: latest
|
||||||
|
skip-pkg-cache: true # golangci-lint can't work with this cache enabled, ref. https://github.com/golangci/golangci-lint-action/issues/135.
|
||||||
|
|
||||||
gomodcheck:
|
gomodcheck:
|
||||||
name: Check internal dependencies
|
name: Check internal dependencies
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
- name: Check dependencies
|
- name: Check dependencies
|
||||||
run: |
|
run: |
|
||||||
./scripts/check_deps.sh
|
./scripts/check_deps.sh
|
||||||
|
- name: Check go.mod is tidy
|
||||||
|
run: |
|
||||||
|
go mod tidy
|
||||||
|
if [[ $(git diff --name-only go.* | grep '' -c) != 0 ]]; then
|
||||||
|
echo "go mod tidy should be executed before the merge, following packages are unused or out of date:";
|
||||||
|
git diff go.*;
|
||||||
|
exit 1;
|
||||||
|
fi
|
||||||
|
|
||||||
|
codegencheck:
|
||||||
|
name: Check code generated with 'go generate' is up-to-date
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
- uses: actions/setup-go@v5
|
||||||
|
with:
|
||||||
|
go-version-file: 'go.mod'
|
||||||
|
|
||||||
|
- name: Install stringer
|
||||||
|
run: go install golang.org/x/tools/cmd/stringer@latest
|
||||||
|
|
||||||
|
- name: Run go generate
|
||||||
|
run: go generate ./...
|
||||||
|
|
||||||
|
- name: Check that autogenerated code is up-to-date
|
||||||
|
run: |
|
||||||
|
if [[ $(git diff --name-only | grep '' -c) != 0 ]]; then
|
||||||
|
echo "Fresh version of autogenerated code should be committed for the following files:";
|
||||||
|
git diff --name-only;
|
||||||
|
exit 1;
|
||||||
|
fi
|
||||||
|
|
||||||
codeql:
|
codeql:
|
||||||
name: CodeQL
|
name: CodeQL
|
||||||
|
@ -53,11 +88,11 @@ jobs:
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
# Initializes the CodeQL tools for scanning.
|
# Initializes the CodeQL tools for scanning.
|
||||||
- name: Initialize CodeQL
|
- name: Initialize CodeQL
|
||||||
uses: github/codeql-action/init@v2
|
uses: github/codeql-action/init@v3
|
||||||
with:
|
with:
|
||||||
languages: ${{ matrix.language }}
|
languages: ${{ matrix.language }}
|
||||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||||
|
@ -68,7 +103,7 @@ jobs:
|
||||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||||
# If this step fails, then you should remove it and run the build manually (see below)
|
# If this step fails, then you should remove it and run the build manually (see below)
|
||||||
- name: Autobuild
|
- name: Autobuild
|
||||||
uses: github/codeql-action/autobuild@v2
|
uses: github/codeql-action/autobuild@v3
|
||||||
|
|
||||||
# ℹ️ Command-line programs to run using the OS shell.
|
# ℹ️ Command-line programs to run using the OS shell.
|
||||||
# 📚 https://git.io/JvXDl
|
# 📚 https://git.io/JvXDl
|
||||||
|
@ -82,41 +117,37 @@ jobs:
|
||||||
# make release
|
# make release
|
||||||
|
|
||||||
- name: Perform CodeQL Analysis
|
- name: Perform CodeQL Analysis
|
||||||
uses: github/codeql-action/analyze@v2
|
uses: github/codeql-action/analyze@v3
|
||||||
|
|
||||||
test_cover:
|
test_cover:
|
||||||
name: Coverage
|
name: Coverage
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-22.04
|
||||||
|
|
||||||
env:
|
env:
|
||||||
CGO_ENABLED: 0
|
CGO_ENABLED: 0
|
||||||
|
GOEXPERIMENT: nocoverageredesign
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
submodules: 'true'
|
||||||
- name: Sync VM submodule
|
|
||||||
run: |
|
|
||||||
git submodule sync
|
|
||||||
git submodule update --init
|
|
||||||
|
|
||||||
- name: Set up Go
|
- name: Set up Go
|
||||||
uses: actions/setup-go@v4
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: '1.20'
|
go-version: '1.22'
|
||||||
cache: true
|
cache: true
|
||||||
|
|
||||||
- name: Update Go modules
|
|
||||||
run: go mod download -json
|
|
||||||
|
|
||||||
- name: Write coverage profile
|
- name: Write coverage profile
|
||||||
run: go test -v ./... -coverprofile=./coverage.txt -covermode=atomic -coverpkg=./pkg...,./cli/...
|
run: go test -timeout 15m -v ./... -coverprofile=./coverage.txt -covermode=atomic -coverpkg=./pkg...,./cli/...
|
||||||
|
|
||||||
- name: Upload coverage results to Codecov
|
- name: Upload coverage results to Codecov
|
||||||
uses: codecov/codecov-action@v2
|
uses: codecov/codecov-action@v4
|
||||||
with:
|
with:
|
||||||
fail_ci_if_error: true # if something is wrong on uploading codecov results, then this job will fail
|
fail_ci_if_error: true # if something is wrong on uploading codecov results, then this job will fail
|
||||||
files: ./coverage.txt
|
files: ./coverage.txt
|
||||||
|
slug: nspcc-dev/neo-go
|
||||||
|
token: ${{ secrets.CODECOV_TOKEN }}
|
||||||
verbose: true
|
verbose: true
|
||||||
|
|
||||||
tests:
|
tests:
|
||||||
|
@ -124,40 +155,36 @@ jobs:
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
os: [ubuntu-20.04, windows-2022, macos-12]
|
os: [ubuntu-22.04, windows-2022, macos-12, macos-14]
|
||||||
go_versions: [ '1.18', '1.19', '1.20' ]
|
go_versions: [ '1.20', '1.21', '1.22' ]
|
||||||
exclude:
|
exclude:
|
||||||
# Only latest Go version for Windows and MacOS.
|
# Only latest Go version for Windows and MacOS.
|
||||||
- os: windows-2022
|
- os: windows-2022
|
||||||
go_versions: '1.18'
|
|
||||||
- os: windows-2022
|
|
||||||
go_versions: '1.19'
|
|
||||||
- os: macos-12
|
|
||||||
go_versions: '1.18'
|
|
||||||
- os: macos-12
|
|
||||||
go_versions: '1.19'
|
|
||||||
# Exclude latest Go version for Ubuntu as Coverage uses it.
|
|
||||||
- os: ubuntu-20.04
|
|
||||||
go_versions: '1.20'
|
go_versions: '1.20'
|
||||||
|
- os: windows-2022
|
||||||
|
go_versions: '1.21'
|
||||||
|
- os: macos-12
|
||||||
|
go_versions: '1.20'
|
||||||
|
- os: macos-12
|
||||||
|
go_versions: '1.21'
|
||||||
|
- os: macos-14
|
||||||
|
go_versions: '1.20'
|
||||||
|
- os: macos-14
|
||||||
|
go_versions: '1.21'
|
||||||
|
# Exclude latest Go version for Ubuntu as Coverage uses it.
|
||||||
|
- os: ubuntu-22.04
|
||||||
|
go_versions: '1.22'
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
submodules: 'true'
|
||||||
|
|
||||||
- name: Set up Go
|
- name: Set up Go
|
||||||
uses: actions/setup-go@v4
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: '${{ matrix.go_versions }}'
|
go-version: '${{ matrix.go_versions }}'
|
||||||
cache: true
|
|
||||||
|
|
||||||
- name: Update Go modules
|
|
||||||
run: go mod download -json
|
|
||||||
|
|
||||||
- name: Sync VM submodule
|
|
||||||
run: |
|
|
||||||
git submodule sync
|
|
||||||
git submodule update --init
|
|
||||||
|
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
run: go test -v -race ./...
|
run: go test -timeout 15m -v -race ./...
|
475
CHANGELOG.md
475
CHANGELOG.md
|
@ -2,6 +2,479 @@
|
||||||
|
|
||||||
This document outlines major changes between releases.
|
This document outlines major changes between releases.
|
||||||
|
|
||||||
|
## 0.106.1 "Implication" (3 Jun 2024)
|
||||||
|
|
||||||
|
An urgent release that fixes mainnet state difference at block 5462944 which halts
|
||||||
|
blocks processing starting from the height 5468658. This release requires full node
|
||||||
|
DB resynchronization for mainnet nodes. T5 testnet DB state is not affected by this
|
||||||
|
bug (at least up to the current 4087361 height). Thus, DB resynchronisation may be
|
||||||
|
skipped for testnet nodes. No configuration changes implied.
|
||||||
|
|
||||||
|
Bugs fixed:
|
||||||
|
* mainnet state difference at block 5462944 caused by runtime notification
|
||||||
|
permissions check against the updated contract state instead of executing state
|
||||||
|
(#3472)
|
||||||
|
* unused neofs-contract dependency in the node modules (#3458)
|
||||||
|
|
||||||
|
## 0.106.0 "Zephyranthes" (21 May 2024)
|
||||||
|
|
||||||
|
We're rolling out a large set of updates including all of Neo 3.7.4 protocol changes:
|
||||||
|
native contracts update functionality and extended native contract APIs united under
|
||||||
|
the upcoming Cockatrice hardfork. For smart contract developers an ability to
|
||||||
|
generate smart contract bindings with dynamic hash is supported as well as a number
|
||||||
|
of useful extensions for `unwrap` package, compatible NNS smart contract RPC binding
|
||||||
|
and a lot of other handy enhancements. This release also includes a couple of severe
|
||||||
|
regression bug fixes affecting the node state. As a bonus of fixing a wide range of
|
||||||
|
failing tests, we've refactored the node services start and shutdown procedures to
|
||||||
|
make it more stable. This version drops support for Go 1.19 and requires 1.20+ to
|
||||||
|
build (with Go 1.22 supported).
|
||||||
|
|
||||||
|
Notice that this release requires full node resynchronization for both mainnet
|
||||||
|
and testnet nodes. Please pay a special attention to the Cockatrice hardfork schedule
|
||||||
|
and check your configurations. It should be configured for 3967000 of T5 testnet and
|
||||||
|
5450000 of mainnet. To ensure compatibility your node must be configured
|
||||||
|
appropriately.
|
||||||
|
|
||||||
|
New features:
|
||||||
|
* native contracts update functionality bound to hardforks (#3402, #3444)
|
||||||
|
* Cockatrice hardfork planned for 5450000 block of mainnet and 3967000 block of T5
|
||||||
|
testnet (#3402, #3448, #3402, #3446)
|
||||||
|
* `CommitteeChanged` events are emitted by NeoToken native contract starting from
|
||||||
|
Cockatrice hardfork (#3351, #3448)
|
||||||
|
* `getCommitteeAddress` method of NeoToken native contract is available starting
|
||||||
|
from Cockatrice hardfork (#3362, #3402)
|
||||||
|
* `keccak256` method of CryptoLib native contract is available starting from
|
||||||
|
Cockatrice hardfork (#3301, #3402)
|
||||||
|
* dynamic contract hash support for smart contract bindings (#3405)
|
||||||
|
* support `StringCompressed` API for `crypto.PublicKey` (#3408)
|
||||||
|
* support `Copy` API for `transaction.Transaction` and `payload.P2PNotaryRequest`
|
||||||
|
(#3407)
|
||||||
|
* extend `verifyWithECDsa` method of native CryptoLib contract with Keccak256 hasher
|
||||||
|
starting from Cockatrice and add an example of custom Koblitz-based and
|
||||||
|
Keccak256-based transaction witness verification (#3425)
|
||||||
|
* autogenerated `nativehashes` package (#3402, #3431)
|
||||||
|
* introduce `unwrap.Exception` type for better RPC invocation result exceptions
|
||||||
|
detection (#3438)
|
||||||
|
|
||||||
|
Behavior changes:
|
||||||
|
* Neo Name Service smart contract RPC binding follows the official N3 implementation
|
||||||
|
(#3291)
|
||||||
|
* clear LastGasPerVote NeoToken account info on unvoting (#3349)
|
||||||
|
* return fault exception (if any) in `unwrap` RPC client helpers (#3356)
|
||||||
|
* move P2PNotary designation role out of P2PSigExtensions (#3452)
|
||||||
|
|
||||||
|
Improvements:
|
||||||
|
* support `smartcontract.Convertible` interface as RPC Actor and Invoker call
|
||||||
|
parameters (#3297)
|
||||||
|
* allow to import multisignature account into wallet without WIF and password
|
||||||
|
specified (#3293)
|
||||||
|
* upgrade go-ordered-json dependency to avoid possible node state incompatibility
|
||||||
|
issues caused by smart contract manifest marshalling (#3331, #3333)
|
||||||
|
* Go 1.22 support, bump minimum required Go version up to Go 1.20 (#3336)
|
||||||
|
* a number of dependent libraries are updated to the fresh versions (#3338, #3418)
|
||||||
|
* improve error message of `System.Crypto.CheckMultisig` interop API handler (#3374)
|
||||||
|
* upgrade dBFT library to v0.2.0 (#3371, #3413)
|
||||||
|
* increase `ValidUntilBlock` value for transactions generated by CLI commands
|
||||||
|
(#3376)
|
||||||
|
* documentation updates (#3375, #3382)
|
||||||
|
* let default Notary Actor options be customizable (#3394)
|
||||||
|
* extend `getversion` RPC response with RPC server settings (#3386)
|
||||||
|
* make errors related to wallet opening more detailed (#3389)
|
||||||
|
* adjust error messages of `setExecFeeFactor` and `setStoragePrice` methods of
|
||||||
|
native PolicyContract (#3406)
|
||||||
|
* make neotest chain constructor options customizable (#3404)
|
||||||
|
* format improvements for CLI commands description (#3410)
|
||||||
|
* make state dumps comparator script more verbose (#3411)
|
||||||
|
* refactor storage `Get` implementation for BoltDB (#3441)
|
||||||
|
* add `updatecounter` field to the resulting items of `getnativecontracts` RPC API
|
||||||
|
call (#3439)
|
||||||
|
|
||||||
|
Bugs fixed:
|
||||||
|
* node panic on committee missing from node configuration (#3294)
|
||||||
|
* autogenerated RPC bindings do not follow Go naming convention (#3299)
|
||||||
|
* a batch of failing tests is fixed (#3306, #3313, #3321, #3332, #3337, #3335,
|
||||||
|
#3344, #3340, #3350, #3355, #3364, #3368, #3377, #3393, #3397, #3392, #3398,
|
||||||
|
#3400)
|
||||||
|
* outdated minimum required Go version of boilerplate contract generated by
|
||||||
|
`neo-go contract init` (#3318)
|
||||||
|
* outdated address used as an example in RPC client documentation (#3327)
|
||||||
|
* ungraceful node services shutdown procedure (#3307)
|
||||||
|
* logging data race on node services shutdown (#3307)
|
||||||
|
* Map parameter support is missing from RPC server handlers (#3329)
|
||||||
|
* smart contract storage iterator prefix wasn't copied while iterating over values
|
||||||
|
(#3336)
|
||||||
|
* RPC error with -511 code (insufficient funds) returned on `sendrawtransaction` RPC
|
||||||
|
request should cover multiple cases of sender's insufficient funds (#3360, #3361)
|
||||||
|
* reentrancy possibility for Notary deposit withdrawal (#3357)
|
||||||
|
* null `findstorage` RPC response in case of missing storage items (#3385)
|
||||||
|
* uninitialized named return variables in compiler (#3401)
|
||||||
|
* wrong debug sequence points after `JUMP*` instructions shortening by compiler
|
||||||
|
(#3412)
|
||||||
|
* corrupted genesis block record and application log caused by improper Conflicts
|
||||||
|
attribute processing (#3437)
|
||||||
|
* false positive DB-based blocked accounts detection in native PolicyContract leaded
|
||||||
|
to invalid committee computations and reward distribution made by NeoToken (#3443)
|
||||||
|
|
||||||
|
## 0.105.1 "Enumeration" (12 Jan 2024)
|
||||||
|
|
||||||
|
This is another v3.6.2-compatible release that fixes mainnet state difference at
|
||||||
|
block 4688591. It is confirmed to have the same state up to 4723K height (which
|
||||||
|
is current), but to get proper mainnet state you need to resynchronize your node
|
||||||
|
from the genesis. T5 testnet state is not affected (at least up to the current
|
||||||
|
3323K height), thus DB resynchronisation may be skipped for testnet nodes.
|
||||||
|
|
||||||
|
Improvements:
|
||||||
|
* better network services logging (#3287, #3290)
|
||||||
|
|
||||||
|
Bugs fixed:
|
||||||
|
* state difference at block 4688591 of N3 mainnet caused by difference at
|
||||||
|
characters escaping during manifest's `Extra` field JSON serialisation (#3286)
|
||||||
|
|
||||||
|
## 0.105.0 "Designation" (29 Dec 2023)
|
||||||
|
|
||||||
|
We're rolling out an update for NeoGo nodes that contains a number of user-facing
|
||||||
|
API improvements for RPC web-socket notification subsystem, CLI utility, wallet
|
||||||
|
related packages and not only. Try out our new `--await` CLI option for those
|
||||||
|
commands that relay transactions to the network to automatically wait for the
|
||||||
|
on-chain transaction execution result. Subscribe for new block headers with
|
||||||
|
extended RPC notification subsystem interface. Use contract-based accounts
|
||||||
|
provided by `wallet` package and `neotest` framework to sign transactions. These
|
||||||
|
and a set of other improvements are available to our users while this release is
|
||||||
|
staying compatible with 3.6.2 version of C# node.
|
||||||
|
|
||||||
|
This version also delivers a bug fix for consensus node panic caused by improper
|
||||||
|
native NeoToken cache initialisation. Moreover, there's a set of RPC server side
|
||||||
|
improvements, thus, we recommend to upgrade both consensus and RPC nodes to
|
||||||
|
provide more stable consensus node functioning and extended user APIs functionality.
|
||||||
|
No database resynchronisation is needed.
|
||||||
|
|
||||||
|
New features:
|
||||||
|
* block headers RPC web-socket subscription (#3252)
|
||||||
|
* --await option to synchronize on transaction execution for CLI commands (#3265)
|
||||||
|
* partial session-based RPC iterator unwrapping (#3274)
|
||||||
|
* contract-based transaction signers in neotest framework (#3233)
|
||||||
|
* AMD64 release binaries for macOS (#3251)
|
||||||
|
* complex contract signature schemes in wallet.Account (#3256)
|
||||||
|
|
||||||
|
Behavior changes:
|
||||||
|
* basic RPC subscription filter validity checks are implemented on both RPC
|
||||||
|
client and RPC server sides (#3258)
|
||||||
|
* filter of notary request event RPC subscription is extended with `type` field
|
||||||
|
(#3236)
|
||||||
|
* if available, use block headers RPC web-socket subscription for transaction
|
||||||
|
awaiting via `waiter` package API (#3283)
|
||||||
|
|
||||||
|
Improvements:
|
||||||
|
* add smart contract storage limits to interop utilities (#3232)
|
||||||
|
* extend ZKP examples documentation with additional links to PoT ceremony
|
||||||
|
response files (#3234)
|
||||||
|
* support Go types in VM emitter API (#3237)
|
||||||
|
* documentation update (#3239, #3242, #3246)
|
||||||
|
* BoltDB (go.etcd.io/bbolt) dependency upgrade (#3250)
|
||||||
|
* CLI code refactoring (#2682)
|
||||||
|
* extend wallet package to work with byte slice based wallets (#3255)
|
||||||
|
* export RPC client side transaction awaiting functionality via `waiter` package
|
||||||
|
(#3265, #3283)
|
||||||
|
|
||||||
|
Bugs fixed:
|
||||||
|
* remove stale `updatehistory` section of `getnativecontracts` RPC response (#3240)
|
||||||
|
* immediately check RPC client initialisation on access to blocks RPC subscription
|
||||||
|
API (#3257, #3261)
|
||||||
|
* fix CN panic caused by unexpected call to native NeoToken cache (#3253)
|
||||||
|
* make "automatically generated" warning of all automatically generated files
|
||||||
|
follow the standard (#3280)
|
||||||
|
|
||||||
|
## 0.104.0 "Globalization" (27 Nov 2023)
|
||||||
|
|
||||||
|
We're updating NeoGo to push out a number of useful updates and protocol
|
||||||
|
extensions as well as make it compatible with 3.6.2 version of C# node. The most
|
||||||
|
invasive behaviour changes are VM-level protocol constraints imposed on the size
|
||||||
|
of serialized stackitems and `NativeActivation` node setting removal. This version
|
||||||
|
also delivers a set of smaller useful changes in the interoperability layer and
|
||||||
|
native contract functionality including System.Runtime.CurrentSigners interop,
|
||||||
|
`strLen` StdLib method and PolicyContract-based transaction attributes pricing
|
||||||
|
as far as a user-facing `canceltx` CLI command and community-requested
|
||||||
|
`--relative-path` CLI option.
|
||||||
|
|
||||||
|
Node operators must resynchronize their nodes to get fully compatible state
|
||||||
|
(which is confirmed to be compatible with 3.6.2 for current mainnet up to
|
||||||
|
block 4483627 and T5 testnet up to block 3078762). Please, ensure your node
|
||||||
|
configuration doesn't contain `NativeActivations` protocol configuration section
|
||||||
|
as this logic is hidden under Hardforks starting from the current release.
|
||||||
|
|
||||||
|
New features:
|
||||||
|
* System.Runtime.CurrentSigners interop allowing to get signers of the currently
|
||||||
|
loaded transaction (#3058)
|
||||||
|
* `strLen` method to native StdLib contract (#3208)
|
||||||
|
* transaction attributes pricing regulation via native PolicyContract (#3155)
|
||||||
|
* `canceltx` CLI command as an alternative to unsupported `canceltransaction` RPC
|
||||||
|
request (#3223, #3214)
|
||||||
|
|
||||||
|
Behaviour changes:
|
||||||
|
* reduce maximum allowed stackitem.Item size (#3185)
|
||||||
|
* restrict maximum allowed NEF file size and prohibit large contracts deployment (#3186)
|
||||||
|
* bind `NativeActivations` node setting to the `Hardforks` setting (#3212)
|
||||||
|
* introduce serialization limit to stackitem.Item and fail large contracts deploy
|
||||||
|
wrt this setting (#3218)
|
||||||
|
* add customizable `MaxRequestBodyBytes` and `MaxRequestHeaderBytes` RPC server
|
||||||
|
configuration setting (#3221)
|
||||||
|
|
||||||
|
Improvements:
|
||||||
|
* provide more detailed error on attempt to read non-existent service wallet
|
||||||
|
provided via node configuration file (#3210)
|
||||||
|
* optimize emit of imported code for autogenerated RPC bindings (#3215)
|
||||||
|
* documentation update (#3203, #3222)
|
||||||
|
* add `--relative-path` CLI flag allowing to override configuration-specific relative
|
||||||
|
paths (#3206)
|
||||||
|
* update code owners (#3216, @fyrchik will live in our hearts forever)
|
||||||
|
|
||||||
|
Bugs fixed:
|
||||||
|
* unify messages of RPC errors according to the RPC errors NEP (#3199)
|
||||||
|
* limit maximum allowed number ad depth of transaction signers and witnesses per
|
||||||
|
RPC request that accept transaction (#3207, #3221)
|
||||||
|
* forbid unknown fields usage in the node configuration file (#3209)
|
||||||
|
* enable hardfork-dependant code starting exactly from the block height specified
|
||||||
|
in the node configuration (#3211)
|
||||||
|
* require Notary native deposit to be valid for at least one subsequent block after
|
||||||
|
deposit transaction acceptance (#3211)
|
||||||
|
* deduplicate unnamed event types for autogenerated RPC bindings and make the
|
||||||
|
binding generation order strictly defined and stable (#3215, #3220)
|
||||||
|
* do not panic on trying to compile an import cycle (#3215)
|
||||||
|
* state difference at block 3002333 of T5 testnet caused by difference at characters
|
||||||
|
escaping during manifest's `Extra` field JSON serialisation (#3225)
|
||||||
|
* properly start node services that depend on native RoleManagement contract data
|
||||||
|
with genesis `Roles` protocol configuration setting specified (#3229)
|
||||||
|
|
||||||
|
## 0.103.1 "Verification" (09 Nov 2023)
|
||||||
|
|
||||||
|
An urgent 3.6.0-compatible version that contains a hotfix for the bug that
|
||||||
|
prevents node from starting from the existing database every new dBFT epoch.
|
||||||
|
Also, the release includes a bugfix that fails any non-zero NEO and GAS
|
||||||
|
roundtrips from accounts with zero balance.
|
||||||
|
|
||||||
|
Although the DB format and storage states were not affected by this release,
|
||||||
|
the node resynchronization is still recommended for those who want to keep
|
||||||
|
correct application logs. Resynchronization can be skipped if you're ok with
|
||||||
|
wrong application logs for some transactions (e.g. CN doesn't care, and RPC node
|
||||||
|
cares a lot).
|
||||||
|
|
||||||
|
Bugs fixed:
|
||||||
|
* properly initialize cache of native NeoToken contract every new dBFT epoch (#3187)
|
||||||
|
* forbid non-zero NEO and GAS roundtrips from accounts with zero balance (#3191)
|
||||||
|
|
||||||
|
## 0.103.0 "Backwardation" (20 Oct 2023)
|
||||||
|
|
||||||
|
A minor 3.6.0-compatible version of NeoGo with new salty ZKP-related
|
||||||
|
functionality, a large batch of deprecated APIs removal and an experimental
|
||||||
|
genesis block extension. Build Groth-16 circuits, generate proofs and deploy
|
||||||
|
verification contracts easily with the new end-to-end ZKP example and `zkpbinding`
|
||||||
|
NeoGo API. Setup node roles via the node configuration starting from the genesis
|
||||||
|
block without any painful multisignature transaction forming and invoke any
|
||||||
|
custom script in the genesis-level transaction with the new `Genesis` protocol
|
||||||
|
configuration extension. And don't forget to move from deprecated RPC client
|
||||||
|
APIs, as a lot of them have been removed.
|
||||||
|
|
||||||
|
New node configuration format is finally adapted and the deprecated configuration
|
||||||
|
sections are permanently removed according to the schedule. Pay attention to the
|
||||||
|
`SecondsPerBlock` protocol configuration section that was replaced by
|
||||||
|
`TimePerBlock`, a set of node and services address- and port- related configuration
|
||||||
|
section that were replaced by the new `Addresses` format, direct `UnlockWallet`
|
||||||
|
consensus configuration that was replaced by a separate `Consensus` section and
|
||||||
|
a set of node-specific protocol configurations that were moved under a separate
|
||||||
|
`P2P` section.
|
||||||
|
|
||||||
|
This release fixes a set of bugs including a vulnerability introduced by changes
|
||||||
|
in the transaction conflicts storage scheme implemented in #3061 (a part of
|
||||||
|
0.102.0 release). With the patch presented, it's impossible to uncontrollably
|
||||||
|
pollute the storage with malicious conflicting records.
|
||||||
|
|
||||||
|
This version is fully compatible with C# node 3.6.0. However, it requires
|
||||||
|
complete resynchronization on upgrade due to the database storage scheme changes.
|
||||||
|
|
||||||
|
New features:
|
||||||
|
* API for Groth-16 verification contracts autogeneration and end-to-end example for
|
||||||
|
proving and verifying statements on NeoGo (#3043, #3146)
|
||||||
|
* introduce genesis protocol extensions: default node roles designation and genesis
|
||||||
|
transactions (#3168)
|
||||||
|
|
||||||
|
Behaviour changes:
|
||||||
|
* a lot of deprecated functionality is dropped: RPC client old APIs, shared
|
||||||
|
Notifications channel of WebSocket client, SecondsPerBlock protocol
|
||||||
|
configuration, old way of services and node address and port configuration, old
|
||||||
|
P2P related application settings configuration, direct UnlockWallet consensus
|
||||||
|
configuration, direct node-specific protocol configuration (#3150)
|
||||||
|
* database scheme is changed by new way of storing the transaction conflicting
|
||||||
|
records (#3138)
|
||||||
|
|
||||||
|
Improvements:
|
||||||
|
* NeoFS SDK dependency upgrade (#3129)
|
||||||
|
* gnark and gnark-crypto dependencies upgrade (#3145, #3162, #3163)
|
||||||
|
* introduce timeout restriction for BoltDB opening (#3148)
|
||||||
|
* bump code coverage uploading action version (#3153)
|
||||||
|
* Go 1.21 support, bump minimum required Go version up to Go 1.19 (#3157)
|
||||||
|
* upgrade golang.org/x/net version (#3158)
|
||||||
|
* add protocol hardforks configuration to the `getversion` RPC response (#3160)
|
||||||
|
* format autogenerated smart contract bindings with accordance to standard `go fmt` rules (#3164)
|
||||||
|
* add "DO NOT EDIT" warning to the autogenerated smart contract bindings (#3167)
|
||||||
|
|
||||||
|
Bugs fixed:
|
||||||
|
* avoid race between `getnextblockvalidators` RPC call handler and blockchain's
|
||||||
|
block handler routine, significantly refactor native validators caching scheme
|
||||||
|
(#3110)
|
||||||
|
* do not panic on failed NeoFS oracle requests (#3129)
|
||||||
|
* enable Notary subsystem in NeoFS mainnet configuration (#3136)
|
||||||
|
* reorganize storage scheme for transaction conflicting records to avoid possible attack (#3138)
|
||||||
|
* properly deserialize wildcard trusts field of smart contract manifest (#3140)
|
||||||
|
* use more strict GAS limit for transaction network fee calculation via RPC call (#3141)
|
||||||
|
* avoid WebSocket client request blocking (#3142)
|
||||||
|
* properly emit big uint64 constants during smart contract compilation (#3147)
|
||||||
|
* avoid race access to the node version by tests (#3149)
|
||||||
|
* make FindStorage* RPC client APIs to be always compatible with NeoC# RPC server (#3166)
|
||||||
|
|
||||||
|
## 0.102.0 "Aberration" (06 Sep 2023)
|
||||||
|
|
||||||
|
Long-awaited feature-packed 3.6.0-compatible version of NeoGo with all the
|
||||||
|
appropriate protocol updates and a set of tasty improvements and bug
|
||||||
|
fixes. Groth16 ZKP proof checks are there for contract developers as well as
|
||||||
|
new opcodes. A huge number of improvements went into the RPC server and
|
||||||
|
client, new RPCs, improved contract binding generator and standardized
|
||||||
|
extended error codes make developing dApps much easier.
|
||||||
|
|
||||||
|
Users of smart contract utilities and RPC-related Prometheus metrics are
|
||||||
|
advised to take a look at the deprecated APIs removal schedule
|
||||||
|
(ROADMAP.md). This version was delayed for quite some time (waiting for 3.6),
|
||||||
|
so the next minor release (0.103.0) will remove a substantial amount of
|
||||||
|
compatibility code. It's expected to be released in November with 3.6 protocol
|
||||||
|
compatibility (3.7 cycle is likely to require more time).
|
||||||
|
|
||||||
|
This is also the first version that drops support for Go 1.17 and requires
|
||||||
|
1.18+ to build (with Go 1.20 supported). Using generics in smart contracts is
|
||||||
|
not supported yet, but some elements of this support can be implemented in
|
||||||
|
future versions.
|
||||||
|
|
||||||
|
Mainnet and testnet node operators, please pay attention to the Basilisk
|
||||||
|
hardfork schedule and check your configurations. It will happen at block
|
||||||
|
2680000 for T5 testnet and 4120000 for mainnet. To ensure compatibility your
|
||||||
|
node must be configured appropriately. This version requires DB
|
||||||
|
resynchronization, so schedule your updates accordingly.
|
||||||
|
|
||||||
|
New features:
|
||||||
|
* ZKP proof checking support via CryptoLib native contract (operations with
|
||||||
|
BLS12-381 curve points) (#2940, #3042)
|
||||||
|
* System.Storage.Find interop now support "Backwards" flag to iterate in the
|
||||||
|
opposite direction (#2952)
|
||||||
|
* `util ops` CLI utility that pretty-prints VM script (#2965)
|
||||||
|
* `notarypool_unsorted_tx` Prometheus metric for notary-enabled nodes (#2696)
|
||||||
|
* `CloseNotificationChannelIfFull` WSClient option allowing the client to
|
||||||
|
close notification channel on overflow (#2988)
|
||||||
|
* autogenerated RPC bindings for contract events and conversion code from
|
||||||
|
stackitem.Item to structure (#3008, #3035, #3036, #3087)
|
||||||
|
* event type inference from contract code (#3008)
|
||||||
|
* dynamic contract hashes support for RPC bindings (#3012)
|
||||||
|
* "Basilisk" protocol hardfork support (#3056, #3080, #3086, #3104)
|
||||||
|
* ABORTMSG and ASSERTMSG VM opcodes (#3066)
|
||||||
|
* standardized RPC error codes (#3063)
|
||||||
|
* `findstorage` and `findstoragehistoric` RPC support (#3099)
|
||||||
|
* `getstoragehistoric` RPC support (#3099)
|
||||||
|
* `getrawnotarypool` and `getrawnotarytransaction` RPC (#3098)
|
||||||
|
|
||||||
|
Behaviour changes:
|
||||||
|
* deprecated `FromAddress` smart contract helper is dropped from the `util`
|
||||||
|
interop package (#2941)
|
||||||
|
* a number of deprecated RPC-related Prometheus counters are permanently
|
||||||
|
removed (#2941)
|
||||||
|
* NEP-2 account label will be asked on account import via CLI (#2889)
|
||||||
|
* hashes and states of native contracts are now accessible via native
|
||||||
|
ContractManagement API (#2991)
|
||||||
|
* `serv_node_version` gauge Prometheus metric is marked as deprecated and
|
||||||
|
replaced by `neogo_version` and `server_id` (#3009)
|
||||||
|
* strict contract script check is back with Basilisk hardfork, it was
|
||||||
|
previously removed in 0.101.3 for 3.5 protocol compatibility (#3056)
|
||||||
|
* JSON number deserialization (via StdLib.jsonDeserialize) changes with
|
||||||
|
Basilisk hardfork allowing for more precision and handling more corner
|
||||||
|
cases (#3080)
|
||||||
|
* notification type errors are treated as fatal after Basilisk hardfork,
|
||||||
|
before it they're just logged (#3086)
|
||||||
|
* NULL and non-UTF8 items are not allowed for String event types (#3086)
|
||||||
|
* `Conflicts` and `NotValidBefore` transaction attributes are no longer NeoGo
|
||||||
|
extensions, they can be used on regular networks (#2962)
|
||||||
|
|
||||||
|
Improvements:
|
||||||
|
* documentation and example improvements (#2945, #2972, #2979, #3020, #3084,
|
||||||
|
#3099, #3114, #3116, #3119, #3121)
|
||||||
|
* `getproof` and `verifyproof` RPC API support in RPC client (#2942)
|
||||||
|
* Go 1.20 support, bump minimum required Go version up to Go 1.18 (#2908)
|
||||||
|
* faster state reset process (#2819)
|
||||||
|
* optimized voting data storage scheme for NEO contract (#2892, #2893)
|
||||||
|
* NeoFS SDK dependency upgrades (#2995, #3032)
|
||||||
|
* special exported error returned in case of WSClient disconnection (#3000)
|
||||||
|
* automatic guessing of contract and manifest filenames for `contract
|
||||||
|
compile` CLI command and `loadnef` VM CLI command (#3013)
|
||||||
|
* support for pushing stackitem.Convertible objects via VM script emitter (#3016)
|
||||||
|
* economic adjustment for ranking of transactions with `Conflicts` attribute (#3031)
|
||||||
|
* `google.golang.org/grpc` dependency upgrade fixing high severity security
|
||||||
|
vulnerability (#3055, gRPC is only used to communicate with NeoFS nodes in
|
||||||
|
the oracle service)
|
||||||
|
* enforce default RPC server values when it's used as an independent package
|
||||||
|
(not a part of node) (#3107)
|
||||||
|
* unwrap.Nothing function for RPC clients (#3117)
|
||||||
|
* address and reverse hash display in opcode dumps (#3115)
|
||||||
|
|
||||||
|
Bugs fixed:
|
||||||
|
* invalid peer port type returned by `getpeers` RPC response (#2914)
|
||||||
|
* invalid data source for `mempool_unsorted_tx` Prometheus metric (#2969)
|
||||||
|
* dBFT library upgrade fixing the ability of a single node to speed up the
|
||||||
|
process of new blocks creation for the whole network (#3018,
|
||||||
|
nspcc-dev/dbft#75)
|
||||||
|
* failing CALLT instructions in VM CLI for loaded NEF files (#3020)
|
||||||
|
* missing signers check for on-chain conflicting transactions (#3061)
|
||||||
|
* incorrect sequence point boundaries in debug data (#3074)
|
||||||
|
* compiler panic on encountering generic code (#3041)
|
||||||
|
* potential pooled fallback notary transaction changes (#3108)
|
||||||
|
* lost LastGasPerVote value on NEO state deserialization for non-voting
|
||||||
|
accounts (#3122)
|
||||||
|
|
||||||
|
## 0.101.4 "Yarborough" (01 Aug 2023)
|
||||||
|
|
||||||
|
Another one 3.5.0-compatible version that is aimed to fix T5 testnet state
|
||||||
|
difference that has happened at block 2336911 which leads to inability to process
|
||||||
|
new blocks since 2418703. The issue is fixed by allowing JSON numbers
|
||||||
|
unmarshalling from scientific notation to Integer stackitem. Maximum parsing
|
||||||
|
precision for such numbers is currently restricted by 53 bits. This is a
|
||||||
|
temporary C#-compatible solution that is likely to change in the future versions
|
||||||
|
when an appropriate C# node bug is fixed (neo-project/neo#2879).
|
||||||
|
|
||||||
|
A set of minor bug fixes is included as well to flush some of the long-awaited
|
||||||
|
changes that were blocked by the 0.102.0 release delay (caused by v3.6.0 C# node
|
||||||
|
release delay). In particular, invalid headers returned by an RPC server for
|
||||||
|
error responses, invalid format of incremental dumps created by CLI and deadlock
|
||||||
|
on unhealthy RPC server shutdown. Long-awaited `--config-file` CLI option to
|
||||||
|
start the node providing a single configuration file is added.
|
||||||
|
|
||||||
|
T5 testnet chain requires a complete resynchronization for this version. Mainnet
|
||||||
|
chain resynchronization is recommended, but not required.
|
||||||
|
|
||||||
|
New features:
|
||||||
|
* `--config-file` CLI option allowing to start the node with a single configuration file (#3014)
|
||||||
|
|
||||||
|
Improvements:
|
||||||
|
* blockchain Notary and Oracle services documentation improvement (#2972)
|
||||||
|
* BoltDB (`go.etcd.io/bbolt`) dependency upgrade that fixes a number of Windows-related issues (#3034)
|
||||||
|
|
||||||
|
Bugs fixed:
|
||||||
|
* panic on node start with invalid configuration (#2968)
|
||||||
|
* deadlock on unhealthy RPC server shutdown (#2966)
|
||||||
|
* improper WSClient notification channels managing after disconnection (#2980)
|
||||||
|
* missing Prometheus metric initialisation on node start (#2992)
|
||||||
|
* invalid initialisation of native contracts cache (#2994)
|
||||||
|
* incorrect way of incremental DB dumps creation (#3047)
|
||||||
|
* Notary contract is allowed to be a sender of main Notary request transaction (#3065)
|
||||||
|
* discrepancy in signer's witness scope parsing on the RPC server side (#3060)
|
||||||
|
* Invoker calling API isn't allowed to accept nil parameter (#3067)
|
||||||
|
* contract RPC Client unwrapper helper can't handle missing contract case (#3072)
|
||||||
|
* JSON numbers can't be unmarshalled to stackitem from scientific notation (#3073)
|
||||||
|
* invalid content-type header returned by RPC server on error responses (#3075)
|
||||||
|
|
||||||
## 0.101.3 "Yuckiness" (08 Jul 2023)
|
## 0.101.3 "Yuckiness" (08 Jul 2023)
|
||||||
|
|
||||||
Yet another 3.5.0-compatible emergency version that removes scrupulous
|
Yet another 3.5.0-compatible emergency version that removes scrupulous
|
||||||
|
@ -2136,7 +2609,7 @@ Behavior changes:
|
||||||
* contracts no longer have single entry point, rather they export a set of
|
* contracts no longer have single entry point, rather they export a set of
|
||||||
methods with specific offsets. Go smart contract compiler has been changed
|
methods with specific offsets. Go smart contract compiler has been changed
|
||||||
accordingly to add all exported (as in Go) methods to the manifest
|
accordingly to add all exported (as in Go) methods to the manifest
|
||||||
(but with the first letter being lowercased to match NEP-5 expections,
|
(but with the first letter being lowercased to match NEP-5 expectations,
|
||||||
#1228). Please also refer to examples changes to better see how it affects
|
#1228). Please also refer to examples changes to better see how it affects
|
||||||
contracts, manifests and configuration files (#1296)
|
contracts, manifests and configuration files (#1296)
|
||||||
* native contracts are now called via Neo.Native.Call syscall (#1191)
|
* native contracts are now called via Neo.Native.Call syscall (#1191)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# Builder image
|
# Builder image
|
||||||
# Keep go version in sync with Build GA job.
|
# Keep go version in sync with Build GA job.
|
||||||
FROM golang:1.20-alpine as builder
|
FROM golang:1.22-alpine as builder
|
||||||
|
|
||||||
# Display go version for information purposes.
|
# Display go version for information purposes.
|
||||||
RUN go version
|
RUN go version
|
||||||
|
|
|
@ -1,75 +1,6 @@
|
||||||
# Builder image
|
# Builder image
|
||||||
FROM mcr.microsoft.com/windows/servercore:ltsc2022 as builder
|
|
||||||
|
|
||||||
SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop';", "$ProgressPreference = 'SilentlyContinue';"]
|
|
||||||
|
|
||||||
ENV GIT_VERSION=2.23.0
|
|
||||||
|
|
||||||
ENV GIT_TAG=v2.23.0.windows.1
|
|
||||||
|
|
||||||
ENV GIT_DOWNLOAD_URL=https://github.com/git-for-windows/git/releases/download/v2.23.0.windows.1/MinGit-2.23.0-64-bit.zip
|
|
||||||
|
|
||||||
ENV GIT_DOWNLOAD_SHA256=8f65208f92c0b4c3ae4c0cf02d4b5f6791d539cd1a07b2df62b7116467724735
|
|
||||||
|
|
||||||
RUN Write-Host ('Downloading {0} ...' -f $env:GIT_DOWNLOAD_URL); \
|
|
||||||
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; \
|
|
||||||
Invoke-WebRequest -Uri $env:GIT_DOWNLOAD_URL -OutFile 'git.zip'; \
|
|
||||||
\
|
|
||||||
Write-Host ('Verifying sha256 ({0}) ...' -f $env:GIT_DOWNLOAD_SHA256); \
|
|
||||||
if ((Get-FileHash git.zip -Algorithm sha256).Hash -ne $env:GIT_DOWNLOAD_SHA256) { \
|
|
||||||
Write-Host 'FAILED!'; \
|
|
||||||
exit 1; \
|
|
||||||
}; \
|
|
||||||
\
|
|
||||||
Write-Host 'Expanding ...'; \
|
|
||||||
Expand-Archive -Path git.zip -DestinationPath C:\git\.; \
|
|
||||||
\
|
|
||||||
Write-Host 'Removing ...'; \
|
|
||||||
Remove-Item git.zip -Force; \
|
|
||||||
\
|
|
||||||
Write-Host 'Updating PATH ...'; \
|
|
||||||
$env:PATH = 'C:\git\cmd;C:\git\mingw64\bin;C:\git\usr\bin;' + $env:PATH; \
|
|
||||||
[Environment]::SetEnvironmentVariable('PATH', $env:PATH, [EnvironmentVariableTarget]::Machine); \
|
|
||||||
\
|
|
||||||
Write-Host 'Verifying install ("git version") ...'; \
|
|
||||||
git version; \
|
|
||||||
\
|
|
||||||
Write-Host 'Complete.';
|
|
||||||
|
|
||||||
ENV GOPATH=C:\\go
|
|
||||||
|
|
||||||
RUN $newPath = ('{0}\bin;C:\Program Files\Go\bin;{1}' -f $env:GOPATH, $env:PATH); \
|
|
||||||
Write-Host ('Updating PATH: {0}' -f $newPath); \
|
|
||||||
[Environment]::SetEnvironmentVariable('PATH', $newPath, [EnvironmentVariableTarget]::Machine);
|
|
||||||
|
|
||||||
# Keep go version in sync with Build GA job.
|
# Keep go version in sync with Build GA job.
|
||||||
ENV GOLANG_VERSION=1.20
|
FROM golang:1.22.0-windowsservercore-ltsc2022 as builder
|
||||||
|
|
||||||
RUN $url = 'https://go.dev/dl/go1.20.windows-amd64.zip'; \
|
|
||||||
Write-Host ('Downloading {0} ...' -f $url); \
|
|
||||||
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; \
|
|
||||||
Invoke-WebRequest -Uri $url -OutFile 'go.zip'; \
|
|
||||||
\
|
|
||||||
$sha256 = 'e8f6d8bbcf3df58d2ba29818e13b04c2e42ba2e4d90d580720b21c34d10bbf68'; \
|
|
||||||
Write-Host ('Verifying sha256 ({0}) ...' -f $sha256); \
|
|
||||||
if ((Get-FileHash go.zip -Algorithm sha256).Hash -ne $sha256) { \
|
|
||||||
Write-Host 'FAILED!'; \
|
|
||||||
exit 1; \
|
|
||||||
}; \
|
|
||||||
\
|
|
||||||
Write-Host 'Expanding ...'; \
|
|
||||||
Expand-Archive go.zip -DestinationPath C:\; \
|
|
||||||
\
|
|
||||||
Write-Host 'Moving ...'; \
|
|
||||||
Move-Item -Path C:\go -Destination 'C:\Program Files\Go'; \
|
|
||||||
\
|
|
||||||
Write-Host 'Removing ...'; \
|
|
||||||
Remove-Item go.zip -Force; \
|
|
||||||
\
|
|
||||||
Write-Host 'Verifying install ("go version") ...'; \
|
|
||||||
go version; \
|
|
||||||
\
|
|
||||||
Write-Host 'Complete.';
|
|
||||||
|
|
||||||
COPY . /neo-go
|
COPY . /neo-go
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
MIT License
|
MIT License
|
||||||
|
|
||||||
Copyright (c) 2018-2022 Anthony De Meulemeester (@anthdm), City of Zion
|
Copyright (c) 2018-2023 NeoSPCC (@nspcc-dev), Anthony De Meulemeester (@anthdm), City of Zion community (@CityOfZion)
|
||||||
community (@CityOfZion), NeoSPCC (@nspcc-dev)
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|
2
Makefile
2
Makefile
|
@ -3,7 +3,7 @@ REPONAME = "neo-go"
|
||||||
NETMODE ?= "privnet"
|
NETMODE ?= "privnet"
|
||||||
BINARY=neo-go
|
BINARY=neo-go
|
||||||
BINARY_PATH=./bin/$(BINARY)$(shell go env GOEXE)
|
BINARY_PATH=./bin/$(BINARY)$(shell go env GOEXE)
|
||||||
GO_VERSION ?= 1.18
|
GO_VERSION ?= 1.20
|
||||||
DESTDIR = ""
|
DESTDIR = ""
|
||||||
SYSCONFIGDIR = "/etc"
|
SYSCONFIGDIR = "/etc"
|
||||||
BINDIR = "/usr/bin"
|
BINDIR = "/usr/bin"
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
<hr />
|
<hr />
|
||||||
|
|
||||||
[![codecov](https://codecov.io/gh/nspcc-dev/neo-go/branch/master/graph/badge.svg)](https://codecov.io/gh/nspcc-dev/neo-go)
|
[![codecov](https://codecov.io/gh/nspcc-dev/neo-go/branch/master/graph/badge.svg)](https://codecov.io/gh/nspcc-dev/neo-go)
|
||||||
[![GithubWorkflows Tests](https://github.com/nspcc-dev/neo-go/actions/workflows/run_tests.yml/badge.svg)](https://github.com/nspcc-dev/neo-go/actions/workflows/run_tests.yml)
|
[![GithubWorkflows Tests](https://github.com/nspcc-dev/neo-go/actions/workflows/tests.yml/badge.svg)](https://github.com/nspcc-dev/neo-go/actions/workflows/tests.yml)
|
||||||
[![Report](https://goreportcard.com/badge/github.com/nspcc-dev/neo-go)](https://goreportcard.com/report/github.com/nspcc-dev/neo-go)
|
[![Report](https://goreportcard.com/badge/github.com/nspcc-dev/neo-go)](https://goreportcard.com/report/github.com/nspcc-dev/neo-go)
|
||||||
[![GoDoc](https://godoc.org/github.com/nspcc-dev/neo-go?status.svg)](https://godoc.org/github.com/nspcc-dev/neo-go)
|
[![GoDoc](https://godoc.org/github.com/nspcc-dev/neo-go?status.svg)](https://godoc.org/github.com/nspcc-dev/neo-go)
|
||||||
![GitHub release (latest SemVer)](https://img.shields.io/github/v/release/nspcc-dev/neo-go?sort=semver)
|
![GitHub release (latest SemVer)](https://img.shields.io/github/v/release/nspcc-dev/neo-go?sort=semver)
|
||||||
|
@ -51,7 +51,7 @@ NeoGo, `:latest` points to the latest release) or build yourself.
|
||||||
|
|
||||||
### Building
|
### Building
|
||||||
|
|
||||||
Building NeoGo requires Go 1.18+ and `make`:
|
Building NeoGo requires Go 1.20+ and `make`:
|
||||||
|
|
||||||
```
|
```
|
||||||
make
|
make
|
||||||
|
@ -180,9 +180,8 @@ describing the feature/topic you are going to implement.
|
||||||
|
|
||||||
# Contact
|
# Contact
|
||||||
|
|
||||||
- [@roman-khimov](https://github.com/roman-khimov) on GitHub
|
|
||||||
- [@AnnaShaleva](https://github.com/AnnaShaleva) on GitHub
|
- [@AnnaShaleva](https://github.com/AnnaShaleva) on GitHub
|
||||||
- [@fyrchik](https://github.com/fyrchik) on GitHub
|
- [@roman-khimov](https://github.com/roman-khimov) on GitHub
|
||||||
- Reach out to us on the [Neo Discord](https://discordapp.com/invite/R8v48YA) channel
|
- Reach out to us on the [Neo Discord](https://discordapp.com/invite/R8v48YA) channel
|
||||||
|
|
||||||
# License
|
# License
|
||||||
|
|
130
ROADMAP.md
130
ROADMAP.md
|
@ -7,14 +7,13 @@ functionality.
|
||||||
## Versions 0.7X.Y (as needed)
|
## Versions 0.7X.Y (as needed)
|
||||||
* Neo 2.0 support (bug fixes, minor functionality additions)
|
* Neo 2.0 support (bug fixes, minor functionality additions)
|
||||||
|
|
||||||
## Version 0.102.0 (~March 2022)
|
## Version 0.107.0 (~Jun-Jul 2024)
|
||||||
* 3.6.0 compatibility
|
* protocol updates
|
||||||
|
* bug fixes
|
||||||
|
* node resynchronisation from local DB
|
||||||
|
* CLI library upgrade
|
||||||
|
|
||||||
## Version 0.102.1 (~April 2022)
|
## Version 1.0 (2024, TBD)
|
||||||
* improved RPC error codes
|
|
||||||
* extended data types for iterators to be used by RPC wrapper generator
|
|
||||||
|
|
||||||
## Version 1.0 (2023, TBD)
|
|
||||||
* stable version
|
* stable version
|
||||||
|
|
||||||
# Deprecated functionality
|
# Deprecated functionality
|
||||||
|
@ -26,110 +25,21 @@ APIs/commands/configurations will be removed and here is a list of scheduled
|
||||||
breaking changes. Consider changing your code/scripts/configurations if you're
|
breaking changes. Consider changing your code/scripts/configurations if you're
|
||||||
using anything mentioned here.
|
using anything mentioned here.
|
||||||
|
|
||||||
## Old RPC client APIs
|
|
||||||
|
|
||||||
A huge set of RPC client APIs was deprecated in versions 0.99.2 and 0.99.3
|
|
||||||
(August-September 2022), including very frequently used ones like
|
|
||||||
SignAndPushInvocationTx, AddNetworkFee, TransferNEP17. A new set of
|
|
||||||
invoker/actor/unwrap/nep17/etc packages was introduced decoupling these
|
|
||||||
functions from RPC client and simplifying typical backend code. Please refer
|
|
||||||
to rpcclient package documentation for specific replacements for each of these
|
|
||||||
APIs and convert your code to using them.
|
|
||||||
|
|
||||||
While a lot of the code is already converted to new APIs, old ones still can
|
|
||||||
be used in some code not known to us. Therefore we will remove old APIs not
|
|
||||||
earlier than May 2023, with 0.103.0 release.
|
|
||||||
|
|
||||||
## WSClient Notifications channel and SubscribeFor* APIs
|
|
||||||
|
|
||||||
Version 0.99.5 of NeoGo introduces a new set of subscription APIs that gives
|
|
||||||
more control to the WSClient user that can pass specific channels to be used
|
|
||||||
for specific subscriptions now. Old APIs and generic Notifications channel are
|
|
||||||
still available, but will be removed, so please convert your code to using new
|
|
||||||
Receive* APIs.
|
|
||||||
|
|
||||||
Removal of these APIs is scheduled for May 2023 (~0.103.0 release).
|
|
||||||
|
|
||||||
## SecondsPerBlock protocol configuration
|
|
||||||
|
|
||||||
With 0.100.0 version SecondsPerBlock protocol configuration setting was
|
|
||||||
deprecated and replaced by a bit more generic and precise TimePerBlock
|
|
||||||
(allowing for subsecond time). An informational message is printed on node
|
|
||||||
startup to inform about this, it's very easy to deal with this configuration
|
|
||||||
change, just replace one line.
|
|
||||||
|
|
||||||
Removal of SecondsPerBlock is scheduled for May-June 2023 (~0.103.0 release).
|
|
||||||
|
|
||||||
## Services/node address and port configuration
|
|
||||||
|
|
||||||
Version 0.100.0 of NeoGo introduces a multiple binding addresses capability to
|
|
||||||
the node's services (RPC server, TLS RPC configuration, Prometheus, Pprof) and
|
|
||||||
the node itself. It allows to specify several listen addresses/ports using an
|
|
||||||
array of "address:port" pairs in the service's `Addresses` config section and
|
|
||||||
array of "address:port:announcedPort" tuples in the `ApplicationConfiguration`'s
|
|
||||||
`Addresses` node config section. Deprecated `Address` and `Port` sections of
|
|
||||||
`RPC`, `Prometheus`, `Pprof` subsections of the `ApplicationConfiguration`
|
|
||||||
as far as the one of RPC server's `TLSConfig` are still available, but will be
|
|
||||||
removed, so please convert your node configuration file to use new `P2P`-level
|
|
||||||
`Addresses` section for the node services. Deprecated `Address`, `NodePort` and
|
|
||||||
`AnnouncedPort` sections of `ApplicationConfiguration` will also be removed
|
|
||||||
eventually, so please update your node configuration file to use `Addresses`
|
|
||||||
section for the P2P addresses configuration.
|
|
||||||
|
|
||||||
Removal of these config sections is scheduled for May-June 2023 (~0.103.0 release).
|
|
||||||
|
|
||||||
## P2P application settings configuration
|
|
||||||
|
|
||||||
Version 0.100.0 of NeoGo marks the following P2P application settings as
|
|
||||||
deprecated: `AttemptConnPeers`, `BroadcastFactor`, `DialTimeout`,
|
|
||||||
`ExtensiblePoolSize`, `MaxPeers`, `MinPeers`, `PingInterval`, `PingTimeout`,
|
|
||||||
`ProtoTickInterval`. These settings are moved to a separate `P2P` section of
|
|
||||||
`ApplicationConfiguration`. The `DialTimeout`, `PingInterval`, `PingTimeout`,
|
|
||||||
`ProtoTickInterval` settings are converted to more precise `Duration` format
|
|
||||||
(allowing for subsecond time). Please, update your node configuration (all you
|
|
||||||
need is to move specified settings under the `P2P` section and convert
|
|
||||||
time-related settings to `Duration` format).
|
|
||||||
|
|
||||||
Removal of deprecated P2P related application settings is scheduled for May-June
|
|
||||||
2023 (~0.103.0 release).
|
|
||||||
|
|
||||||
## Direct UnlockWallet consensus configuration
|
|
||||||
|
|
||||||
Top-level UnlockWallet section in ApplicationConfiguration was used as an
|
|
||||||
implicit consensus service configuration, now this setting (with Enabled flag)
|
|
||||||
is moved into a section of its own (Consensus). Old configurations are still
|
|
||||||
supported, but this support will eventually be removed.
|
|
||||||
|
|
||||||
Removal of this compatibility code is scheduled for May-June 2023 (~0.103.0
|
|
||||||
release).
|
|
||||||
|
|
||||||
## Node-specific configuration moved from Protocol to Application
|
|
||||||
|
|
||||||
GarbageCollectionPeriod, KeepOnlyLatestState, RemoveUntraceableBlocks,
|
|
||||||
SaveStorageBatch and VerifyBlocks settings were moved from
|
|
||||||
ProtocolConfiguration to ApplicationConfiguration in version 0.100.0. Old
|
|
||||||
configurations are still supported, except for VerifyBlocks which is replaced
|
|
||||||
by SkipBlockVerification with inverted meaning (and hence an inverted default)
|
|
||||||
for security reasons.
|
|
||||||
|
|
||||||
Removal of these options from ProtocolConfiguration is scheduled for May-June
|
|
||||||
2023 (~0.103.0 release).
|
|
||||||
|
|
||||||
## GetPeers RPC server response type changes and RPC client support
|
## GetPeers RPC server response type changes and RPC client support
|
||||||
|
|
||||||
GetPeers RPC command returns a list of Peers where the port type has changed from
|
GetPeers RPC command returns a list of Peers where the port type has changed from
|
||||||
string to uint16 to match C#. The RPC client currently supports unmarshalling both
|
string to uint16 to match C#. The RPC client currently supports unmarshalling both
|
||||||
formats.
|
formats.
|
||||||
|
|
||||||
Removal of Peer unmarshalling with string based ports is scheduled for ~September 2023
|
Removal of Peer unmarshalling with string based ports is scheduled for Jun-Jul 2024
|
||||||
(~0.105.0 release).
|
(~0.107.0 release).
|
||||||
|
|
||||||
## `NEOBalance` from stack item
|
## `NEOBalance` from stack item
|
||||||
|
|
||||||
We check struct items count before convert LastGasPerVote to let RPC client be compatible with
|
We check struct items count before convert LastGasPerVote to let RPC client be compatible with
|
||||||
old versions.
|
old versions.
|
||||||
|
|
||||||
Removal of this compatiblility code is scheduled for Sep-Oct 2023.
|
Removal of this compatiblility code is scheduled for Jun-Jul 2024.
|
||||||
|
|
||||||
## `serv_node_version` Prometheus gauge metric
|
## `serv_node_version` Prometheus gauge metric
|
||||||
|
|
||||||
|
@ -138,4 +48,24 @@ metrics with proper version formatting. `neogo_version` contains NeoGo version
|
||||||
hidden under `version` label and `server_id` contains network server ID hidden
|
hidden under `version` label and `server_id` contains network server ID hidden
|
||||||
under `server_id` label.
|
under `server_id` label.
|
||||||
|
|
||||||
Removal of `serv_node_version` is scheduled for Sep-Oct 2023 (~0.105.0 release).
|
Removal of `serv_node_version` is scheduled for Jun-Jul 2024 (~0.107.0 release).
|
||||||
|
|
||||||
|
## RPC error codes returned by old versions and C#-nodes
|
||||||
|
|
||||||
|
NeoGo retains certain deprecated error codes: `neorpc.ErrCompatGeneric`,
|
||||||
|
`neorpc.ErrCompatNoOpenedWallet`. They returned by nodes not compliant with the
|
||||||
|
neo-project/proposals#156 (NeoGo pre-0.102.0 and all known C# versions).
|
||||||
|
|
||||||
|
Removal of the deprecated RPC error codes is planned for Jun-Jul 2024 (~0.107.0
|
||||||
|
release).
|
||||||
|
|
||||||
|
## Block based web-socket waiter transaction awaiting
|
||||||
|
|
||||||
|
Web-socket RPC based `waiter.EventWaiter` uses `header_of_added_block` notifications
|
||||||
|
subscription to manage transaction awaiting. To support old NeoGo RPC servers
|
||||||
|
(older than 0.105.0) that do not have block headers subscription ability,
|
||||||
|
event-based waiter fallbacks to the old way of block monitoring with
|
||||||
|
`block_added` notifications subscription.
|
||||||
|
|
||||||
|
Removal of stale RPC server compatibility code from `waiter.EventWaiter` is
|
||||||
|
scheduled for Jun-Jul 2024 (~0.107.0 release).
|
|
@ -4,11 +4,12 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/internal/testcli"
|
"github.com/nspcc-dev/neo-go/internal/testcli"
|
||||||
|
"github.com/nspcc-dev/neo-go/internal/versionutil"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/config"
|
"github.com/nspcc-dev/neo-go/pkg/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestCLIVersion(t *testing.T) {
|
func TestCLIVersion(t *testing.T) {
|
||||||
config.Version = "0.90.0-test" // Zero-length version string disables '--version' completely.
|
config.Version = versionutil.TestVersion // Zero-length version string disables '--version' completely.
|
||||||
e := testcli.NewExecutor(t, false)
|
e := testcli.NewExecutor(t, false)
|
||||||
e.Run(t, "neo-go", "--version")
|
e.Run(t, "neo-go", "--version")
|
||||||
e.CheckNextLine(t, "^NeoGo")
|
e.CheckNextLine(t, "^NeoGo")
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package cmdargs
|
package cmdargs
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/hex"
|
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
@ -45,7 +44,7 @@ func TestParseCosigner(t *testing.T) {
|
||||||
Scopes: transaction.CalledByEntry | transaction.CustomContracts,
|
Scopes: transaction.CalledByEntry | transaction.CustomContracts,
|
||||||
AllowedContracts: []util.Uint160{c1, c2},
|
AllowedContracts: []util.Uint160{c1, c2},
|
||||||
},
|
},
|
||||||
acc.StringLE() + ":CustomGroups:" + hex.EncodeToString(priv.PublicKey().Bytes()): {
|
acc.StringLE() + ":CustomGroups:" + priv.PublicKey().StringCompressed(): {
|
||||||
Account: acc,
|
Account: acc,
|
||||||
Scopes: transaction.CustomGroups,
|
Scopes: transaction.CustomGroups,
|
||||||
AllowedGroups: keys.PublicKeys{priv.PublicKey()},
|
AllowedGroups: keys.PublicKeys{priv.PublicKey()},
|
||||||
|
|
|
@ -14,6 +14,7 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/internal/testcli"
|
"github.com/nspcc-dev/neo-go/internal/testcli"
|
||||||
|
"github.com/nspcc-dev/neo-go/internal/versionutil"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/native/nativenames"
|
"github.com/nspcc-dev/neo-go/pkg/core/native/nativenames"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/state"
|
"github.com/nspcc-dev/neo-go/pkg/core/state"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
|
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
|
||||||
|
@ -29,6 +30,9 @@ const (
|
||||||
nftOwnerAddr = "NbrUYaZgyhSkNoRo9ugRyEMdUZxrhkNaWB"
|
nftOwnerAddr = "NbrUYaZgyhSkNoRo9ugRyEMdUZxrhkNaWB"
|
||||||
nftOwnerWallet = "../../examples/my_wallet.json"
|
nftOwnerWallet = "../../examples/my_wallet.json"
|
||||||
nftOwnerPass = "qwerty"
|
nftOwnerPass = "qwerty"
|
||||||
|
|
||||||
|
// Keep contract NEFs consistent between runs.
|
||||||
|
_ = versionutil.TestVersion
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestNEP11Import(t *testing.T) {
|
func TestNEP11Import(t *testing.T) {
|
||||||
|
@ -324,6 +328,14 @@ func TestNEP11_ND_OwnerOf_BalanceOf_Transfer(t *testing.T) {
|
||||||
e.Run(t, append(cmdCheckBalance, "--token", h.StringLE())...)
|
e.Run(t, append(cmdCheckBalance, "--token", h.StringLE())...)
|
||||||
checkBalanceResult(t, nftOwnerAddr, tokenID1)
|
checkBalanceResult(t, nftOwnerAddr, tokenID1)
|
||||||
|
|
||||||
|
// check --await flag
|
||||||
|
tokenID2 := mint(t)
|
||||||
|
e.In.WriteString(nftOwnerPass + "\r")
|
||||||
|
e.Run(t, append(cmdTransfer, "--await", "--id", hex.EncodeToString(tokenID2))...)
|
||||||
|
e.CheckAwaitableTxPersisted(t)
|
||||||
|
e.Run(t, append(cmdCheckBalance, "--token", h.StringLE())...)
|
||||||
|
checkBalanceResult(t, nftOwnerAddr, tokenID1)
|
||||||
|
|
||||||
// transfer: good, to NEP-11-Payable contract, with data
|
// transfer: good, to NEP-11-Payable contract, with data
|
||||||
verifyH := deployVerifyContract(t, e)
|
verifyH := deployVerifyContract(t, e)
|
||||||
cmdTransfer = []string{
|
cmdTransfer = []string{
|
||||||
|
|
|
@ -19,19 +19,34 @@ import (
|
||||||
|
|
||||||
func TestNEP17Balance(t *testing.T) {
|
func TestNEP17Balance(t *testing.T) {
|
||||||
e := testcli.NewExecutor(t, true)
|
e := testcli.NewExecutor(t, true)
|
||||||
|
|
||||||
|
args := []string{
|
||||||
|
"neo-go", "wallet", "nep17", "multitransfer",
|
||||||
|
"--rpc-endpoint", "http://" + e.RPC.Addresses()[0],
|
||||||
|
"--wallet", testcli.ValidatorWallet,
|
||||||
|
"--from", testcli.ValidatorAddr,
|
||||||
|
"GAS:" + testcli.TestWalletMultiAccount1 + ":1",
|
||||||
|
"NEO:" + testcli.TestWalletMultiAccount1 + ":10",
|
||||||
|
"GAS:" + testcli.TestWalletMultiAccount3 + ":3",
|
||||||
|
"--force",
|
||||||
|
}
|
||||||
|
e.In.WriteString("one\r")
|
||||||
|
e.Run(t, args...)
|
||||||
|
e.CheckTxPersisted(t)
|
||||||
|
|
||||||
cmdbalance := []string{"neo-go", "wallet", "nep17", "balance"}
|
cmdbalance := []string{"neo-go", "wallet", "nep17", "balance"}
|
||||||
cmdbase := append(cmdbalance,
|
cmdbase := append(cmdbalance,
|
||||||
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
|
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
|
||||||
"--wallet", testcli.ValidatorWallet,
|
"--wallet", testcli.TestWalletMultiPath,
|
||||||
)
|
)
|
||||||
cmd := append(cmdbase, "--address", testcli.ValidatorAddr)
|
cmd := append(cmdbase, "--address", testcli.TestWalletMultiAccount1)
|
||||||
t.Run("excessive parameters", func(t *testing.T) {
|
t.Run("excessive parameters", func(t *testing.T) {
|
||||||
e.RunWithError(t, append(cmd, "--token", "NEO", "gas")...)
|
e.RunWithError(t, append(cmd, "--token", "NEO", "gas")...)
|
||||||
})
|
})
|
||||||
t.Run("NEO", func(t *testing.T) {
|
t.Run("NEO", func(t *testing.T) {
|
||||||
b, index := e.Chain.GetGoverningTokenBalance(testcli.ValidatorHash)
|
b, index := e.Chain.GetGoverningTokenBalance(testcli.TestWalletMultiAccount1Hash)
|
||||||
checkResult := func(t *testing.T) {
|
checkResult := func(t *testing.T) {
|
||||||
e.CheckNextLine(t, "^\\s*Account\\s+"+testcli.ValidatorAddr)
|
e.CheckNextLine(t, "^\\s*Account\\s+"+testcli.TestWalletMultiAccount1)
|
||||||
e.CheckNextLine(t, "^\\s*NEO:\\s+NeoToken \\("+e.Chain.GoverningTokenHash().StringLE()+"\\)")
|
e.CheckNextLine(t, "^\\s*NEO:\\s+NeoToken \\("+e.Chain.GoverningTokenHash().StringLE()+"\\)")
|
||||||
e.CheckNextLine(t, "^\\s*Amount\\s*:\\s*"+b.String()+"$")
|
e.CheckNextLine(t, "^\\s*Amount\\s*:\\s*"+b.String()+"$")
|
||||||
e.CheckNextLine(t, "^\\s*Updated\\s*:\\s*"+strconv.FormatUint(uint64(index), 10))
|
e.CheckNextLine(t, "^\\s*Updated\\s*:\\s*"+strconv.FormatUint(uint64(index), 10))
|
||||||
|
@ -48,65 +63,53 @@ func TestNEP17Balance(t *testing.T) {
|
||||||
})
|
})
|
||||||
t.Run("GAS", func(t *testing.T) {
|
t.Run("GAS", func(t *testing.T) {
|
||||||
e.Run(t, append(cmd, "--token", "GAS")...)
|
e.Run(t, append(cmd, "--token", "GAS")...)
|
||||||
e.CheckNextLine(t, "^\\s*Account\\s+"+testcli.ValidatorAddr)
|
e.CheckNextLine(t, "^\\s*Account\\s+"+testcli.TestWalletMultiAccount1)
|
||||||
e.CheckNextLine(t, "^\\s*GAS:\\s+GasToken \\("+e.Chain.UtilityTokenHash().StringLE()+"\\)")
|
e.CheckNextLine(t, "^\\s*GAS:\\s+GasToken \\("+e.Chain.UtilityTokenHash().StringLE()+"\\)")
|
||||||
b := e.Chain.GetUtilityTokenBalance(testcli.ValidatorHash)
|
b := e.Chain.GetUtilityTokenBalance(testcli.TestWalletMultiAccount1Hash)
|
||||||
e.CheckNextLine(t, "^\\s*Amount\\s*:\\s*"+fixedn.Fixed8(b.Int64()).String()+"$")
|
e.CheckNextLine(t, "^\\s*Amount\\s*:\\s*"+fixedn.Fixed8(b.Int64()).String()+"$")
|
||||||
})
|
})
|
||||||
t.Run("zero balance of known token", func(t *testing.T) {
|
t.Run("zero balance of known token", func(t *testing.T) {
|
||||||
e.Run(t, append(cmdbase, []string{"--token", "NEO"}...)...)
|
e.Run(t, append(cmdbase, []string{"--token", "NEO", "--address", testcli.TestWalletMultiAccount2}...)...)
|
||||||
addr1, err := address.StringToUint160("Nhfg3TbpwogLvDGVvAvqyThbsHgoSUKwtn")
|
e.CheckNextLine(t, "^Account "+testcli.TestWalletMultiAccount2)
|
||||||
require.NoError(t, err)
|
|
||||||
e.CheckNextLine(t, "^Account "+address.Uint160ToString(addr1))
|
|
||||||
e.CheckNextLine(t, "^\\s*NEO:\\s+NeoToken \\("+e.Chain.GoverningTokenHash().StringLE()+"\\)")
|
e.CheckNextLine(t, "^\\s*NEO:\\s+NeoToken \\("+e.Chain.GoverningTokenHash().StringLE()+"\\)")
|
||||||
e.CheckNextLine(t, "^\\s*Amount\\s*:\\s*"+fixedn.Fixed8(0).String()+"$")
|
e.CheckNextLine(t, "^\\s*Amount\\s*:\\s*"+fixedn.Fixed8(0).String()+"$")
|
||||||
e.CheckNextLine(t, "^\\s*Updated:")
|
e.CheckNextLine(t, "^\\s*Updated:")
|
||||||
e.CheckNextLine(t, "^\\s*$")
|
e.CheckEOF(t)
|
||||||
})
|
})
|
||||||
t.Run("all accounts", func(t *testing.T) {
|
t.Run("all accounts", func(t *testing.T) {
|
||||||
e.Run(t, cmdbase...)
|
e.Run(t, cmdbase...)
|
||||||
addr1, err := address.StringToUint160("Nhfg3TbpwogLvDGVvAvqyThbsHgoSUKwtn")
|
|
||||||
require.NoError(t, err)
|
|
||||||
e.CheckNextLine(t, "^Account "+address.Uint160ToString(addr1))
|
|
||||||
e.CheckNextLine(t, "^\\s*GAS:\\s+GasToken \\("+e.Chain.UtilityTokenHash().StringLE()+"\\)")
|
|
||||||
balance := e.Chain.GetUtilityTokenBalance(addr1)
|
|
||||||
e.CheckNextLine(t, "^\\s*Amount\\s*:\\s*"+fixedn.Fixed8(balance.Int64()).String()+"$")
|
|
||||||
e.CheckNextLine(t, "^\\s*Updated:")
|
|
||||||
e.CheckNextLine(t, "^\\s*$")
|
|
||||||
|
|
||||||
addr2, err := address.StringToUint160("NVTiAjNgagDkTr5HTzDmQP9kPwPHN5BgVq")
|
e.CheckNextLine(t, "^Account "+testcli.TestWalletMultiAccount1)
|
||||||
require.NoError(t, err)
|
|
||||||
e.CheckNextLine(t, "^Account "+address.Uint160ToString(addr2))
|
|
||||||
e.CheckNextLine(t, "^\\s*$")
|
|
||||||
|
|
||||||
addr3, err := address.StringToUint160("NfgHwwTi3wHAS8aFAN243C5vGbkYDpqLHP")
|
|
||||||
require.NoError(t, err)
|
|
||||||
e.CheckNextLine(t, "^Account "+address.Uint160ToString(addr3))
|
|
||||||
// The order of assets is undefined.
|
// The order of assets is undefined.
|
||||||
for i := 0; i < 2; i++ {
|
for i := 0; i < 2; i++ {
|
||||||
line := e.GetNextLine(t)
|
line := e.GetNextLine(t)
|
||||||
if strings.Contains(line, "GAS") {
|
if strings.Contains(line, "GAS") {
|
||||||
e.CheckLine(t, line, "^\\s*GAS:\\s+GasToken \\("+e.Chain.UtilityTokenHash().StringLE()+"\\)")
|
e.CheckLine(t, line, "^\\s*GAS:\\s+GasToken \\("+e.Chain.UtilityTokenHash().StringLE()+"\\)")
|
||||||
balance = e.Chain.GetUtilityTokenBalance(addr3)
|
balance := e.Chain.GetUtilityTokenBalance(testcli.TestWalletMultiAccount1Hash)
|
||||||
e.CheckNextLine(t, "^\\s*Amount\\s*:\\s*"+fixedn.Fixed8(balance.Int64()).String()+"$")
|
e.CheckNextLine(t, "^\\s*Amount\\s*:\\s*"+fixedn.Fixed8(balance.Int64()).String()+"$")
|
||||||
e.CheckNextLine(t, "^\\s*Updated:")
|
e.CheckNextLine(t, "^\\s*Updated:")
|
||||||
} else {
|
} else {
|
||||||
balance, index := e.Chain.GetGoverningTokenBalance(testcli.ValidatorHash)
|
balance, index := e.Chain.GetGoverningTokenBalance(testcli.TestWalletMultiAccount1Hash)
|
||||||
e.CheckLine(t, line, "^\\s*NEO:\\s+NeoToken \\("+e.Chain.GoverningTokenHash().StringLE()+"\\)")
|
e.CheckLine(t, line, "^\\s*NEO:\\s+NeoToken \\("+e.Chain.GoverningTokenHash().StringLE()+"\\)")
|
||||||
e.CheckNextLine(t, "^\\s*Amount\\s*:\\s*"+balance.String()+"$")
|
e.CheckNextLine(t, "^\\s*Amount\\s*:\\s*"+balance.String()+"$")
|
||||||
e.CheckNextLine(t, "^\\s*Updated\\s*:\\s*"+strconv.FormatUint(uint64(index), 10))
|
e.CheckNextLine(t, "^\\s*Updated\\s*:\\s*"+strconv.FormatUint(uint64(index), 10))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
e.CheckNextLine(t, "^\\s*$")
|
e.CheckNextLine(t, "^\\s*$")
|
||||||
addr4, err := address.StringToUint160("NiFxRcC5Anz9pmqQyMHh5vamBUZDbRRRzA") // deployed verify.go contract
|
|
||||||
require.NoError(t, err)
|
e.CheckNextLine(t, "^Account "+testcli.TestWalletMultiAccount2)
|
||||||
e.CheckNextLine(t, "^Account "+address.Uint160ToString(addr4))
|
e.CheckNextLine(t, "^\\s*$")
|
||||||
|
|
||||||
|
e.CheckNextLine(t, "^Account "+testcli.TestWalletMultiAccount3)
|
||||||
|
e.CheckNextLine(t, "^\\s*GAS:\\s+GasToken \\("+e.Chain.UtilityTokenHash().StringLE()+"\\)")
|
||||||
|
balance := e.Chain.GetUtilityTokenBalance(testcli.TestWalletMultiAccount3Hash)
|
||||||
|
e.CheckNextLine(t, "^\\s*Amount\\s*:\\s*"+fixedn.Fixed8(balance.Int64()).String()+"$")
|
||||||
|
e.CheckNextLine(t, "^\\s*Updated:")
|
||||||
e.CheckEOF(t)
|
e.CheckEOF(t)
|
||||||
})
|
})
|
||||||
t.Run("Bad token", func(t *testing.T) {
|
t.Run("Bad token", func(t *testing.T) {
|
||||||
e.Run(t, append(cmd, "--token", "kek")...)
|
e.Run(t, append(cmd, "--token", "kek")...)
|
||||||
e.CheckNextLine(t, "^\\s*Account\\s+"+testcli.ValidatorAddr)
|
e.CheckNextLine(t, "^\\s*Account\\s+"+testcli.TestWalletMultiAccount1)
|
||||||
e.CheckNextLine(t, `^\s*Can't find data for "kek" token\s*`)
|
e.CheckNextLine(t, `^\s*Can't find data for "kek" token\s*`)
|
||||||
e.CheckEOF(t)
|
e.CheckEOF(t)
|
||||||
})
|
})
|
||||||
|
@ -223,12 +226,19 @@ func TestNEP17Transfer(t *testing.T) {
|
||||||
"neo-go", "wallet", "nep17", "transfer",
|
"neo-go", "wallet", "nep17", "transfer",
|
||||||
"--rpc-endpoint", "http://" + e.RPC.Addresses()[0],
|
"--rpc-endpoint", "http://" + e.RPC.Addresses()[0],
|
||||||
"--wallet", testcli.ValidatorWallet,
|
"--wallet", testcli.ValidatorWallet,
|
||||||
"--to", address.Uint160ToString(e.Chain.GetNotaryContractScriptHash()),
|
|
||||||
"--token", "GAS",
|
"--token", "GAS",
|
||||||
"--amount", "1",
|
"--amount", "1",
|
||||||
"--from", testcli.ValidatorAddr,
|
|
||||||
"--force",
|
"--force",
|
||||||
"[", testcli.ValidatorAddr, strconv.Itoa(int(validTil)), "]"}
|
"--from", testcli.ValidatorAddr}
|
||||||
|
|
||||||
|
t.Run("with await", func(t *testing.T) {
|
||||||
|
e.In.WriteString("one\r")
|
||||||
|
e.Run(t, append(cmd, "--to", nftOwnerAddr, "--await")...)
|
||||||
|
e.CheckAwaitableTxPersisted(t)
|
||||||
|
})
|
||||||
|
|
||||||
|
cmd = append(cmd, "--to", address.Uint160ToString(e.Chain.GetNotaryContractScriptHash()),
|
||||||
|
"[", testcli.ValidatorAddr, strconv.Itoa(int(validTil)), "]")
|
||||||
|
|
||||||
t.Run("with data", func(t *testing.T) {
|
t.Run("with data", func(t *testing.T) {
|
||||||
e.In.WriteString("one\r")
|
e.In.WriteString("one\r")
|
||||||
|
|
|
@ -11,27 +11,50 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/nspcc-dev/neo-go/cli/flags"
|
||||||
|
"github.com/nspcc-dev/neo-go/cli/input"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/config"
|
"github.com/nspcc-dev/neo-go/pkg/config"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/config/netmode"
|
"github.com/nspcc-dev/neo-go/pkg/config/netmode"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/io"
|
"github.com/nspcc-dev/neo-go/pkg/io"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/rpcclient"
|
"github.com/nspcc-dev/neo-go/pkg/rpcclient"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/rpcclient/actor"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/rpcclient/invoker"
|
"github.com/nspcc-dev/neo-go/pkg/rpcclient/invoker"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
||||||
"github.com/urfave/cli"
|
"github.com/urfave/cli"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
"go.uber.org/zap/zapcore"
|
"go.uber.org/zap/zapcore"
|
||||||
|
"golang.org/x/term"
|
||||||
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
// DefaultTimeout is the default timeout used for RPC requests.
|
const (
|
||||||
const DefaultTimeout = 10 * time.Second
|
// DefaultTimeout is the default timeout used for RPC requests.
|
||||||
|
DefaultTimeout = 10 * time.Second
|
||||||
|
// DefaultAwaitableTimeout is the default timeout used for RPC requests that
|
||||||
|
// require transaction awaiting. It is set to the approximate time of three
|
||||||
|
// Neo N3 mainnet blocks accepting.
|
||||||
|
DefaultAwaitableTimeout = 3 * 15 * time.Second
|
||||||
|
)
|
||||||
|
|
||||||
// RPCEndpointFlag is a long flag name for an RPC endpoint. It can be used to
|
// RPCEndpointFlag is a long flag name for an RPC endpoint. It can be used to
|
||||||
// check for flag presence in the context.
|
// check for flag presence in the context.
|
||||||
const RPCEndpointFlag = "rpc-endpoint"
|
const RPCEndpointFlag = "rpc-endpoint"
|
||||||
|
|
||||||
|
// Wallet is a set of flags used for wallet operations.
|
||||||
|
var Wallet = []cli.Flag{cli.StringFlag{
|
||||||
|
Name: "wallet, w",
|
||||||
|
Usage: "wallet to use to get the key for transaction signing; conflicts with --wallet-config flag",
|
||||||
|
}, cli.StringFlag{
|
||||||
|
Name: "wallet-config",
|
||||||
|
Usage: "path to wallet config to use to get the key for transaction signing; conflicts with --wallet flag"},
|
||||||
|
}
|
||||||
|
|
||||||
// Network is a set of flags for choosing the network to operate on
|
// Network is a set of flags for choosing the network to operate on
|
||||||
// (privnet/mainnet/testnet).
|
// (privnet/mainnet/testnet).
|
||||||
var Network = []cli.Flag{
|
var Network = []cli.Flag{
|
||||||
|
@ -73,6 +96,13 @@ var ConfigFile = cli.StringFlag{
|
||||||
Usage: "path to the node configuration file (overrides --config-path option)",
|
Usage: "path to the node configuration file (overrides --config-path option)",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RelativePath is a flag for commands that use node configuration and provide
|
||||||
|
// a prefix to all relative paths in config files.
|
||||||
|
var RelativePath = cli.StringFlag{
|
||||||
|
Name: "relative-path",
|
||||||
|
Usage: "a prefix to all relative paths in the node configuration file",
|
||||||
|
}
|
||||||
|
|
||||||
// Debug is a flag for commands that allow node in debug mode usage.
|
// Debug is a flag for commands that allow node in debug mode usage.
|
||||||
var Debug = cli.BoolFlag{
|
var Debug = cli.BoolFlag{
|
||||||
Name: "debug, d",
|
Name: "debug, d",
|
||||||
|
@ -81,6 +111,8 @@ var Debug = cli.BoolFlag{
|
||||||
|
|
||||||
var errNoEndpoint = errors.New("no RPC endpoint specified, use option '--" + RPCEndpointFlag + "' or '-r'")
|
var errNoEndpoint = errors.New("no RPC endpoint specified, use option '--" + RPCEndpointFlag + "' or '-r'")
|
||||||
var errInvalidHistoric = errors.New("invalid 'historic' parameter, neither a block number, nor a block/state hash")
|
var errInvalidHistoric = errors.New("invalid 'historic' parameter, neither a block number, nor a block/state hash")
|
||||||
|
var errNoWallet = errors.New("no wallet parameter found, specify it with the '--wallet' or '-w' flag or specify wallet config file with the '--wallet-config' flag")
|
||||||
|
var errConflictingWalletFlags = errors.New("--wallet flag conflicts with --wallet-config flag, please, provide one of them to specify wallet location")
|
||||||
|
|
||||||
// GetNetwork examines Context's flags and returns the appropriate network. It
|
// GetNetwork examines Context's flags and returns the appropriate network. It
|
||||||
// defaults to PrivNet if no flags are given.
|
// defaults to PrivNet if no flags are given.
|
||||||
|
@ -104,6 +136,9 @@ func GetTimeoutContext(ctx *cli.Context) (context.Context, func()) {
|
||||||
if dur == 0 {
|
if dur == 0 {
|
||||||
dur = DefaultTimeout
|
dur = DefaultTimeout
|
||||||
}
|
}
|
||||||
|
if !ctx.IsSet("timeout") && ctx.Bool("await") {
|
||||||
|
dur = DefaultAwaitableTimeout
|
||||||
|
}
|
||||||
return context.WithTimeout(context.Background(), dur)
|
return context.WithTimeout(context.Background(), dur)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -159,15 +194,18 @@ func GetRPCWithInvoker(gctx context.Context, ctx *cli.Context, signers []transac
|
||||||
// GetConfigFromContext looks at the path and the mode flags in the given config and
|
// GetConfigFromContext looks at the path and the mode flags in the given config and
|
||||||
// returns an appropriate config.
|
// returns an appropriate config.
|
||||||
func GetConfigFromContext(ctx *cli.Context) (config.Config, error) {
|
func GetConfigFromContext(ctx *cli.Context) (config.Config, error) {
|
||||||
var configFile = ctx.String("config-file")
|
var (
|
||||||
|
configFile = ctx.String("config-file")
|
||||||
|
relativePath = ctx.String("relative-path")
|
||||||
|
)
|
||||||
if len(configFile) != 0 {
|
if len(configFile) != 0 {
|
||||||
return config.LoadFile(configFile)
|
return config.LoadFile(configFile, relativePath)
|
||||||
}
|
}
|
||||||
var configPath = "./config"
|
var configPath = "./config"
|
||||||
if argCp := ctx.String("config-path"); argCp != "" {
|
if argCp := ctx.String("config-path"); argCp != "" {
|
||||||
configPath = argCp
|
configPath = argCp
|
||||||
}
|
}
|
||||||
return config.Load(configPath, GetNetwork(ctx))
|
return config.Load(configPath, GetNetwork(ctx), relativePath)
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -182,6 +220,7 @@ var (
|
||||||
// If logPath is configured -- function creates a dir and a file for logging.
|
// If logPath is configured -- function creates a dir and a file for logging.
|
||||||
// If logPath is configured on Windows -- function returns closer to be
|
// If logPath is configured on Windows -- function returns closer to be
|
||||||
// able to close sink for the opened log output file.
|
// able to close sink for the opened log output file.
|
||||||
|
// If the program is run in TTY then logger adds timestamp to its entries.
|
||||||
func HandleLoggingParams(debug bool, cfg config.ApplicationConfiguration) (*zap.Logger, *zap.AtomicLevel, func() error, error) {
|
func HandleLoggingParams(debug bool, cfg config.ApplicationConfiguration) (*zap.Logger, *zap.AtomicLevel, func() error, error) {
|
||||||
var (
|
var (
|
||||||
level = zapcore.InfoLevel
|
level = zapcore.InfoLevel
|
||||||
|
@ -202,7 +241,11 @@ func HandleLoggingParams(debug bool, cfg config.ApplicationConfiguration) (*zap.
|
||||||
cc.DisableStacktrace = true
|
cc.DisableStacktrace = true
|
||||||
cc.EncoderConfig.EncodeDuration = zapcore.StringDurationEncoder
|
cc.EncoderConfig.EncodeDuration = zapcore.StringDurationEncoder
|
||||||
cc.EncoderConfig.EncodeLevel = zapcore.CapitalLevelEncoder
|
cc.EncoderConfig.EncodeLevel = zapcore.CapitalLevelEncoder
|
||||||
|
if term.IsTerminal(int(os.Stdout.Fd())) {
|
||||||
cc.EncoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder
|
cc.EncoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder
|
||||||
|
} else {
|
||||||
|
cc.EncoderConfig.EncodeTime = func(t time.Time, encoder zapcore.PrimitiveArrayEncoder) {}
|
||||||
|
}
|
||||||
cc.Encoding = "console"
|
cc.Encoding = "console"
|
||||||
cc.Level = zap.NewAtomicLevelAt(level)
|
cc.Level = zap.NewAtomicLevelAt(level)
|
||||||
cc.Sampling = nil
|
cc.Sampling = nil
|
||||||
|
@ -260,3 +303,108 @@ func HandleLoggingParams(debug bool, cfg config.ApplicationConfiguration) (*zap.
|
||||||
log, err := cc.Build()
|
log, err := cc.Build()
|
||||||
return log, &cc.Level, _winfileSinkCloser, err
|
return log, &cc.Level, _winfileSinkCloser, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetRPCWithActor returns an RPC client instance and Actor instance for the given context.
|
||||||
|
func GetRPCWithActor(gctx context.Context, ctx *cli.Context, signers []actor.SignerAccount) (*rpcclient.Client, *actor.Actor, cli.ExitCoder) {
|
||||||
|
c, err := GetRPCClient(gctx, ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
a, actorErr := actor.New(c, signers)
|
||||||
|
if actorErr != nil {
|
||||||
|
c.Close()
|
||||||
|
return nil, nil, cli.NewExitError(fmt.Errorf("failed to create Actor: %w", actorErr), 1)
|
||||||
|
}
|
||||||
|
return c, a, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAccFromContext returns account and wallet from context. If address is not set, default address is used.
|
||||||
|
func GetAccFromContext(ctx *cli.Context) (*wallet.Account, *wallet.Wallet, error) {
|
||||||
|
var addr util.Uint160
|
||||||
|
|
||||||
|
wPath := ctx.String("wallet")
|
||||||
|
walletConfigPath := ctx.String("wallet-config")
|
||||||
|
if len(wPath) != 0 && len(walletConfigPath) != 0 {
|
||||||
|
return nil, nil, errConflictingWalletFlags
|
||||||
|
}
|
||||||
|
if len(wPath) == 0 && len(walletConfigPath) == 0 {
|
||||||
|
return nil, nil, errNoWallet
|
||||||
|
}
|
||||||
|
var pass *string
|
||||||
|
if len(walletConfigPath) != 0 {
|
||||||
|
cfg, err := ReadWalletConfig(walletConfigPath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
wPath = cfg.Path
|
||||||
|
pass = &cfg.Password
|
||||||
|
}
|
||||||
|
|
||||||
|
wall, err := wallet.NewWalletFromFile(wPath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
addrFlag := ctx.Generic("address").(*flags.Address)
|
||||||
|
if addrFlag.IsSet {
|
||||||
|
addr = addrFlag.Uint160()
|
||||||
|
} else {
|
||||||
|
addr = wall.GetChangeAddress()
|
||||||
|
if addr.Equals(util.Uint160{}) {
|
||||||
|
return nil, wall, errors.New("can't get default address")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
acc, err := GetUnlockedAccount(wall, addr, pass)
|
||||||
|
return acc, wall, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetUnlockedAccount returns account from wallet, address and uses pass to unlock specified account if given.
|
||||||
|
// If the password is not given, then it is requested from user.
|
||||||
|
func GetUnlockedAccount(wall *wallet.Wallet, addr util.Uint160, pass *string) (*wallet.Account, error) {
|
||||||
|
acc := wall.GetAccount(addr)
|
||||||
|
if acc == nil {
|
||||||
|
return nil, fmt.Errorf("wallet contains no account for '%s'", address.Uint160ToString(addr))
|
||||||
|
}
|
||||||
|
|
||||||
|
if acc.CanSign() || acc.EncryptedWIF == "" {
|
||||||
|
return acc, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if pass == nil {
|
||||||
|
rawPass, err := input.ReadPassword(
|
||||||
|
fmt.Sprintf("Enter account %s password > ", address.Uint160ToString(addr)))
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Error reading password: %w", err)
|
||||||
|
}
|
||||||
|
trimmed := strings.TrimRight(string(rawPass), "\n")
|
||||||
|
pass = &trimmed
|
||||||
|
}
|
||||||
|
err := acc.Decrypt(*pass, wall.Scrypt)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return acc, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadWalletConfig reads wallet config from the given path.
|
||||||
|
func ReadWalletConfig(configPath string) (*config.Wallet, error) {
|
||||||
|
file, err := os.Open(configPath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
configData, err := os.ReadFile(configPath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("unable to read wallet config: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg := &config.Wallet{}
|
||||||
|
|
||||||
|
err = yaml.Unmarshal(configData, &cfg)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to unmarshal wallet config YAML: %w", err)
|
||||||
|
}
|
||||||
|
return cfg, nil
|
||||||
|
}
|
||||||
|
|
|
@ -3,7 +3,6 @@ package query
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/hex"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
@ -111,7 +110,10 @@ func queryTx(ctx *cli.Context) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DumpApplicationLog(ctx, res, &txOut.Transaction, &txOut.TransactionMetadata, ctx.Bool("verbose"))
|
err = DumpApplicationLog(ctx, res, &txOut.Transaction, &txOut.TransactionMetadata, ctx.Bool("verbose"))
|
||||||
|
if err != nil {
|
||||||
|
return cli.NewExitError(err, 1)
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,47 +122,49 @@ func DumpApplicationLog(
|
||||||
res *result.ApplicationLog,
|
res *result.ApplicationLog,
|
||||||
tx *transaction.Transaction,
|
tx *transaction.Transaction,
|
||||||
txMeta *result.TransactionMetadata,
|
txMeta *result.TransactionMetadata,
|
||||||
verbose bool) {
|
verbose bool) error {
|
||||||
buf := bytes.NewBuffer(nil)
|
var buf []byte
|
||||||
|
|
||||||
// Ignore the errors below because `Write` to buffer doesn't return error.
|
buf = fmt.Appendf(buf, "Hash:\t%s\n", tx.Hash().StringLE())
|
||||||
tw := tabwriter.NewWriter(buf, 0, 4, 4, '\t', 0)
|
buf = fmt.Appendf(buf, "OnChain:\t%t\n", res != nil)
|
||||||
_, _ = tw.Write([]byte("Hash:\t" + tx.Hash().StringLE() + "\n"))
|
|
||||||
_, _ = tw.Write([]byte(fmt.Sprintf("OnChain:\t%t\n", res != nil)))
|
|
||||||
if res == nil {
|
if res == nil {
|
||||||
_, _ = tw.Write([]byte("ValidUntil:\t" + strconv.FormatUint(uint64(tx.ValidUntilBlock), 10) + "\n"))
|
buf = fmt.Appendf(buf, "ValidUntil:\t%s\n", strconv.FormatUint(uint64(tx.ValidUntilBlock), 10))
|
||||||
} else {
|
} else {
|
||||||
if txMeta != nil {
|
if txMeta != nil {
|
||||||
_, _ = tw.Write([]byte("BlockHash:\t" + txMeta.Blockhash.StringLE() + "\n"))
|
buf = fmt.Appendf(buf, "BlockHash:\t%s\n", txMeta.Blockhash.StringLE())
|
||||||
}
|
}
|
||||||
if len(res.Executions) != 1 {
|
if len(res.Executions) != 1 {
|
||||||
_, _ = tw.Write([]byte("Success:\tunknown (no execution data)\n"))
|
buf = fmt.Appendf(buf, "Success:\tunknown (no execution data)\n")
|
||||||
} else {
|
} else {
|
||||||
_, _ = tw.Write([]byte(fmt.Sprintf("Success:\t%t\n", res.Executions[0].VMState == vmstate.Halt)))
|
buf = fmt.Appendf(buf, "Success:\t%t\n", res.Executions[0].VMState == vmstate.Halt)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if verbose {
|
if verbose {
|
||||||
for _, sig := range tx.Signers {
|
for _, sig := range tx.Signers {
|
||||||
_, _ = tw.Write([]byte(fmt.Sprintf("Signer:\t%s (%s)",
|
buf = fmt.Appendf(buf, "Signer:\t%s (%s)\n", address.Uint160ToString(sig.Account), sig.Scopes)
|
||||||
address.Uint160ToString(sig.Account),
|
|
||||||
sig.Scopes) + "\n"))
|
|
||||||
}
|
}
|
||||||
_, _ = tw.Write([]byte("SystemFee:\t" + fixedn.Fixed8(tx.SystemFee).String() + " GAS\n"))
|
buf = fmt.Appendf(buf, "SystemFee:\t%s GAS\n", fixedn.Fixed8(tx.SystemFee).String())
|
||||||
_, _ = tw.Write([]byte("NetworkFee:\t" + fixedn.Fixed8(tx.NetworkFee).String() + " GAS\n"))
|
buf = fmt.Appendf(buf, "NetworkFee:\t%s GAS\n", fixedn.Fixed8(tx.NetworkFee).String())
|
||||||
_, _ = tw.Write([]byte("Script:\t" + base64.StdEncoding.EncodeToString(tx.Script) + "\n"))
|
buf = fmt.Appendf(buf, "Script:\t%s\n", base64.StdEncoding.EncodeToString(tx.Script))
|
||||||
v := vm.New()
|
v := vm.New()
|
||||||
v.Load(tx.Script)
|
v.Load(tx.Script)
|
||||||
v.PrintOps(tw)
|
opts := bytes.NewBuffer(nil)
|
||||||
|
v.PrintOps(opts)
|
||||||
|
buf = append(buf, opts.Bytes()...)
|
||||||
if res != nil {
|
if res != nil {
|
||||||
for _, e := range res.Executions {
|
for _, e := range res.Executions {
|
||||||
if e.VMState != vmstate.Halt {
|
if e.VMState != vmstate.Halt {
|
||||||
_, _ = tw.Write([]byte("Exception:\t" + e.FaultException + "\n"))
|
buf = fmt.Appendf(buf, "Exception:\t%s\n", e.FaultException)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ = tw.Flush()
|
tw := tabwriter.NewWriter(ctx.App.Writer, 0, 4, 4, '\t', 0)
|
||||||
fmt.Fprint(ctx.App.Writer, buf.String())
|
_, err := tw.Write(buf)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return tw.Flush()
|
||||||
}
|
}
|
||||||
|
|
||||||
func queryCandidates(ctx *cli.Context) error {
|
func queryCandidates(ctx *cli.Context) error {
|
||||||
|
@ -196,15 +200,17 @@ func queryCandidates(ctx *cli.Context) error {
|
||||||
}
|
}
|
||||||
return vals[i].PublicKey.Cmp(&vals[j].PublicKey) == -1
|
return vals[i].PublicKey.Cmp(&vals[j].PublicKey) == -1
|
||||||
})
|
})
|
||||||
buf := bytes.NewBuffer(nil)
|
var res []byte
|
||||||
tw := tabwriter.NewWriter(buf, 0, 2, 2, ' ', 0)
|
res = fmt.Appendf(res, "Key\tVotes\tCommittee\tConsensus\n")
|
||||||
_, _ = tw.Write([]byte("Key\tVotes\tCommittee\tConsensus\n"))
|
|
||||||
for _, val := range vals {
|
for _, val := range vals {
|
||||||
_, _ = tw.Write([]byte(fmt.Sprintf("%s\t%d\t%t\t%t\n", hex.EncodeToString(val.PublicKey.Bytes()), val.Votes, comm.Contains(&val.PublicKey), val.Active)))
|
res = fmt.Appendf(res, "%s\t%d\t%t\t%t\n", val.PublicKey.StringCompressed(), val.Votes, comm.Contains(&val.PublicKey), val.Active)
|
||||||
}
|
}
|
||||||
_ = tw.Flush()
|
tw := tabwriter.NewWriter(ctx.App.Writer, 0, 2, 2, ' ', 0)
|
||||||
fmt.Fprint(ctx.App.Writer, buf.String())
|
_, err = tw.Write(res)
|
||||||
return nil
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return tw.Flush()
|
||||||
}
|
}
|
||||||
|
|
||||||
func queryCommittee(ctx *cli.Context) error {
|
func queryCommittee(ctx *cli.Context) error {
|
||||||
|
@ -228,7 +234,7 @@ func queryCommittee(ctx *cli.Context) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, k := range comm {
|
for _, k := range comm {
|
||||||
fmt.Fprintln(ctx.App.Writer, hex.EncodeToString(k.Bytes()))
|
fmt.Fprintln(ctx.App.Writer, k.StringCompressed())
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -299,7 +305,7 @@ func queryVoter(ctx *cli.Context) error {
|
||||||
}
|
}
|
||||||
voted := "null"
|
voted := "null"
|
||||||
if st.VoteTo != nil {
|
if st.VoteTo != nil {
|
||||||
voted = fmt.Sprintf("%s (%s)", hex.EncodeToString(st.VoteTo.Bytes()), address.Uint160ToString(st.VoteTo.GetScriptHash()))
|
voted = fmt.Sprintf("%s (%s)", st.VoteTo.StringCompressed(), address.Uint160ToString(st.VoteTo.GetScriptHash()))
|
||||||
}
|
}
|
||||||
fmt.Fprintf(ctx.App.Writer, "\tVoted: %s\n", voted)
|
fmt.Fprintf(ctx.App.Writer, "\tVoted: %s\n", voted)
|
||||||
fmt.Fprintf(ctx.App.Writer, "\tAmount : %s\n", fixedn.ToString(&st.Balance, int(dec)))
|
fmt.Fprintf(ctx.App.Writer, "\tAmount : %s\n", fixedn.ToString(&st.Balance, int(dec)))
|
||||||
|
|
|
@ -77,7 +77,8 @@ func TestServerStart(t *testing.T) {
|
||||||
})
|
})
|
||||||
t.Run("invalid consensus config", func(t *testing.T) {
|
t.Run("invalid consensus config", func(t *testing.T) {
|
||||||
saveCfg(t, func(cfg *config.Config) {
|
saveCfg(t, func(cfg *config.Config) {
|
||||||
cfg.ApplicationConfiguration.UnlockWallet.Path = "bad_consensus_wallet.json"
|
cfg.ApplicationConfiguration.Consensus.Enabled = true
|
||||||
|
cfg.ApplicationConfiguration.Consensus.UnlockWallet.Path = "bad_consensus_wallet.json"
|
||||||
})
|
})
|
||||||
e.RunWithError(t, baseCmd...)
|
e.RunWithError(t, baseCmd...)
|
||||||
})
|
})
|
||||||
|
|
|
@ -34,7 +34,7 @@ import (
|
||||||
|
|
||||||
// NewCommands returns 'node' command.
|
// NewCommands returns 'node' command.
|
||||||
func NewCommands() []cli.Command {
|
func NewCommands() []cli.Command {
|
||||||
cfgFlags := []cli.Flag{options.Config, options.ConfigFile}
|
cfgFlags := []cli.Flag{options.Config, options.ConfigFile, options.RelativePath}
|
||||||
cfgFlags = append(cfgFlags, options.Network...)
|
cfgFlags = append(cfgFlags, options.Network...)
|
||||||
var cfgWithCountFlags = make([]cli.Flag, len(cfgFlags))
|
var cfgWithCountFlags = make([]cli.Flag, len(cfgFlags))
|
||||||
copy(cfgWithCountFlags, cfgFlags)
|
copy(cfgWithCountFlags, cfgFlags)
|
||||||
|
@ -136,7 +136,6 @@ func initBCWithMetrics(cfg config.Config, log *zap.Logger) (*core.Blockchain, *m
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, nil, cli.NewExitError(err, 1)
|
return nil, nil, nil, cli.NewExitError(err, 1)
|
||||||
}
|
}
|
||||||
configureAddresses(&cfg.ApplicationConfiguration)
|
|
||||||
prometheus := metrics.NewPrometheusService(cfg.ApplicationConfiguration.Prometheus, log)
|
prometheus := metrics.NewPrometheusService(cfg.ApplicationConfiguration.Prometheus, log)
|
||||||
pprof := metrics.NewPprofService(cfg.ApplicationConfiguration.Pprof, log)
|
pprof := metrics.NewPprofService(cfg.ApplicationConfiguration.Pprof, log)
|
||||||
|
|
||||||
|
@ -359,7 +358,14 @@ func resetDB(ctx *cli.Context) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func mkOracle(config config.OracleConfiguration, magic netmode.Magic, chain *core.Blockchain, serv *network.Server, log *zap.Logger) (*oracle.Oracle, error) {
|
// oracleService is an interface representing Oracle service with network.Service
|
||||||
|
// capabilities and ability to submit oracle responses.
|
||||||
|
type oracleService interface {
|
||||||
|
rpcsrv.OracleHandler
|
||||||
|
network.Service
|
||||||
|
}
|
||||||
|
|
||||||
|
func mkOracle(config config.OracleConfiguration, magic netmode.Magic, chain *core.Blockchain, serv *network.Server, log *zap.Logger) (oracleService, error) {
|
||||||
if !config.Enabled {
|
if !config.Enabled {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
@ -416,7 +422,7 @@ func mkP2PNotary(config config.P2PNotary, chain *core.Blockchain, serv *network.
|
||||||
}
|
}
|
||||||
n, err := notary.NewNotary(cfg, serv.Net, serv.GetNotaryPool(), func(tx *transaction.Transaction) error {
|
n, err := notary.NewNotary(cfg, serv.Net, serv.GetNotaryPool(), func(tx *transaction.Transaction) error {
|
||||||
err := serv.RelayTxn(tx)
|
err := serv.RelayTxn(tx)
|
||||||
if err != nil && !errors.Is(err, core.ErrAlreadyExists) {
|
if err != nil && !errors.Is(err, core.ErrAlreadyExists) && !errors.Is(err, core.ErrAlreadyInPool) {
|
||||||
return fmt.Errorf("can't relay completed notary transaction: hash %s, error: %w", tx.Hash().StringLE(), err)
|
return fmt.Errorf("can't relay completed notary transaction: hash %s, error: %w", tx.Hash().StringLE(), err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
@ -492,7 +498,7 @@ func startServer(ctx *cli.Context) error {
|
||||||
rpcServer := rpcsrv.New(chain, cfg.ApplicationConfiguration.RPC, serv, oracleSrv, log, errChan)
|
rpcServer := rpcsrv.New(chain, cfg.ApplicationConfiguration.RPC, serv, oracleSrv, log, errChan)
|
||||||
serv.AddService(&rpcServer)
|
serv.AddService(&rpcServer)
|
||||||
|
|
||||||
go serv.Start()
|
serv.Start()
|
||||||
if !cfg.ApplicationConfiguration.RPC.StartWhenSynchronized {
|
if !cfg.ApplicationConfiguration.RPC.StartWhenSynchronized {
|
||||||
// Run RPC server in a separate routine. This is necessary to avoid a potential
|
// Run RPC server in a separate routine. This is necessary to avoid a potential
|
||||||
// deadlock: Start() can write errors to errChan which is not yet read in the
|
// deadlock: Start() can write errors to errChan which is not yet read in the
|
||||||
|
@ -540,7 +546,6 @@ Main:
|
||||||
break // Continue working.
|
break // Continue working.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
configureAddresses(&cfgnew.ApplicationConfiguration)
|
|
||||||
switch sig {
|
switch sig {
|
||||||
case sighup:
|
case sighup:
|
||||||
if newLogLevel != zapcore.InvalidLevel {
|
if newLogLevel != zapcore.InvalidLevel {
|
||||||
|
@ -641,24 +646,6 @@ Main:
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// configureAddresses sets up addresses for RPC, Prometheus and Pprof depending from the provided config.
|
|
||||||
// In case RPC or Prometheus or Pprof Address provided each of them will use it.
|
|
||||||
// In case global Address (of the node) provided and RPC/Prometheus/Pprof don't have configured addresses they will
|
|
||||||
// use global one. So Node and RPC and Prometheus and Pprof will run on one address.
|
|
||||||
func configureAddresses(cfg *config.ApplicationConfiguration) {
|
|
||||||
if cfg.Address != nil && *cfg.Address != "" { //nolint:staticcheck // SA1019: cfg.Address is deprecated
|
|
||||||
if cfg.RPC.Address == nil || *cfg.RPC.Address == "" { //nolint:staticcheck // SA1019: cfg.RPC.Address is deprecated
|
|
||||||
cfg.RPC.Address = cfg.Address //nolint:staticcheck // SA1019: cfg.RPC.Address is deprecated
|
|
||||||
}
|
|
||||||
if cfg.Prometheus.Address == nil || *cfg.Prometheus.Address == "" { //nolint:staticcheck // SA1019: cfg.Prometheus.Address is deprecated
|
|
||||||
cfg.Prometheus.Address = cfg.Address //nolint:staticcheck // SA1019: cfg.Prometheus.Address is deprecated
|
|
||||||
}
|
|
||||||
if cfg.Pprof.Address == nil || *cfg.Pprof.Address == "" { //nolint:staticcheck // SA1019: cfg.Pprof.Address is deprecated
|
|
||||||
cfg.Pprof.Address = cfg.Address //nolint:staticcheck // SA1019: cfg.Pprof.Address is deprecated
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// initBlockChain initializes BlockChain with preselected DB.
|
// initBlockChain initializes BlockChain with preselected DB.
|
||||||
func initBlockChain(cfg config.Config, log *zap.Logger) (*core.Blockchain, storage.Store, error) {
|
func initBlockChain(cfg config.Config, log *zap.Logger) (*core.Blockchain, storage.Store, error) {
|
||||||
store, err := storage.NewStore(cfg.ApplicationConfiguration.DBConfiguration)
|
store, err := storage.NewStore(cfg.ApplicationConfiguration.DBConfiguration)
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"flag"
|
"flag"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"runtime"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"go.uber.org/zap/zapcore"
|
"go.uber.org/zap/zapcore"
|
||||||
|
@ -49,6 +50,39 @@ func TestGetConfigFromContext(t *testing.T) {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, netmode.TestNet, cfg.ProtocolConfiguration.Magic)
|
require.Equal(t, netmode.TestNet, cfg.ProtocolConfiguration.Magic)
|
||||||
})
|
})
|
||||||
|
t.Run("relative-path windows", func(t *testing.T) {
|
||||||
|
if runtime.GOOS != "windows" {
|
||||||
|
t.Skip("skipping Windows specific test")
|
||||||
|
}
|
||||||
|
|
||||||
|
set := flag.NewFlagSet("flagSet", flag.ExitOnError)
|
||||||
|
set.String("relative-path", "..\\..\\config", "")
|
||||||
|
set.Bool("testnet", true, "")
|
||||||
|
set.String("config-file", ".\\testdata\\protocol.testnet.windows.yml", "")
|
||||||
|
ctx := cli.NewContext(cli.NewApp(), set, nil)
|
||||||
|
cfg, err := options.GetConfigFromContext(ctx)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, filepath.Join("..", "..", "config", "chains", "testnet"), cfg.ApplicationConfiguration.DBConfiguration.LevelDBOptions.DataDirectoryPath)
|
||||||
|
require.Equal(t, "C:\\someFolder\\cn_wallet.json", cfg.ApplicationConfiguration.Consensus.UnlockWallet.Path)
|
||||||
|
require.Equal(t, "C:\\someFolder\\notary_wallet.json", cfg.ApplicationConfiguration.P2PNotary.UnlockWallet.Path)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("relative-path non-windows", func(t *testing.T) {
|
||||||
|
if runtime.GOOS == "windows" {
|
||||||
|
t.Skip("skipping non-Windows specific test")
|
||||||
|
}
|
||||||
|
|
||||||
|
set := flag.NewFlagSet("flagSet", flag.ExitOnError)
|
||||||
|
set.String("relative-path", "../../config", "")
|
||||||
|
set.Bool("testnet", true, "")
|
||||||
|
set.String("config-file", "../../config/protocol.testnet.yml", "")
|
||||||
|
ctx := cli.NewContext(cli.NewApp(), set, nil)
|
||||||
|
cfg, err := options.GetConfigFromContext(ctx)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, filepath.Join("..", "..", "config", "chains", "testnet"), cfg.ApplicationConfiguration.DBConfiguration.LevelDBOptions.DataDirectoryPath)
|
||||||
|
require.Equal(t, "/cn_wallet.json", cfg.ApplicationConfiguration.Consensus.UnlockWallet.Path)
|
||||||
|
require.Equal(t, "/notary_wallet.json", cfg.ApplicationConfiguration.P2PNotary.UnlockWallet.Path)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestHandleLoggingParams(t *testing.T) {
|
func TestHandleLoggingParams(t *testing.T) {
|
||||||
|
@ -324,64 +358,6 @@ func TestRestoreDB(t *testing.T) {
|
||||||
require.NoError(t, restoreDB(ctx))
|
require.NoError(t, restoreDB(ctx))
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestConfigureAddresses checks deprecated code compatibility, it should be removed
|
|
||||||
// along with deprecated `Address` field removal.
|
|
||||||
func TestConfigureAddresses(t *testing.T) {
|
|
||||||
defaultAddress := "http://localhost:10333"
|
|
||||||
customAddress := "http://localhost:10334"
|
|
||||||
|
|
||||||
t.Run("default addresses", func(t *testing.T) {
|
|
||||||
cfg := &config.ApplicationConfiguration{
|
|
||||||
Address: &defaultAddress, //nolint:staticcheck // SA1019: Address is deprecated
|
|
||||||
}
|
|
||||||
configureAddresses(cfg)
|
|
||||||
require.Equal(t, defaultAddress, *cfg.RPC.Address) //nolint:staticcheck // SA1019: cfg.RPC.Address is deprecated
|
|
||||||
require.Equal(t, defaultAddress, *cfg.Prometheus.Address) //nolint:staticcheck // SA1019: cfg.Prometheus.Address is deprecated
|
|
||||||
require.Equal(t, defaultAddress, *cfg.Pprof.Address) //nolint:staticcheck // SA1019: cfg.Pprof.Address is deprecated
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("custom RPC address", func(t *testing.T) {
|
|
||||||
cfg := &config.ApplicationConfiguration{
|
|
||||||
Address: &defaultAddress, //nolint:staticcheck // SA1019: Address is deprecated
|
|
||||||
RPC: config.RPC{
|
|
||||||
BasicService: config.BasicService{
|
|
||||||
Address: &customAddress, //nolint:staticcheck // SA1019: Address is deprecated
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
configureAddresses(cfg)
|
|
||||||
require.Equal(t, *cfg.RPC.Address, customAddress) //nolint:staticcheck // SA1019: cfg.RPC.Address is deprecated
|
|
||||||
require.Equal(t, *cfg.Prometheus.Address, defaultAddress) //nolint:staticcheck // SA1019: cfg.Prometheus.Address is deprecated
|
|
||||||
require.Equal(t, *cfg.Pprof.Address, defaultAddress) //nolint:staticcheck // SA1019: cfg.Pprof.Address is deprecated
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("custom Pprof address", func(t *testing.T) {
|
|
||||||
cfg := &config.ApplicationConfiguration{
|
|
||||||
Address: &defaultAddress, //nolint:staticcheck // SA1019: Address is deprecated
|
|
||||||
Pprof: config.BasicService{
|
|
||||||
Address: &customAddress, //nolint:staticcheck // SA1019: Address is deprecated
|
|
||||||
},
|
|
||||||
}
|
|
||||||
configureAddresses(cfg)
|
|
||||||
require.Equal(t, *cfg.RPC.Address, defaultAddress) //nolint:staticcheck // SA1019: cfg.RPC.Address is deprecated
|
|
||||||
require.Equal(t, *cfg.Prometheus.Address, defaultAddress) //nolint:staticcheck // SA1019: cfg.Prometheus.Address is deprecated
|
|
||||||
require.Equal(t, *cfg.Pprof.Address, customAddress) //nolint:staticcheck // SA1019: cfg.Pprof.Address is deprecated
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("custom Prometheus address", func(t *testing.T) {
|
|
||||||
cfg := &config.ApplicationConfiguration{
|
|
||||||
Address: &defaultAddress, //nolint:staticcheck // SA1019: Address is deprecated
|
|
||||||
Prometheus: config.BasicService{
|
|
||||||
Address: &customAddress, //nolint:staticcheck // SA1019: Address is deprecated
|
|
||||||
},
|
|
||||||
}
|
|
||||||
configureAddresses(cfg)
|
|
||||||
require.Equal(t, *cfg.RPC.Address, defaultAddress) //nolint:staticcheck // SA1019: cfg.RPC.Address is deprecated
|
|
||||||
require.Equal(t, *cfg.Prometheus.Address, customAddress) //nolint:staticcheck // SA1019: cfg.Prometheus.Address is deprecated
|
|
||||||
require.Equal(t, *cfg.Pprof.Address, defaultAddress) //nolint:staticcheck // SA1019: cfg.Pprof.Address is deprecated
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestInitBlockChain(t *testing.T) {
|
func TestInitBlockChain(t *testing.T) {
|
||||||
t.Run("bad storage", func(t *testing.T) {
|
t.Run("bad storage", func(t *testing.T) {
|
||||||
_, _, err := initBlockChain(config.Config{}, nil)
|
_, _, err := initBlockChain(config.Config{}, nil)
|
||||||
|
|
96
cli/server/testdata/protocol.testnet.windows.yml
vendored
Normal file
96
cli/server/testdata/protocol.testnet.windows.yml
vendored
Normal file
|
@ -0,0 +1,96 @@
|
||||||
|
ProtocolConfiguration:
|
||||||
|
Magic: 894710606
|
||||||
|
MaxBlockSize: 2097152
|
||||||
|
MaxBlockSystemFee: 150000000000
|
||||||
|
MaxTraceableBlocks: 2102400
|
||||||
|
MaxTransactionsPerBlock: 5000
|
||||||
|
InitialGASSupply: 52000000
|
||||||
|
TimePerBlock: 15s
|
||||||
|
MemPoolSize: 50000
|
||||||
|
StandbyCommittee:
|
||||||
|
- 023e9b32ea89b94d066e649b124fd50e396ee91369e8e2a6ae1b11c170d022256d
|
||||||
|
- 03009b7540e10f2562e5fd8fac9eaec25166a58b26e412348ff5a86927bfac22a2
|
||||||
|
- 02ba2c70f5996f357a43198705859fae2cfea13e1172962800772b3d588a9d4abd
|
||||||
|
- 03408dcd416396f64783ac587ea1e1593c57d9fea880c8a6a1920e92a259477806
|
||||||
|
- 02a7834be9b32e2981d157cb5bbd3acb42cfd11ea5c3b10224d7a44e98c5910f1b
|
||||||
|
- 0214baf0ceea3a66f17e7e1e839ea25fd8bed6cd82e6bb6e68250189065f44ff01
|
||||||
|
- 030205e9cefaea5a1dfc580af20c8d5aa2468bb0148f1a5e4605fc622c80e604ba
|
||||||
|
- 025831cee3708e87d78211bec0d1bfee9f4c85ae784762f042e7f31c0d40c329b8
|
||||||
|
- 02cf9dc6e85d581480d91e88e8cbeaa0c153a046e89ded08b4cefd851e1d7325b5
|
||||||
|
- 03840415b0a0fcf066bcc3dc92d8349ebd33a6ab1402ef649bae00e5d9f5840828
|
||||||
|
- 026328aae34f149853430f526ecaa9cf9c8d78a4ea82d08bdf63dd03c4d0693be6
|
||||||
|
- 02c69a8d084ee7319cfecf5161ff257aa2d1f53e79bf6c6f164cff5d94675c38b3
|
||||||
|
- 0207da870cedb777fceff948641021714ec815110ca111ccc7a54c168e065bda70
|
||||||
|
- 035056669864feea401d8c31e447fb82dd29f342a9476cfd449584ce2a6165e4d7
|
||||||
|
- 0370c75c54445565df62cfe2e76fbec4ba00d1298867972213530cae6d418da636
|
||||||
|
- 03957af9e77282ae3263544b7b2458903624adc3f5dee303957cb6570524a5f254
|
||||||
|
- 03d84d22b8753cf225d263a3a782a4e16ca72ef323cfde04977c74f14873ab1e4c
|
||||||
|
- 02147c1b1d5728e1954958daff2f88ee2fa50a06890a8a9db3fa9e972b66ae559f
|
||||||
|
- 03c609bea5a4825908027e4ab217e7efc06e311f19ecad9d417089f14927a173d5
|
||||||
|
- 0231edee3978d46c335e851c76059166eb8878516f459e085c0dd092f0f1d51c21
|
||||||
|
- 03184b018d6b2bc093e535519732b3fd3f7551c8cffaf4621dd5a0b89482ca66c9
|
||||||
|
ValidatorsCount: 7
|
||||||
|
SeedList:
|
||||||
|
- seed1t5.neo.org:20333
|
||||||
|
- seed2t5.neo.org:20333
|
||||||
|
- seed3t5.neo.org:20333
|
||||||
|
- seed4t5.neo.org:20333
|
||||||
|
- seed5t5.neo.org:20333
|
||||||
|
VerifyTransactions: false
|
||||||
|
P2PSigExtensions: false
|
||||||
|
Hardforks:
|
||||||
|
Aspidochelone: 210000
|
||||||
|
Basilisk: 2680000
|
||||||
|
|
||||||
|
ApplicationConfiguration:
|
||||||
|
SkipBlockVerification: false
|
||||||
|
DBConfiguration:
|
||||||
|
Type: "leveldb" #other options: 'inmemory','boltdb'
|
||||||
|
# DB type options. Uncomment those you need in case you want to switch DB type.
|
||||||
|
LevelDBOptions:
|
||||||
|
DataDirectoryPath: ".\\chains\\testnet"
|
||||||
|
P2P:
|
||||||
|
Addresses:
|
||||||
|
- ":20333" # in form of "[host]:[port][:announcedPort]"
|
||||||
|
DialTimeout: 3s
|
||||||
|
ProtoTickInterval: 2s
|
||||||
|
PingInterval: 30s
|
||||||
|
PingTimeout: 90s
|
||||||
|
MaxPeers: 100
|
||||||
|
AttemptConnPeers: 20
|
||||||
|
MinPeers: 10
|
||||||
|
Relay: true
|
||||||
|
Consensus:
|
||||||
|
Enabled: false
|
||||||
|
UnlockWallet:
|
||||||
|
Path: "C:\\someFolder\\cn_wallet.json"
|
||||||
|
Password: "pass"
|
||||||
|
Oracle:
|
||||||
|
Enabled: false
|
||||||
|
AllowedContentTypes:
|
||||||
|
- application/json
|
||||||
|
P2PNotary:
|
||||||
|
Enabled: false
|
||||||
|
UnlockWallet:
|
||||||
|
Path: "C:\\someFolder\\notary_wallet.json"
|
||||||
|
Password: "pass"
|
||||||
|
RPC:
|
||||||
|
Enabled: true
|
||||||
|
Addresses:
|
||||||
|
- ":20332"
|
||||||
|
MaxGasInvoke: 15
|
||||||
|
EnableCORSWorkaround: false
|
||||||
|
TLSConfig:
|
||||||
|
Enabled: false
|
||||||
|
Addresses:
|
||||||
|
- ":20331"
|
||||||
|
CertFile: serv.crt
|
||||||
|
KeyFile: serv.key
|
||||||
|
Prometheus:
|
||||||
|
Enabled: true
|
||||||
|
Addresses:
|
||||||
|
- ":2112"
|
||||||
|
Pprof:
|
||||||
|
Enabled: false
|
||||||
|
Addresses:
|
||||||
|
- ":2113"
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
@ -13,6 +14,7 @@ import (
|
||||||
"github.com/nspcc-dev/neo-go/cli/smartcontract"
|
"github.com/nspcc-dev/neo-go/cli/smartcontract"
|
||||||
"github.com/nspcc-dev/neo-go/internal/random"
|
"github.com/nspcc-dev/neo-go/internal/random"
|
||||||
"github.com/nspcc-dev/neo-go/internal/testcli"
|
"github.com/nspcc-dev/neo-go/internal/testcli"
|
||||||
|
"github.com/nspcc-dev/neo-go/internal/versionutil"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/config"
|
"github.com/nspcc-dev/neo-go/pkg/config"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/interop/storage"
|
"github.com/nspcc-dev/neo-go/pkg/core/interop/storage"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/state"
|
"github.com/nspcc-dev/neo-go/pkg/core/state"
|
||||||
|
@ -23,6 +25,7 @@ import (
|
||||||
"github.com/nspcc-dev/neo-go/pkg/neorpc/result"
|
"github.com/nspcc-dev/neo-go/pkg/neorpc/result"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/nef"
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract/nef"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/vm/vmstate"
|
"github.com/nspcc-dev/neo-go/pkg/vm/vmstate"
|
||||||
|
@ -31,6 +34,9 @@ import (
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Keep contract NEFs consistent between runs.
|
||||||
|
const _ = versionutil.TestVersion
|
||||||
|
|
||||||
func TestCalcHash(t *testing.T) {
|
func TestCalcHash(t *testing.T) {
|
||||||
tmpDir := t.TempDir()
|
tmpDir := t.TempDir()
|
||||||
e := testcli.NewExecutor(t, false)
|
e := testcli.NewExecutor(t, false)
|
||||||
|
@ -97,9 +103,6 @@ func TestCalcHash(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestContractBindings(t *testing.T) {
|
func TestContractBindings(t *testing.T) {
|
||||||
// For proper nef generation.
|
|
||||||
config.Version = "v0.98.1-test"
|
|
||||||
|
|
||||||
// For proper contract init. The actual version as it will be replaced.
|
// For proper contract init. The actual version as it will be replaced.
|
||||||
smartcontract.ModVersion = "v0.0.0"
|
smartcontract.ModVersion = "v0.0.0"
|
||||||
|
|
||||||
|
@ -143,18 +146,7 @@ func Blocks() []*alias.Block {
|
||||||
cmd = append(cmd, "--in", ctrPath, "--bindings", bindingsPath)
|
cmd = append(cmd, "--in", ctrPath, "--bindings", bindingsPath)
|
||||||
|
|
||||||
// Replace `pkg/interop` in go.mod to avoid getting an actual module version.
|
// Replace `pkg/interop` in go.mod to avoid getting an actual module version.
|
||||||
goMod := filepath.Join(ctrPath, "go.mod")
|
require.NoError(t, updateGoMod(ctrPath, "myimport.com/testcontract", "../../pkg/interop"))
|
||||||
data, err := os.ReadFile(goMod)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
i := bytes.IndexByte(data, '\n')
|
|
||||||
data = append([]byte("module myimport.com/testcontract"), data[i:]...)
|
|
||||||
|
|
||||||
wd, err := os.Getwd()
|
|
||||||
require.NoError(t, err)
|
|
||||||
data = append(data, "\nreplace github.com/nspcc-dev/neo-go/pkg/interop => "...)
|
|
||||||
data = append(data, filepath.Join(wd, "../../pkg/interop")...)
|
|
||||||
require.NoError(t, os.WriteFile(goMod, data, os.ModePerm))
|
|
||||||
|
|
||||||
cmd = append(cmd, "--config", cfgPath,
|
cmd = append(cmd, "--config", cfgPath,
|
||||||
"--out", filepath.Join(tmpDir, "out.nef"),
|
"--out", filepath.Join(tmpDir, "out.nef"),
|
||||||
|
@ -174,7 +166,9 @@ func Blocks() []*alias.Block {
|
||||||
|
|
||||||
bs, err := os.ReadFile(outPath)
|
bs, err := os.ReadFile(outPath)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, `// Package testcontract contains wrappers for testcontract contract.
|
require.Equal(t, `// Code generated by neo-go contract generate-wrapper --manifest <file.json> --out <file.go> [--hash <hash>] [--config <config>]; DO NOT EDIT.
|
||||||
|
|
||||||
|
// Package testcontract contains wrappers for testcontract contract.
|
||||||
package testcontract
|
package testcontract
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -209,10 +203,85 @@ func ToMap(a []testcontract.MyPair) map[int]string {
|
||||||
`, string(bs))
|
`, string(bs))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestContractInitAndCompile(t *testing.T) {
|
// updateGoMod updates the go.mod file located in the specified directory.
|
||||||
// For proper nef generation.
|
// It sets the module name and replaces the neo-go interop package path with
|
||||||
config.Version = "v0.98.1-test"
|
// the provided one to avoid getting an actual module version.
|
||||||
|
func updateGoMod(dir, moduleName, neoGoPath string) error {
|
||||||
|
goModPath := filepath.Join(dir, "go.mod")
|
||||||
|
data, err := os.ReadFile(goModPath)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to read go.mod: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
i := bytes.IndexByte(data, '\n')
|
||||||
|
if i == -1 {
|
||||||
|
return fmt.Errorf("unexpected go.mod format")
|
||||||
|
}
|
||||||
|
|
||||||
|
updatedData := append([]byte("module "+moduleName), data[i:]...)
|
||||||
|
wd, err := os.Getwd()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to get working directory: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
replacementPath := filepath.Join(wd, neoGoPath)
|
||||||
|
updatedData = append(updatedData, "\nreplace github.com/nspcc-dev/neo-go/pkg/interop => "+replacementPath+" \n"...)
|
||||||
|
|
||||||
|
if err := os.WriteFile(goModPath, updatedData, os.ModePerm); err != nil {
|
||||||
|
return fmt.Errorf("failed to write updated go.mod: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDynamicWrapper(t *testing.T) {
|
||||||
|
// For proper contract init. The actual version as it will be replaced.
|
||||||
|
smartcontract.ModVersion = "v0.0.0"
|
||||||
|
|
||||||
|
tmpDir := t.TempDir()
|
||||||
|
e := testcli.NewExecutor(t, true)
|
||||||
|
|
||||||
|
ctrPath := "../smartcontract/testdata"
|
||||||
|
|
||||||
|
verifyHash := testcli.DeployContract(t, e, filepath.Join(ctrPath, "verify.go"), filepath.Join(ctrPath, "verify.yml"), testcli.ValidatorWallet, testcli.ValidatorAddr, testcli.ValidatorPass)
|
||||||
|
|
||||||
|
helperContract := `package testcontract
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/interop"
|
||||||
|
verify "myimport.com/testcontract/bindings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func CallVerifyContract(h interop.Hash160) bool{
|
||||||
|
contractInstance := verify.NewContract(h)
|
||||||
|
return contractInstance.Verify()
|
||||||
|
}`
|
||||||
|
|
||||||
|
helperDir := filepath.Join(tmpDir, "helper")
|
||||||
|
e.Run(t, "neo-go", "contract", "init", "--name", helperDir)
|
||||||
|
|
||||||
|
require.NoError(t, updateGoMod(helperDir, "myimport.com/testcontract", "../../pkg/interop"))
|
||||||
|
require.NoError(t, os.WriteFile(filepath.Join(helperDir, "main.go"), []byte(helperContract), os.ModePerm))
|
||||||
|
require.NoError(t, os.Mkdir(filepath.Join(helperDir, "bindings"), os.ModePerm))
|
||||||
|
|
||||||
|
e.Run(t, "neo-go", "contract", "generate-wrapper",
|
||||||
|
"--config", filepath.Join(ctrPath, "verify.bindings.yml"), "--manifest", filepath.Join(ctrPath, "verify.manifest.json"),
|
||||||
|
"--out", filepath.Join(helperDir, "bindings", "testdata.go"))
|
||||||
|
e.Run(t, "neo-go", "contract", "compile", "--in", filepath.Join(helperDir, "main.go"), "--config", filepath.Join(helperDir, "neo-go.yml"))
|
||||||
|
helperHash := testcli.DeployContract(t, e, filepath.Join(helperDir, "main.go"), filepath.Join(helperDir, "neo-go.yml"), testcli.ValidatorWallet, testcli.ValidatorAddr, testcli.ValidatorPass)
|
||||||
|
|
||||||
|
e.In.WriteString("one\r")
|
||||||
|
e.Run(t, "neo-go", "contract", "invokefunction",
|
||||||
|
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
|
||||||
|
"--wallet", testcli.ValidatorWallet, "--address", testcli.ValidatorAddr, "--force", "--await", helperHash.StringLE(), "callVerifyContract", verifyHash.StringLE())
|
||||||
|
|
||||||
|
tx, _ := e.CheckTxPersisted(t, "Sent invocation transaction ")
|
||||||
|
aer, err := e.Chain.GetAppExecResults(tx.Hash(), trigger.Application)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, aer[0].Stack[0].Value().(bool), true)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestContractInitAndCompile(t *testing.T) {
|
||||||
// For proper contract init. The actual version as it will be replaced.
|
// For proper contract init. The actual version as it will be replaced.
|
||||||
smartcontract.ModVersion = "v0.0.0"
|
smartcontract.ModVersion = "v0.0.0"
|
||||||
|
|
||||||
|
@ -264,15 +333,7 @@ func TestContractInitAndCompile(t *testing.T) {
|
||||||
})
|
})
|
||||||
|
|
||||||
// Replace `pkg/interop` in go.mod to avoid getting an actual module version.
|
// Replace `pkg/interop` in go.mod to avoid getting an actual module version.
|
||||||
goMod := filepath.Join(ctrPath, "go.mod")
|
require.NoError(t, updateGoMod(ctrPath, "myimport.com/testcontract", "../../pkg/interop"))
|
||||||
data, err := os.ReadFile(goMod)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
wd, err := os.Getwd()
|
|
||||||
require.NoError(t, err)
|
|
||||||
data = append(data, "\nreplace github.com/nspcc-dev/neo-go/pkg/interop => "...)
|
|
||||||
data = append(data, filepath.Join(wd, "../../pkg/interop")...)
|
|
||||||
require.NoError(t, os.WriteFile(goMod, data, os.ModePerm))
|
|
||||||
|
|
||||||
cmd = append(cmd, "--config", cfgPath)
|
cmd = append(cmd, "--config", cfgPath)
|
||||||
|
|
||||||
|
@ -310,9 +371,6 @@ func TestDeployBigContract(t *testing.T) {
|
||||||
e := testcli.NewExecutorWithConfig(t, true, true, func(c *config.Config) {
|
e := testcli.NewExecutorWithConfig(t, true, true, func(c *config.Config) {
|
||||||
c.ApplicationConfiguration.RPC.MaxGasInvoke = fixedn.Fixed8(1)
|
c.ApplicationConfiguration.RPC.MaxGasInvoke = fixedn.Fixed8(1)
|
||||||
})
|
})
|
||||||
|
|
||||||
// For proper nef generation.
|
|
||||||
config.Version = "0.90.0-test"
|
|
||||||
tmpDir := t.TempDir()
|
tmpDir := t.TempDir()
|
||||||
|
|
||||||
nefName := filepath.Join(tmpDir, "deploy.nef")
|
nefName := filepath.Join(tmpDir, "deploy.nef")
|
||||||
|
@ -331,9 +389,6 @@ func TestDeployBigContract(t *testing.T) {
|
||||||
|
|
||||||
func TestContractDeployWithData(t *testing.T) {
|
func TestContractDeployWithData(t *testing.T) {
|
||||||
eCompile := testcli.NewExecutor(t, false)
|
eCompile := testcli.NewExecutor(t, false)
|
||||||
|
|
||||||
// For proper nef generation.
|
|
||||||
config.Version = "0.90.0-test"
|
|
||||||
tmpDir := t.TempDir()
|
tmpDir := t.TempDir()
|
||||||
|
|
||||||
nefName := filepath.Join(tmpDir, "deploy.nef")
|
nefName := filepath.Join(tmpDir, "deploy.nef")
|
||||||
|
@ -343,7 +398,7 @@ func TestContractDeployWithData(t *testing.T) {
|
||||||
"--config", "testdata/deploy/neo-go.yml",
|
"--config", "testdata/deploy/neo-go.yml",
|
||||||
"--out", nefName, "--manifest", manifestName)
|
"--out", nefName, "--manifest", manifestName)
|
||||||
|
|
||||||
deployContract := func(t *testing.T, haveData bool, scope string) {
|
deployContract := func(t *testing.T, haveData bool, scope string, await bool) {
|
||||||
e := testcli.NewExecutor(t, true)
|
e := testcli.NewExecutor(t, true)
|
||||||
cmd := []string{
|
cmd := []string{
|
||||||
"neo-go", "contract", "deploy",
|
"neo-go", "contract", "deploy",
|
||||||
|
@ -353,6 +408,9 @@ func TestContractDeployWithData(t *testing.T) {
|
||||||
"--force",
|
"--force",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if await {
|
||||||
|
cmd = append(cmd, "--await")
|
||||||
|
}
|
||||||
if haveData {
|
if haveData {
|
||||||
cmd = append(cmd, "[", "key1", "12", "key2", "take_me_to_church", "]")
|
cmd = append(cmd, "[", "key1", "12", "key2", "take_me_to_church", "]")
|
||||||
}
|
}
|
||||||
|
@ -363,8 +421,13 @@ func TestContractDeployWithData(t *testing.T) {
|
||||||
}
|
}
|
||||||
e.In.WriteString(testcli.ValidatorPass + "\r")
|
e.In.WriteString(testcli.ValidatorPass + "\r")
|
||||||
e.Run(t, cmd...)
|
e.Run(t, cmd...)
|
||||||
|
var tx *transaction.Transaction
|
||||||
|
if await {
|
||||||
|
tx, _ = e.CheckAwaitableTxPersisted(t)
|
||||||
|
} else {
|
||||||
|
tx, _ = e.CheckTxPersisted(t)
|
||||||
|
}
|
||||||
|
|
||||||
tx, _ := e.CheckTxPersisted(t, "Sent invocation transaction ")
|
|
||||||
require.Equal(t, scope, tx.Signers[0].Scopes.String())
|
require.Equal(t, scope, tx.Signers[0].Scopes.String())
|
||||||
if !haveData {
|
if !haveData {
|
||||||
return
|
return
|
||||||
|
@ -401,16 +464,16 @@ func TestContractDeployWithData(t *testing.T) {
|
||||||
require.Equal(t, []byte("take_me_to_church"), res.Stack[0].Value())
|
require.Equal(t, []byte("take_me_to_church"), res.Stack[0].Value())
|
||||||
}
|
}
|
||||||
|
|
||||||
deployContract(t, true, "")
|
deployContract(t, true, "", false)
|
||||||
deployContract(t, false, "Global")
|
deployContract(t, false, "Global", false)
|
||||||
deployContract(t, true, "Global")
|
deployContract(t, true, "Global", false)
|
||||||
|
deployContract(t, false, "", true)
|
||||||
|
deployContract(t, true, "Global", true)
|
||||||
|
deployContract(t, true, "", true)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDeployWithSigners(t *testing.T) {
|
func TestDeployWithSigners(t *testing.T) {
|
||||||
e := testcli.NewExecutor(t, true)
|
e := testcli.NewExecutor(t, true)
|
||||||
|
|
||||||
// For proper nef generation.
|
|
||||||
config.Version = "0.90.0-test"
|
|
||||||
tmpDir := t.TempDir()
|
tmpDir := t.TempDir()
|
||||||
|
|
||||||
nefName := filepath.Join(tmpDir, "deploy.nef")
|
nefName := filepath.Join(tmpDir, "deploy.nef")
|
||||||
|
@ -472,9 +535,6 @@ func TestDeployWithSigners(t *testing.T) {
|
||||||
|
|
||||||
func TestContractManifestGroups(t *testing.T) {
|
func TestContractManifestGroups(t *testing.T) {
|
||||||
e := testcli.NewExecutor(t, true)
|
e := testcli.NewExecutor(t, true)
|
||||||
|
|
||||||
// For proper nef generation.
|
|
||||||
config.Version = "0.90.0-test"
|
|
||||||
tmpDir := t.TempDir()
|
tmpDir := t.TempDir()
|
||||||
|
|
||||||
_, err := wallet.NewWalletFromFile(testcli.TestWalletPath)
|
_, err := wallet.NewWalletFromFile(testcli.TestWalletPath)
|
||||||
|
@ -631,9 +691,6 @@ func TestContract_TestInvokeScript(t *testing.T) {
|
||||||
|
|
||||||
func TestComlileAndInvokeFunction(t *testing.T) {
|
func TestComlileAndInvokeFunction(t *testing.T) {
|
||||||
e := testcli.NewExecutor(t, true)
|
e := testcli.NewExecutor(t, true)
|
||||||
|
|
||||||
// For proper nef generation.
|
|
||||||
config.Version = "0.90.0-test"
|
|
||||||
tmpDir := t.TempDir()
|
tmpDir := t.TempDir()
|
||||||
|
|
||||||
nefName := filepath.Join(tmpDir, "deploy.nef")
|
nefName := filepath.Join(tmpDir, "deploy.nef")
|
||||||
|
@ -786,6 +843,12 @@ func TestComlileAndInvokeFunction(t *testing.T) {
|
||||||
e.Run(t, append(cmd, h.StringLE(), "getValue",
|
e.Run(t, append(cmd, h.StringLE(), "getValue",
|
||||||
"--", testcli.ValidatorAddr, hVerify.StringLE())...)
|
"--", testcli.ValidatorAddr, hVerify.StringLE())...)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("with await", func(t *testing.T) {
|
||||||
|
e.In.WriteString("one\r")
|
||||||
|
e.Run(t, append(cmd, "--force", "--await", h.StringLE(), "getValue")...)
|
||||||
|
e.CheckAwaitableTxPersisted(t)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("real invoke and save tx", func(t *testing.T) {
|
t.Run("real invoke and save tx", func(t *testing.T) {
|
||||||
|
@ -963,9 +1026,6 @@ func TestComlileAndInvokeFunction(t *testing.T) {
|
||||||
|
|
||||||
func TestContractInspect(t *testing.T) {
|
func TestContractInspect(t *testing.T) {
|
||||||
e := testcli.NewExecutor(t, false)
|
e := testcli.NewExecutor(t, false)
|
||||||
|
|
||||||
// For proper nef generation.
|
|
||||||
config.Version = "0.90.0-test"
|
|
||||||
const srcPath = "testdata/deploy/main.go"
|
const srcPath = "testdata/deploy/main.go"
|
||||||
tmpDir := t.TempDir()
|
tmpDir := t.TempDir()
|
||||||
|
|
||||||
|
@ -1000,9 +1060,6 @@ func TestCompileExamples(t *testing.T) {
|
||||||
infos, err := os.ReadDir(examplePath)
|
infos, err := os.ReadDir(examplePath)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// For proper nef generation.
|
|
||||||
config.Version = "0.90.0-test"
|
|
||||||
|
|
||||||
e := testcli.NewExecutor(t, false)
|
e := testcli.NewExecutor(t, false)
|
||||||
|
|
||||||
for _, info := range infos {
|
for _, info := range infos {
|
||||||
|
@ -1011,6 +1068,10 @@ func TestCompileExamples(t *testing.T) {
|
||||||
// there are also a couple of files inside the `/examples` which doesn't need to be compiled
|
// there are also a couple of files inside the `/examples` which doesn't need to be compiled
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
if info.Name() == "zkp" {
|
||||||
|
// A set of special ZKP-related examples, they have their own tests.
|
||||||
|
continue
|
||||||
|
}
|
||||||
t.Run(info.Name(), func(t *testing.T) {
|
t.Run(info.Name(), func(t *testing.T) {
|
||||||
infos, err := os.ReadDir(filepath.Join(examplePath, info.Name()))
|
infos, err := os.ReadDir(filepath.Join(examplePath, info.Name()))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
@ -1087,3 +1148,27 @@ func filterFilename(infos []os.DirEntry, ext string) string {
|
||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestContractCompile_NEFSizeCheck(t *testing.T) {
|
||||||
|
tmpDir := t.TempDir()
|
||||||
|
e := testcli.NewExecutor(t, false)
|
||||||
|
|
||||||
|
src := `package nefconstraints
|
||||||
|
var data = "%s"
|
||||||
|
|
||||||
|
func Main() string {
|
||||||
|
return data
|
||||||
|
}`
|
||||||
|
data := make([]byte, stackitem.MaxSize-10)
|
||||||
|
for i := range data {
|
||||||
|
data[i] = byte('a')
|
||||||
|
}
|
||||||
|
|
||||||
|
in := filepath.Join(tmpDir, "main.go")
|
||||||
|
cfg := filepath.Join(tmpDir, "main.yml")
|
||||||
|
require.NoError(t, os.WriteFile(cfg, []byte("name: main"), os.ModePerm))
|
||||||
|
require.NoError(t, os.WriteFile(in, []byte(fmt.Sprintf(src, data)), os.ModePerm))
|
||||||
|
|
||||||
|
e.RunWithError(t, "neo-go", "contract", "compile", "--in", in)
|
||||||
|
require.NoFileExists(t, filepath.Join(tmpDir, "main.nef"))
|
||||||
|
}
|
||||||
|
|
|
@ -30,15 +30,20 @@ var generatorFlags = []cli.Flag{
|
||||||
},
|
},
|
||||||
cli.StringFlag{
|
cli.StringFlag{
|
||||||
Name: "hash",
|
Name: "hash",
|
||||||
Usage: "Smart-contract hash",
|
Usage: "Smart-contract hash. If not passed, the wrapper will be designed for dynamic hash usage",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
var generateWrapperCmd = cli.Command{
|
var generateWrapperCmd = cli.Command{
|
||||||
Name: "generate-wrapper",
|
Name: "generate-wrapper",
|
||||||
Usage: "generate wrapper to use in other contracts",
|
Usage: "generate wrapper to use in other contracts",
|
||||||
UsageText: "neo-go contract generate-wrapper --manifest <file.json> --out <file.go> --hash <hash> [--config <config>]",
|
UsageText: "neo-go contract generate-wrapper --manifest <file.json> --out <file.go> [--hash <hash>] [--config <config>]",
|
||||||
Description: ``,
|
Description: `Generates a Go wrapper to use it in other smart contracts. If the
|
||||||
|
--hash flag is provided, CALLT instruction is used for the target contract
|
||||||
|
invocation as an optimization of the wrapper contract code. If omitted, the
|
||||||
|
generated wrapper will be designed for dynamic hash usage, allowing
|
||||||
|
the hash to be specified at runtime.
|
||||||
|
`,
|
||||||
Action: contractGenerateWrapper,
|
Action: contractGenerateWrapper,
|
||||||
Flags: generatorFlags,
|
Flags: generatorFlags,
|
||||||
}
|
}
|
||||||
|
@ -46,21 +51,21 @@ var generateWrapperCmd = cli.Command{
|
||||||
var generateRPCWrapperCmd = cli.Command{
|
var generateRPCWrapperCmd = cli.Command{
|
||||||
Name: "generate-rpcwrapper",
|
Name: "generate-rpcwrapper",
|
||||||
Usage: "generate RPC wrapper to use for data reads",
|
Usage: "generate RPC wrapper to use for data reads",
|
||||||
UsageText: "neo-go contract generate-rpcwrapper --manifest <file.json> --out <file.go> --hash <hash> [--config <config>]",
|
UsageText: "neo-go contract generate-rpcwrapper --manifest <file.json> --out <file.go> [--hash <hash>] [--config <config>]",
|
||||||
Action: contractGenerateRPCWrapper,
|
Action: contractGenerateRPCWrapper,
|
||||||
Flags: generatorFlags,
|
Flags: generatorFlags,
|
||||||
}
|
}
|
||||||
|
|
||||||
func contractGenerateWrapper(ctx *cli.Context) error {
|
func contractGenerateWrapper(ctx *cli.Context) error {
|
||||||
return contractGenerateSomething(ctx, binding.Generate, false)
|
return contractGenerateSomething(ctx, binding.Generate)
|
||||||
}
|
}
|
||||||
|
|
||||||
func contractGenerateRPCWrapper(ctx *cli.Context) error {
|
func contractGenerateRPCWrapper(ctx *cli.Context) error {
|
||||||
return contractGenerateSomething(ctx, rpcbinding.Generate, true)
|
return contractGenerateSomething(ctx, rpcbinding.Generate)
|
||||||
}
|
}
|
||||||
|
|
||||||
// contractGenerateSomething reads generator parameters and calls the given callback.
|
// contractGenerateSomething reads generator parameters and calls the given callback.
|
||||||
func contractGenerateSomething(ctx *cli.Context, cb func(binding.Config) error, allowEmptyHash bool) error {
|
func contractGenerateSomething(ctx *cli.Context, cb func(binding.Config) error) error {
|
||||||
if err := cmdargs.EnsureNone(ctx); err != nil {
|
if err := cmdargs.EnsureNone(ctx); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -73,8 +78,6 @@ func contractGenerateSomething(ctx *cli.Context, cb func(binding.Config) error,
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(fmt.Errorf("invalid contract hash: %w", err), 1)
|
return cli.NewExitError(fmt.Errorf("invalid contract hash: %w", err), 1)
|
||||||
}
|
}
|
||||||
} else if !allowEmptyHash {
|
|
||||||
return cli.NewExitError("contract hash must be provided via --hash flag", 1)
|
|
||||||
}
|
}
|
||||||
m, _, err := readManifest(ctx.String("manifest"), h)
|
m, _, err := readManifest(ctx.String("manifest"), h)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -151,7 +151,9 @@ callflags:
|
||||||
"--hash", h.StringLE(),
|
"--hash", h.StringLE(),
|
||||||
}))
|
}))
|
||||||
|
|
||||||
const expected = `// Package wrapper contains wrappers for MyContract contract.
|
const expected = `// Code generated by neo-go contract generate-wrapper --manifest <file.json> --out <file.go> [--hash <hash>] [--config <config>]; DO NOT EDIT.
|
||||||
|
|
||||||
|
// Package wrapper contains wrappers for MyContract contract.
|
||||||
package wrapper
|
package wrapper
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -172,8 +174,8 @@ func Sum(first int, second int) int {
|
||||||
return neogointernal.CallWithToken(Hash, "sum", int(contract.All), first, second).(int)
|
return neogointernal.CallWithToken(Hash, "sum", int(contract.All), first, second).(int)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sum_3 invokes ` + "`sum`" + ` method of contract.
|
// Sum2 invokes ` + "`sum`" + ` method of contract.
|
||||||
func Sum_3(first int, second int, third int) int {
|
func Sum2(first int, second int, third int) int {
|
||||||
return neogointernal.CallWithToken(Hash, "sum", int(contract.All), first, second, third).(int)
|
return neogointernal.CallWithToken(Hash, "sum", int(contract.All), first, second, third).(int)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -231,6 +233,99 @@ func MyFunc(in map[int]mycontract.Input) []mycontract.Output {
|
||||||
data, err := os.ReadFile(outFile)
|
data, err := os.ReadFile(outFile)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, expected, string(data))
|
require.Equal(t, expected, string(data))
|
||||||
|
|
||||||
|
require.NoError(t, app.Run([]string{"", "generate-wrapper",
|
||||||
|
"--manifest", manifestFile,
|
||||||
|
"--config", cfgPath,
|
||||||
|
"--out", outFile,
|
||||||
|
}))
|
||||||
|
expectedWithDynamicHash := `// Code generated by neo-go contract generate-wrapper --manifest <file.json> --out <file.go> [--hash <hash>] [--config <config>]; DO NOT EDIT.
|
||||||
|
|
||||||
|
// Package wrapper contains wrappers for MyContract contract.
|
||||||
|
package wrapper
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/heyitsme/mycontract"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/interop"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/interop/contract"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/interop/iterator"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/interop/native/ledger"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/interop/storage"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Contract represents the MyContract smart contract.
|
||||||
|
type Contract struct {
|
||||||
|
Hash interop.Hash160
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewContract returns a new Contract instance with the specified hash.
|
||||||
|
func NewContract(hash interop.Hash160) Contract {
|
||||||
|
return Contract{Hash: hash}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sum invokes ` + "`sum`" + ` method of contract.
|
||||||
|
func (c Contract) Sum(first int, second int) int {
|
||||||
|
return contract.Call(c.Hash, "sum", contract.All, first, second).(int)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sum2 invokes ` + "`sum`" + ` method of contract.
|
||||||
|
func (c Contract) Sum2(first int, second int, third int) int {
|
||||||
|
return contract.Call(c.Hash, "sum", contract.All, first, second, third).(int)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sum3 invokes ` + "`sum3`" + ` method of contract.
|
||||||
|
func (c Contract) Sum3() int {
|
||||||
|
return contract.Call(c.Hash, "sum3", contract.ReadOnly).(int)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Zum invokes ` + "`zum`" + ` method of contract.
|
||||||
|
func (c Contract) Zum(typev int, typev_ int, funcv int) int {
|
||||||
|
return contract.Call(c.Hash, "zum", contract.All, typev, typev_, funcv).(int)
|
||||||
|
}
|
||||||
|
|
||||||
|
// JustExecute invokes ` + "`justExecute`" + ` method of contract.
|
||||||
|
func (c Contract) JustExecute(arr []any) {
|
||||||
|
contract.Call(c.Hash, "justExecute", contract.All, arr)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetPublicKey invokes ` + "`getPublicKey`" + ` method of contract.
|
||||||
|
func (c Contract) GetPublicKey() interop.PublicKey {
|
||||||
|
return contract.Call(c.Hash, "getPublicKey", contract.All).(interop.PublicKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
// OtherTypes invokes ` + "`otherTypes`" + ` method of contract.
|
||||||
|
func (c Contract) OtherTypes(ctr interop.Hash160, tx interop.Hash256, sig interop.Signature, data any) bool {
|
||||||
|
return contract.Call(c.Hash, "otherTypes", contract.All, ctr, tx, sig, data).(bool)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SearchStorage invokes ` + "`searchStorage`" + ` method of contract.
|
||||||
|
func (c Contract) SearchStorage(ctx storage.Context) iterator.Iterator {
|
||||||
|
return contract.Call(c.Hash, "searchStorage", contract.All, ctx).(iterator.Iterator)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetFromMap invokes ` + "`getFromMap`" + ` method of contract.
|
||||||
|
func (c Contract) GetFromMap(intMap map[string]int, indices []string) []int {
|
||||||
|
return contract.Call(c.Hash, "getFromMap", contract.All, intMap, indices).([]int)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DoSomething invokes ` + "`doSomething`" + ` method of contract.
|
||||||
|
func (c Contract) DoSomething(bytes []byte, str string) any {
|
||||||
|
return contract.Call(c.Hash, "doSomething", contract.ReadStates, bytes, str).(any)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetBlockWrapper invokes ` + "`getBlockWrapper`" + ` method of contract.
|
||||||
|
func (c Contract) GetBlockWrapper() ledger.Block {
|
||||||
|
return contract.Call(c.Hash, "getBlockWrapper", contract.All).(ledger.Block)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MyFunc invokes ` + "`myFunc`" + ` method of contract.
|
||||||
|
func (c Contract) MyFunc(in map[int]mycontract.Input) []mycontract.Output {
|
||||||
|
return contract.Call(c.Hash, "myFunc", contract.All, in).([]mycontract.Output)
|
||||||
|
}
|
||||||
|
`
|
||||||
|
data, err = os.ReadFile(outFile)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, expectedWithDynamicHash, string(data))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGenerateValidPackageName(t *testing.T) {
|
func TestGenerateValidPackageName(t *testing.T) {
|
||||||
|
@ -265,7 +360,9 @@ func TestGenerateValidPackageName(t *testing.T) {
|
||||||
|
|
||||||
data, err := os.ReadFile(outFile)
|
data, err := os.ReadFile(outFile)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, `// Package myspacecontract contains wrappers for My space contract contract.
|
require.Equal(t, `// Code generated by neo-go contract generate-wrapper --manifest <file.json> --out <file.go> [--hash <hash>] [--config <config>]; DO NOT EDIT.
|
||||||
|
|
||||||
|
// Package myspacecontract contains wrappers for My space contract contract.
|
||||||
package myspacecontract
|
package myspacecontract
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -289,7 +386,9 @@ func Get() int {
|
||||||
|
|
||||||
data, err = os.ReadFile(outFile)
|
data, err = os.ReadFile(outFile)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, `// Package myspacecontract contains RPC wrappers for My space contract contract.
|
require.Equal(t, `// Code generated by neo-go contract generate-rpcwrapper --manifest <file.json> --out <file.go> [--hash <hash>] [--config <config>]; DO NOT EDIT.
|
||||||
|
|
||||||
|
// Package myspacecontract contains RPC wrappers for My space contract contract.
|
||||||
package myspacecontract
|
package myspacecontract
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -389,6 +488,7 @@ func TestAssistedRPCBindings(t *testing.T) {
|
||||||
}
|
}
|
||||||
testName += fmt.Sprintf(", predefined hash: %t", hasDefinedHash)
|
testName += fmt.Sprintf(", predefined hash: %t", hasDefinedHash)
|
||||||
t.Run(testName, func(t *testing.T) {
|
t.Run(testName, func(t *testing.T) {
|
||||||
|
outFile := filepath.Join(tmpDir, "out.go")
|
||||||
configFile := filepath.Join(source, "config.yml")
|
configFile := filepath.Join(source, "config.yml")
|
||||||
expectedFile := filepath.Join(source, "rpcbindings.out")
|
expectedFile := filepath.Join(source, "rpcbindings.out")
|
||||||
if len(suffix) != 0 {
|
if len(suffix) != 0 {
|
||||||
|
@ -415,14 +515,14 @@ func TestAssistedRPCBindings(t *testing.T) {
|
||||||
cmds := []string{"", "contract", "generate-rpcwrapper",
|
cmds := []string{"", "contract", "generate-rpcwrapper",
|
||||||
"--config", bindingF,
|
"--config", bindingF,
|
||||||
"--manifest", manifestF,
|
"--manifest", manifestF,
|
||||||
"--out", expectedFile,
|
"--out", outFile,
|
||||||
}
|
}
|
||||||
if hasDefinedHash {
|
if hasDefinedHash {
|
||||||
cmds = append(cmds, "--hash", "0x00112233445566778899aabbccddeeff00112233")
|
cmds = append(cmds, "--hash", "0x00112233445566778899aabbccddeeff00112233")
|
||||||
}
|
}
|
||||||
require.NoError(t, app.Run(cmds))
|
require.NoError(t, app.Run(cmds))
|
||||||
|
|
||||||
data, err := os.ReadFile(expectedFile)
|
data, err := os.ReadFile(outFile)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
data = bytes.ReplaceAll(data, []byte("\r"), []byte{}) // Windows.
|
data = bytes.ReplaceAll(data, []byte("\r"), []byte{}) // Windows.
|
||||||
if rewriteExpectedOutputs {
|
if rewriteExpectedOutputs {
|
||||||
|
@ -437,12 +537,12 @@ func TestAssistedRPCBindings(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, hasDefinedHash := range []bool{true, false} {
|
for _, hasDefinedHash := range []bool{true, false} {
|
||||||
checkBinding(filepath.Join("testdata", "types"), hasDefinedHash, false)
|
checkBinding(filepath.Join("testdata", "rpcbindings", "types"), hasDefinedHash, false)
|
||||||
checkBinding(filepath.Join("testdata", "structs"), hasDefinedHash, false)
|
checkBinding(filepath.Join("testdata", "rpcbindings", "structs"), hasDefinedHash, false)
|
||||||
}
|
}
|
||||||
checkBinding(filepath.Join("testdata", "notifications"), true, false)
|
checkBinding(filepath.Join("testdata", "rpcbindings", "notifications"), true, false)
|
||||||
checkBinding(filepath.Join("testdata", "notifications"), true, false, "_extended")
|
checkBinding(filepath.Join("testdata", "rpcbindings", "notifications"), true, false, "_extended")
|
||||||
checkBinding(filepath.Join("testdata", "notifications"), true, true, "_guessed")
|
checkBinding(filepath.Join("testdata", "rpcbindings", "notifications"), true, true, "_guessed")
|
||||||
|
|
||||||
require.False(t, rewriteExpectedOutputs)
|
require.False(t, rewriteExpectedOutputs)
|
||||||
}
|
}
|
||||||
|
@ -540,10 +640,10 @@ func TestCompile_GuessEventTypes(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
t.Run("not declared in manifest", func(t *testing.T) {
|
t.Run("not declared in manifest", func(t *testing.T) {
|
||||||
check(t, filepath.Join("testdata", "invalid5"), "inconsistent usages of event `Non declared event`: not declared in the contract config")
|
check(t, filepath.Join("testdata", "rpcbindings", "invalid1"), "inconsistent usages of event `Non declared event`: not declared in the contract config")
|
||||||
})
|
})
|
||||||
t.Run("invalid number of params", func(t *testing.T) {
|
t.Run("invalid number of params", func(t *testing.T) {
|
||||||
check(t, filepath.Join("testdata", "invalid6"), "inconsistent usages of event `SomeEvent` against config: number of params mismatch: 2 vs 1")
|
check(t, filepath.Join("testdata", "rpcbindings", "invalid2"), "inconsistent usages of event `SomeEvent` against config: number of params mismatch: 2 vs 1")
|
||||||
})
|
})
|
||||||
/*
|
/*
|
||||||
// TODO: this on is a controversial one. If event information is provided in the config file, then conversion code
|
// TODO: this on is a controversial one. If event information is provided in the config file, then conversion code
|
||||||
|
@ -552,13 +652,61 @@ func TestCompile_GuessEventTypes(t *testing.T) {
|
||||||
// Thus, this testcase is always failing (no compilation error occures).
|
// Thus, this testcase is always failing (no compilation error occures).
|
||||||
// Question: do we want to compare `RealType` of the emitted parameter with the one expected in the manifest?
|
// Question: do we want to compare `RealType` of the emitted parameter with the one expected in the manifest?
|
||||||
t.Run("SC parameter type mismatch", func(t *testing.T) {
|
t.Run("SC parameter type mismatch", func(t *testing.T) {
|
||||||
check(t, filepath.Join("testdata", "invalid7"), "inconsistent usages of event `SomeEvent` against config: number of params mismatch: 2 vs 1")
|
check(t, filepath.Join("testdata", "rpcbindings", "invalid3"), "inconsistent usages of event `SomeEvent` against config: number of params mismatch: 2 vs 1")
|
||||||
})
|
})
|
||||||
*/
|
*/
|
||||||
t.Run("extended types mismatch", func(t *testing.T) {
|
t.Run("extended types mismatch", func(t *testing.T) {
|
||||||
check(t, filepath.Join("testdata", "invalid8"), "inconsistent usages of event `SomeEvent`: extended type of param #0 mismatch")
|
check(t, filepath.Join("testdata", "rpcbindings", "invalid4"), "inconsistent usages of event `SomeEvent`: extended type of param #0 mismatch")
|
||||||
})
|
})
|
||||||
t.Run("named types redeclare", func(t *testing.T) {
|
t.Run("named types redeclare", func(t *testing.T) {
|
||||||
check(t, filepath.Join("testdata", "invalid9"), "configured declared named type intersects with the contract's one: `invalid9.NamedStruct`")
|
check(t, filepath.Join("testdata", "rpcbindings", "invalid5"), "configured declared named type intersects with the contract's one: `invalid5.NamedStruct`")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGenerateRPCBindings_Errors(t *testing.T) {
|
||||||
|
app := cli.NewApp()
|
||||||
|
app.Commands = NewCommands()
|
||||||
|
app.ExitErrHandler = func(*cli.Context, error) {}
|
||||||
|
|
||||||
|
t.Run("duplicating resulting fields", func(t *testing.T) {
|
||||||
|
check := func(t *testing.T, packageName string, autogen bool, expectedError string) {
|
||||||
|
tmpDir := t.TempDir()
|
||||||
|
source := filepath.Join("testdata", "rpcbindings", packageName)
|
||||||
|
configFile := filepath.Join(source, "invalid.yml")
|
||||||
|
out := filepath.Join(tmpDir, "rpcbindings.out")
|
||||||
|
manifestF := filepath.Join(tmpDir, "manifest.json")
|
||||||
|
bindingF := filepath.Join(tmpDir, "binding.yml")
|
||||||
|
nefF := filepath.Join(tmpDir, "out.nef")
|
||||||
|
cmd := []string{"", "contract", "compile",
|
||||||
|
"--in", source,
|
||||||
|
"--config", configFile,
|
||||||
|
"--manifest", manifestF,
|
||||||
|
"--bindings", bindingF,
|
||||||
|
"--out", nefF,
|
||||||
|
}
|
||||||
|
if autogen {
|
||||||
|
cmd = append(cmd, "--guess-eventtypes")
|
||||||
|
}
|
||||||
|
require.NoError(t, app.Run(cmd))
|
||||||
|
|
||||||
|
cmds := []string{"", "contract", "generate-rpcwrapper",
|
||||||
|
"--config", bindingF,
|
||||||
|
"--manifest", manifestF,
|
||||||
|
"--out", out,
|
||||||
|
}
|
||||||
|
err := app.Run(cmds)
|
||||||
|
require.Error(t, err)
|
||||||
|
require.True(t, strings.Contains(err.Error(), expectedError), err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Run("event", func(t *testing.T) {
|
||||||
|
check(t, "invalid6", false, "error during generation: named type `SomeStruct` has two fields with identical resulting binding name `Field`")
|
||||||
|
})
|
||||||
|
t.Run("autogen event", func(t *testing.T) {
|
||||||
|
check(t, "invalid7", true, "error during generation: named type `invalid7.SomeStruct` has two fields with identical resulting binding name `Field`")
|
||||||
|
})
|
||||||
|
t.Run("struct", func(t *testing.T) {
|
||||||
|
check(t, "invalid8", false, "error during generation: named type `invalid8.SomeStruct` has two fields with identical resulting binding name `Field`")
|
||||||
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/cli/cmdargs"
|
"github.com/nspcc-dev/neo-go/cli/cmdargs"
|
||||||
"github.com/nspcc-dev/neo-go/cli/flags"
|
"github.com/nspcc-dev/neo-go/cli/flags"
|
||||||
|
"github.com/nspcc-dev/neo-go/cli/options"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/state"
|
"github.com/nspcc-dev/neo-go/pkg/core/state"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/nef"
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract/nef"
|
||||||
|
@ -37,7 +38,7 @@ func manifestAddGroup(ctx *cli.Context) error {
|
||||||
|
|
||||||
h := state.CreateContractHash(sender, nf.Checksum, m.Name)
|
h := state.CreateContractHash(sender, nf.Checksum, m.Name)
|
||||||
|
|
||||||
gAcc, w, err := getAccFromContext(ctx)
|
gAcc, w, err := options.GetAccFromContext(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(fmt.Errorf("can't get account to sign group with: %w", err), 1)
|
return cli.NewExitError(fmt.Errorf("can't get account to sign group with: %w", err), 1)
|
||||||
}
|
}
|
||||||
|
@ -109,7 +110,7 @@ func readManifest(filename string, hash util.Uint160) (*manifest.Manifest, []byt
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
if err := m.IsValid(hash); err != nil {
|
if err := m.IsValid(hash, true); err != nil {
|
||||||
return nil, nil, fmt.Errorf("manifest is invalid: %w", err)
|
return nil, nil, fmt.Errorf("manifest is invalid: %w", err)
|
||||||
}
|
}
|
||||||
return m, manifestBytes, nil
|
return m, manifestBytes, nil
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package smartcontract
|
package smartcontract
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/hex"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
@ -28,10 +27,9 @@ func (p permission) MarshalYAML() (any, error) {
|
||||||
&yaml.Node{Kind: yaml.ScalarNode, Value: permHashKey},
|
&yaml.Node{Kind: yaml.ScalarNode, Value: permHashKey},
|
||||||
&yaml.Node{Kind: yaml.ScalarNode, Value: p.Contract.Value.(util.Uint160).StringLE()})
|
&yaml.Node{Kind: yaml.ScalarNode, Value: p.Contract.Value.(util.Uint160).StringLE()})
|
||||||
case manifest.PermissionGroup:
|
case manifest.PermissionGroup:
|
||||||
bs := p.Contract.Value.(*keys.PublicKey).Bytes()
|
|
||||||
m.Content = append(m.Content,
|
m.Content = append(m.Content,
|
||||||
&yaml.Node{Kind: yaml.ScalarNode, Value: permGroupKey},
|
&yaml.Node{Kind: yaml.ScalarNode, Value: permGroupKey},
|
||||||
&yaml.Node{Kind: yaml.ScalarNode, Value: hex.EncodeToString(bs)})
|
&yaml.Node{Kind: yaml.ScalarNode, Value: p.Contract.Value.(*keys.PublicKey).StringCompressed()})
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("invalid permission type: %d", p.Contract.Type)
|
return nil, fmt.Errorf("invalid permission type: %d", p.Contract.Type)
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,14 +11,11 @@ import (
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/cli/cmdargs"
|
"github.com/nspcc-dev/neo-go/cli/cmdargs"
|
||||||
"github.com/nspcc-dev/neo-go/cli/flags"
|
"github.com/nspcc-dev/neo-go/cli/flags"
|
||||||
"github.com/nspcc-dev/neo-go/cli/input"
|
|
||||||
"github.com/nspcc-dev/neo-go/cli/options"
|
"github.com/nspcc-dev/neo-go/cli/options"
|
||||||
"github.com/nspcc-dev/neo-go/cli/txctx"
|
"github.com/nspcc-dev/neo-go/cli/txctx"
|
||||||
cliwallet "github.com/nspcc-dev/neo-go/cli/wallet"
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/compiler"
|
"github.com/nspcc-dev/neo-go/pkg/compiler"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/state"
|
"github.com/nspcc-dev/neo-go/pkg/core/state"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/neorpc/result"
|
"github.com/nspcc-dev/neo-go/pkg/neorpc/result"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/rpcclient/actor"
|
"github.com/nspcc-dev/neo-go/pkg/rpcclient/actor"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/rpcclient/invoker"
|
"github.com/nspcc-dev/neo-go/pkg/rpcclient/invoker"
|
||||||
|
@ -43,20 +40,9 @@ var (
|
||||||
errNoConfFile = errors.New("no config file was found, specify a config file with the '--config' or '-c' flag")
|
errNoConfFile = errors.New("no config file was found, specify a config file with the '--config' or '-c' flag")
|
||||||
errNoManifestFile = errors.New("no manifest file was found, specify manifest file with '--manifest' or '-m' flag")
|
errNoManifestFile = errors.New("no manifest file was found, specify manifest file with '--manifest' or '-m' flag")
|
||||||
errNoMethod = errors.New("no method specified for function invocation command")
|
errNoMethod = errors.New("no method specified for function invocation command")
|
||||||
errNoWallet = errors.New("no wallet parameter found, specify it with the '--wallet' or '-w' flag or specify wallet config file with the '--wallet-config' flag")
|
|
||||||
errConflictingWalletFlags = errors.New("--wallet flag conflicts with --wallet-config flag, please, provide one of them to specify wallet location")
|
|
||||||
errNoScriptHash = errors.New("no smart contract hash was provided, specify one as the first argument")
|
errNoScriptHash = errors.New("no smart contract hash was provided, specify one as the first argument")
|
||||||
errNoSmartContractName = errors.New("no name was provided, specify the '--name or -n' flag")
|
errNoSmartContractName = errors.New("no name was provided, specify the '--name or -n' flag")
|
||||||
errFileExist = errors.New("A file with given smart-contract name already exists")
|
errFileExist = errors.New("A file with given smart-contract name already exists")
|
||||||
|
|
||||||
walletFlag = cli.StringFlag{
|
|
||||||
Name: "wallet, w",
|
|
||||||
Usage: "wallet to use to get the key for transaction signing; conflicts with --wallet-config flag",
|
|
||||||
}
|
|
||||||
walletConfigFlag = cli.StringFlag{
|
|
||||||
Name: "wallet-config",
|
|
||||||
Usage: "path to wallet config to use to get the key for transaction signing; conflicts with --wallet flag",
|
|
||||||
}
|
|
||||||
addressFlag = flags.AddressFlag{
|
addressFlag = flags.AddressFlag{
|
||||||
Name: addressFlagName,
|
Name: addressFlagName,
|
||||||
Usage: "address to use as transaction signee (and gas source)",
|
Usage: "address to use as transaction signee (and gas source)",
|
||||||
|
@ -100,14 +86,14 @@ func NewCommands() []cli.Command {
|
||||||
testInvokeFunctionFlags := []cli.Flag{options.Historic}
|
testInvokeFunctionFlags := []cli.Flag{options.Historic}
|
||||||
testInvokeFunctionFlags = append(testInvokeFunctionFlags, options.RPC...)
|
testInvokeFunctionFlags = append(testInvokeFunctionFlags, options.RPC...)
|
||||||
invokeFunctionFlags := []cli.Flag{
|
invokeFunctionFlags := []cli.Flag{
|
||||||
walletFlag,
|
|
||||||
walletConfigFlag,
|
|
||||||
addressFlag,
|
addressFlag,
|
||||||
txctx.GasFlag,
|
txctx.GasFlag,
|
||||||
txctx.SysGasFlag,
|
txctx.SysGasFlag,
|
||||||
txctx.OutFlag,
|
txctx.OutFlag,
|
||||||
txctx.ForceFlag,
|
txctx.ForceFlag,
|
||||||
|
txctx.AwaitFlag,
|
||||||
}
|
}
|
||||||
|
invokeFunctionFlags = append(invokeFunctionFlags, options.Wallet...)
|
||||||
invokeFunctionFlags = append(invokeFunctionFlags, options.RPC...)
|
invokeFunctionFlags = append(invokeFunctionFlags, options.RPC...)
|
||||||
deployFlags := append(invokeFunctionFlags, []cli.Flag{
|
deployFlags := append(invokeFunctionFlags, []cli.Flag{
|
||||||
cli.StringFlag{
|
cli.StringFlag{
|
||||||
|
@ -119,6 +105,24 @@ func NewCommands() []cli.Command {
|
||||||
Usage: "Manifest input file (*.manifest.json)",
|
Usage: "Manifest input file (*.manifest.json)",
|
||||||
},
|
},
|
||||||
}...)
|
}...)
|
||||||
|
manifestAddGroupFlags := append([]cli.Flag{
|
||||||
|
cli.StringFlag{
|
||||||
|
Name: "sender, s",
|
||||||
|
Usage: "deploy transaction sender",
|
||||||
|
},
|
||||||
|
flags.AddressFlag{
|
||||||
|
Name: addressFlagName, // use the same name for handler code unification.
|
||||||
|
Usage: "account to sign group with",
|
||||||
|
},
|
||||||
|
cli.StringFlag{
|
||||||
|
Name: "nef, n",
|
||||||
|
Usage: "path to the NEF file",
|
||||||
|
},
|
||||||
|
cli.StringFlag{
|
||||||
|
Name: "manifest, m",
|
||||||
|
Usage: "path to the manifest",
|
||||||
|
},
|
||||||
|
}, options.Wallet...)
|
||||||
return []cli.Command{{
|
return []cli.Command{{
|
||||||
Name: "contract",
|
Name: "contract",
|
||||||
Usage: "compile - debug - deploy smart contracts",
|
Usage: "compile - debug - deploy smart contracts",
|
||||||
|
@ -133,7 +137,8 @@ func NewCommands() []cli.Command {
|
||||||
then the output filenames for these flags will be guessed using the contract
|
then the output filenames for these flags will be guessed using the contract
|
||||||
name or path provided via --in option by trimming/adding corresponding suffixes
|
name or path provided via --in option by trimming/adding corresponding suffixes
|
||||||
to the common part of the path. In the latter case the configuration filepath
|
to the common part of the path. In the latter case the configuration filepath
|
||||||
will be guessed from the --in option using the same rule."`,
|
will be guessed from the --in option using the same rule.
|
||||||
|
`,
|
||||||
Action: contractCompile,
|
Action: contractCompile,
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
cli.StringFlag{
|
cli.StringFlag{
|
||||||
|
@ -185,10 +190,12 @@ func NewCommands() []cli.Command {
|
||||||
{
|
{
|
||||||
Name: "deploy",
|
Name: "deploy",
|
||||||
Usage: "deploy a smart contract (.nef with description)",
|
Usage: "deploy a smart contract (.nef with description)",
|
||||||
UsageText: "neo-go contract deploy -r endpoint -w wallet [-a address] [-g gas] [-e sysgas] --in contract.nef --manifest contract.manifest.json [--out file] [--force] [data]",
|
UsageText: "neo-go contract deploy -r endpoint -w wallet [-a address] [-g gas] [-e sysgas] --in contract.nef --manifest contract.manifest.json [--out file] [--force] [--await] [data]",
|
||||||
Description: `Deploys given contract into the chain. The gas parameter is for additional
|
Description: `Deploys given contract into the chain. The gas parameter is for additional
|
||||||
gas to be added as a network fee to prioritize the transaction. The data
|
gas to be added as a network fee to prioritize the transaction. The data
|
||||||
parameter is an optional parameter to be passed to '_deploy' method.
|
parameter is an optional parameter to be passed to '_deploy' method. When
|
||||||
|
--await flag is specified, it waits for the transaction to be included
|
||||||
|
in a block.
|
||||||
`,
|
`,
|
||||||
Action: contractDeploy,
|
Action: contractDeploy,
|
||||||
Flags: deployFlags,
|
Flags: deployFlags,
|
||||||
|
@ -198,13 +205,14 @@ func NewCommands() []cli.Command {
|
||||||
{
|
{
|
||||||
Name: "invokefunction",
|
Name: "invokefunction",
|
||||||
Usage: "invoke deployed contract on the blockchain",
|
Usage: "invoke deployed contract on the blockchain",
|
||||||
UsageText: "neo-go contract invokefunction -r endpoint -w wallet [-a address] [-g gas] [-e sysgas] [--out file] [--force] scripthash [method] [arguments...] [--] [signers...]",
|
UsageText: "neo-go contract invokefunction -r endpoint -w wallet [-a address] [-g gas] [-e sysgas] [--out file] [--force] [--await] scripthash [method] [arguments...] [--] [signers...]",
|
||||||
Description: `Executes given (as a script hash) deployed script with the given method,
|
Description: `Executes given (as a script hash) deployed script with the given method,
|
||||||
arguments and signers. Sender is included in the list of signers by default
|
arguments and signers. Sender is included in the list of signers by default
|
||||||
with None witness scope. If you'd like to change default sender's scope,
|
with None witness scope. If you'd like to change default sender's scope,
|
||||||
specify it via signers parameter. See testinvokefunction documentation for
|
specify it via signers parameter. See testinvokefunction documentation for
|
||||||
the details about parameters. It differs from testinvokefunction in that this
|
the details about parameters. It differs from testinvokefunction in that this
|
||||||
command sends an invocation transaction to the network.
|
command sends an invocation transaction to the network. When --await flag is
|
||||||
|
specified, it waits for the transaction to be included in a block.
|
||||||
`,
|
`,
|
||||||
Action: invokeFunction,
|
Action: invokeFunction,
|
||||||
Flags: invokeFunctionFlags,
|
Flags: invokeFunctionFlags,
|
||||||
|
@ -301,26 +309,7 @@ func NewCommands() []cli.Command {
|
||||||
Usage: "adds group to the manifest",
|
Usage: "adds group to the manifest",
|
||||||
UsageText: "neo-go contract manifest add-group -w wallet [--wallet-config path] -n nef -m manifest -a address -s address",
|
UsageText: "neo-go contract manifest add-group -w wallet [--wallet-config path] -n nef -m manifest -a address -s address",
|
||||||
Action: manifestAddGroup,
|
Action: manifestAddGroup,
|
||||||
Flags: []cli.Flag{
|
Flags: manifestAddGroupFlags,
|
||||||
walletFlag,
|
|
||||||
walletConfigFlag,
|
|
||||||
cli.StringFlag{
|
|
||||||
Name: "sender, s",
|
|
||||||
Usage: "deploy transaction sender",
|
|
||||||
},
|
|
||||||
flags.AddressFlag{
|
|
||||||
Name: addressFlagName, // use the same name for handler code unification.
|
|
||||||
Usage: "account to sign group with",
|
|
||||||
},
|
|
||||||
cli.StringFlag{
|
|
||||||
Name: "nef, n",
|
|
||||||
Usage: "path to the NEF file",
|
|
||||||
},
|
|
||||||
cli.StringFlag{
|
|
||||||
Name: "manifest, m",
|
|
||||||
Usage: "path to the manifest",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -386,6 +375,9 @@ func initSmartContract(ctx *cli.Context) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
gm := []byte("module " + contractName + `
|
gm := []byte("module " + contractName + `
|
||||||
|
|
||||||
|
go 1.20
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/nspcc-dev/neo-go/pkg/interop ` + ver + `
|
github.com/nspcc-dev/neo-go/pkg/interop ` + ver + `
|
||||||
)`)
|
)`)
|
||||||
|
@ -581,7 +573,7 @@ func invokeInternal(ctx *cli.Context, signAndPush bool) error {
|
||||||
w *wallet.Wallet
|
w *wallet.Wallet
|
||||||
)
|
)
|
||||||
if signAndPush {
|
if signAndPush {
|
||||||
acc, w, err = getAccFromContext(ctx)
|
acc, w, err = options.GetAccFromContext(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.NewExitError(err, 1)
|
||||||
}
|
}
|
||||||
|
@ -608,19 +600,14 @@ func invokeWithArgs(ctx *cli.Context, acc *wallet.Account, wall *wallet.Wallet,
|
||||||
}
|
}
|
||||||
gctx, cancel := options.GetTimeoutContext(ctx)
|
gctx, cancel := options.GetTimeoutContext(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
if signAndPush {
|
||||||
c, err := options.GetRPCClient(gctx, ctx)
|
_, act, err = options.GetRPCWithActor(gctx, ctx, signersAccounts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if signAndPush {
|
|
||||||
act, err = actor.New(c, signersAccounts)
|
|
||||||
if err != nil {
|
|
||||||
return cli.NewExitError(fmt.Errorf("failed to create RPC actor: %w", err), 1)
|
|
||||||
}
|
|
||||||
inv = &act.Invoker
|
inv = &act.Invoker
|
||||||
} else {
|
} else {
|
||||||
inv, err = options.GetInvoker(c, ctx, cosigners)
|
_, inv, err = options.GetRPCWithInvoker(gctx, ctx, cosigners)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -757,68 +744,6 @@ func inspect(ctx *cli.Context) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getAccFromContext(ctx *cli.Context) (*wallet.Account, *wallet.Wallet, error) {
|
|
||||||
var addr util.Uint160
|
|
||||||
|
|
||||||
wPath := ctx.String("wallet")
|
|
||||||
walletConfigPath := ctx.String("wallet-config")
|
|
||||||
if len(wPath) != 0 && len(walletConfigPath) != 0 {
|
|
||||||
return nil, nil, errConflictingWalletFlags
|
|
||||||
}
|
|
||||||
if len(wPath) == 0 && len(walletConfigPath) == 0 {
|
|
||||||
return nil, nil, errNoWallet
|
|
||||||
}
|
|
||||||
var pass *string
|
|
||||||
if len(walletConfigPath) != 0 {
|
|
||||||
cfg, err := cliwallet.ReadWalletConfig(walletConfigPath)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
wPath = cfg.Path
|
|
||||||
pass = &cfg.Password
|
|
||||||
}
|
|
||||||
|
|
||||||
wall, err := wallet.NewWalletFromFile(wPath)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
addrFlag := ctx.Generic("address").(*flags.Address)
|
|
||||||
if addrFlag.IsSet {
|
|
||||||
addr = addrFlag.Uint160()
|
|
||||||
} else {
|
|
||||||
addr = wall.GetChangeAddress()
|
|
||||||
}
|
|
||||||
|
|
||||||
acc, err := getUnlockedAccount(wall, addr, pass)
|
|
||||||
return acc, wall, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func getUnlockedAccount(wall *wallet.Wallet, addr util.Uint160, pass *string) (*wallet.Account, error) {
|
|
||||||
acc := wall.GetAccount(addr)
|
|
||||||
if acc == nil {
|
|
||||||
return nil, fmt.Errorf("wallet contains no account for '%s'", address.Uint160ToString(addr))
|
|
||||||
}
|
|
||||||
|
|
||||||
if acc.CanSign() {
|
|
||||||
return acc, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if pass == nil {
|
|
||||||
rawPass, err := input.ReadPassword(
|
|
||||||
fmt.Sprintf("Enter account %s password > ", address.Uint160ToString(addr)))
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("Error reading password: %w", err)
|
|
||||||
}
|
|
||||||
trimmed := strings.TrimRight(string(rawPass), "\n")
|
|
||||||
pass = &trimmed
|
|
||||||
}
|
|
||||||
err := acc.Decrypt(*pass, wall.Scrypt)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return acc, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// contractDeploy deploys contract.
|
// contractDeploy deploys contract.
|
||||||
func contractDeploy(ctx *cli.Context) error {
|
func contractDeploy(ctx *cli.Context) error {
|
||||||
nefFile, f, err := readNEFFile(ctx.String("in"))
|
nefFile, f, err := readNEFFile(ctx.String("in"))
|
||||||
|
@ -844,7 +769,7 @@ func contractDeploy(ctx *cli.Context) error {
|
||||||
appCallParams = append(appCallParams, data[0])
|
appCallParams = append(appCallParams, data[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
acc, w, err := getAccFromContext(ctx)
|
acc, w, err := options.GetAccFromContext(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(fmt.Errorf("can't get sender address: %w", err), 1)
|
return cli.NewExitError(fmt.Errorf("can't get sender address: %w", err), 1)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package smartcontract
|
package smartcontract
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/hex"
|
|
||||||
"flag"
|
"flag"
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
@ -109,7 +108,7 @@ func TestPermissionMarshal(t *testing.T) {
|
||||||
p.Methods.Add("abc")
|
p.Methods.Add("abc")
|
||||||
p.Methods.Add("lamao")
|
p.Methods.Add("lamao")
|
||||||
testPermissionMarshal(t, p,
|
testPermissionMarshal(t, p,
|
||||||
"group: "+hex.EncodeToString(priv.PublicKey().Bytes())+"\n"+
|
"group: "+priv.PublicKey().StringCompressed()+"\n"+
|
||||||
"methods:\n - abc\n - lamao\n")
|
"methods:\n - abc\n - lamao\n")
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -118,7 +117,7 @@ func TestPermissionUnmarshalInvalid(t *testing.T) {
|
||||||
priv, err := keys.NewPrivateKey()
|
priv, err := keys.NewPrivateKey()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
pub := hex.EncodeToString(priv.PublicKey().Bytes())
|
pub := priv.PublicKey().StringCompressed()
|
||||||
u160 := random.Uint160().StringLE()
|
u160 := random.Uint160().StringLE()
|
||||||
testCases := []string{
|
testCases := []string{
|
||||||
"hash: []\nmethods: '*'\n", // invalid hash type
|
"hash: []\nmethods: '*'\n", // invalid hash type
|
||||||
|
|
2
cli/smartcontract/testdata/gas/gas.go
vendored
2
cli/smartcontract/testdata/gas/gas.go
vendored
|
@ -1,3 +1,5 @@
|
||||||
|
// Code generated by neo-go contract generate-rpcwrapper --manifest <file.json> --out <file.go> [--hash <hash>] [--config <config>]; DO NOT EDIT.
|
||||||
|
|
||||||
// Package gastoken contains RPC wrappers for GasToken contract.
|
// Package gastoken contains RPC wrappers for GasToken contract.
|
||||||
package gastoken
|
package gastoken
|
||||||
|
|
||||||
|
|
30
cli/smartcontract/testdata/nameservice/nns.go
vendored
30
cli/smartcontract/testdata/nameservice/nns.go
vendored
|
@ -1,3 +1,5 @@
|
||||||
|
// Code generated by neo-go contract generate-rpcwrapper --manifest <file.json> --out <file.go> [--hash <hash>] [--config <config>]; DO NOT EDIT.
|
||||||
|
|
||||||
// Package nameservice contains RPC wrappers for NameService contract.
|
// Package nameservice contains RPC wrappers for NameService contract.
|
||||||
package nameservice
|
package nameservice
|
||||||
|
|
||||||
|
@ -254,25 +256,25 @@ func (c *Contract) RenewUnsigned(name string) (*transaction.Transaction, error)
|
||||||
return c.actor.MakeUnsignedCall(c.hash, "renew", nil, name)
|
return c.actor.MakeUnsignedCall(c.hash, "renew", nil, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Renew_2 creates a transaction invoking `renew` method of the contract.
|
// Renew2 creates a transaction invoking `renew` method of the contract.
|
||||||
// This transaction is signed and immediately sent to the network.
|
// This transaction is signed and immediately sent to the network.
|
||||||
// The values returned are its hash, ValidUntilBlock value and error if any.
|
// The values returned are its hash, ValidUntilBlock value and error if any.
|
||||||
func (c *Contract) Renew_2(name string, years *big.Int) (util.Uint256, uint32, error) {
|
func (c *Contract) Renew2(name string, years *big.Int) (util.Uint256, uint32, error) {
|
||||||
return c.actor.SendCall(c.hash, "renew", name, years)
|
return c.actor.SendCall(c.hash, "renew", name, years)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Renew_2Transaction creates a transaction invoking `renew` method of the contract.
|
// Renew2Transaction creates a transaction invoking `renew` method of the contract.
|
||||||
// This transaction is signed, but not sent to the network, instead it's
|
// This transaction is signed, but not sent to the network, instead it's
|
||||||
// returned to the caller.
|
// returned to the caller.
|
||||||
func (c *Contract) Renew_2Transaction(name string, years *big.Int) (*transaction.Transaction, error) {
|
func (c *Contract) Renew2Transaction(name string, years *big.Int) (*transaction.Transaction, error) {
|
||||||
return c.actor.MakeCall(c.hash, "renew", name, years)
|
return c.actor.MakeCall(c.hash, "renew", name, years)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Renew_2Unsigned creates a transaction invoking `renew` method of the contract.
|
// Renew2Unsigned creates a transaction invoking `renew` method of the contract.
|
||||||
// This transaction is not signed, it's simply returned to the caller.
|
// This transaction is not signed, it's simply returned to the caller.
|
||||||
// Any fields of it that do not affect fees can be changed (ValidUntilBlock,
|
// Any fields of it that do not affect fees can be changed (ValidUntilBlock,
|
||||||
// Nonce), fee values (NetworkFee, SystemFee) can be increased as well.
|
// Nonce), fee values (NetworkFee, SystemFee) can be increased as well.
|
||||||
func (c *Contract) Renew_2Unsigned(name string, years *big.Int) (*transaction.Transaction, error) {
|
func (c *Contract) Renew2Unsigned(name string, years *big.Int) (*transaction.Transaction, error) {
|
||||||
return c.actor.MakeUnsignedCall(c.hash, "renew", nil, name, years)
|
return c.actor.MakeUnsignedCall(c.hash, "renew", nil, name, years)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -386,7 +388,7 @@ func (e *SetAdminEvent) FromStackItem(item *stackitem.Array) error {
|
||||||
err error
|
err error
|
||||||
)
|
)
|
||||||
index++
|
index++
|
||||||
e.Name, err = func (item stackitem.Item) (string, error) {
|
e.Name, err = func(item stackitem.Item) (string, error) {
|
||||||
b, err := item.TryBytes()
|
b, err := item.TryBytes()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
|
@ -395,13 +397,13 @@ func (e *SetAdminEvent) FromStackItem(item *stackitem.Array) error {
|
||||||
return "", errors.New("not a UTF-8 string")
|
return "", errors.New("not a UTF-8 string")
|
||||||
}
|
}
|
||||||
return string(b), nil
|
return string(b), nil
|
||||||
} (arr[index])
|
}(arr[index])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("field Name: %w", err)
|
return fmt.Errorf("field Name: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
index++
|
index++
|
||||||
e.OldAdmin, err = func (item stackitem.Item) (util.Uint160, error) {
|
e.OldAdmin, err = func(item stackitem.Item) (util.Uint160, error) {
|
||||||
b, err := item.TryBytes()
|
b, err := item.TryBytes()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return util.Uint160{}, err
|
return util.Uint160{}, err
|
||||||
|
@ -411,13 +413,13 @@ func (e *SetAdminEvent) FromStackItem(item *stackitem.Array) error {
|
||||||
return util.Uint160{}, err
|
return util.Uint160{}, err
|
||||||
}
|
}
|
||||||
return u, nil
|
return u, nil
|
||||||
} (arr[index])
|
}(arr[index])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("field OldAdmin: %w", err)
|
return fmt.Errorf("field OldAdmin: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
index++
|
index++
|
||||||
e.NewAdmin, err = func (item stackitem.Item) (util.Uint160, error) {
|
e.NewAdmin, err = func(item stackitem.Item) (util.Uint160, error) {
|
||||||
b, err := item.TryBytes()
|
b, err := item.TryBytes()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return util.Uint160{}, err
|
return util.Uint160{}, err
|
||||||
|
@ -427,7 +429,7 @@ func (e *SetAdminEvent) FromStackItem(item *stackitem.Array) error {
|
||||||
return util.Uint160{}, err
|
return util.Uint160{}, err
|
||||||
}
|
}
|
||||||
return u, nil
|
return u, nil
|
||||||
} (arr[index])
|
}(arr[index])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("field NewAdmin: %w", err)
|
return fmt.Errorf("field NewAdmin: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -479,7 +481,7 @@ func (e *RenewEvent) FromStackItem(item *stackitem.Array) error {
|
||||||
err error
|
err error
|
||||||
)
|
)
|
||||||
index++
|
index++
|
||||||
e.Name, err = func (item stackitem.Item) (string, error) {
|
e.Name, err = func(item stackitem.Item) (string, error) {
|
||||||
b, err := item.TryBytes()
|
b, err := item.TryBytes()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
|
@ -488,7 +490,7 @@ func (e *RenewEvent) FromStackItem(item *stackitem.Array) error {
|
||||||
return "", errors.New("not a UTF-8 string")
|
return "", errors.New("not a UTF-8 string")
|
||||||
}
|
}
|
||||||
return string(b), nil
|
return string(b), nil
|
||||||
} (arr[index])
|
}(arr[index])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("field Name: %w", err)
|
return fmt.Errorf("field Name: %w", err)
|
||||||
}
|
}
|
||||||
|
|
10
cli/smartcontract/testdata/nex/nex.go
vendored
10
cli/smartcontract/testdata/nex/nex.go
vendored
|
@ -1,3 +1,5 @@
|
||||||
|
// Code generated by neo-go contract generate-rpcwrapper --manifest <file.json> --out <file.go> [--hash <hash>] [--config <config>]; DO NOT EDIT.
|
||||||
|
|
||||||
// Package nextoken contains RPC wrappers for NEX Token contract.
|
// Package nextoken contains RPC wrappers for NEX Token contract.
|
||||||
package nextoken
|
package nextoken
|
||||||
|
|
||||||
|
@ -290,7 +292,7 @@ func (e *OnMintEvent) FromStackItem(item *stackitem.Array) error {
|
||||||
err error
|
err error
|
||||||
)
|
)
|
||||||
index++
|
index++
|
||||||
e.From, err = func (item stackitem.Item) (util.Uint160, error) {
|
e.From, err = func(item stackitem.Item) (util.Uint160, error) {
|
||||||
b, err := item.TryBytes()
|
b, err := item.TryBytes()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return util.Uint160{}, err
|
return util.Uint160{}, err
|
||||||
|
@ -300,13 +302,13 @@ func (e *OnMintEvent) FromStackItem(item *stackitem.Array) error {
|
||||||
return util.Uint160{}, err
|
return util.Uint160{}, err
|
||||||
}
|
}
|
||||||
return u, nil
|
return u, nil
|
||||||
} (arr[index])
|
}(arr[index])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("field From: %w", err)
|
return fmt.Errorf("field From: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
index++
|
index++
|
||||||
e.To, err = func (item stackitem.Item) (util.Uint160, error) {
|
e.To, err = func(item stackitem.Item) (util.Uint160, error) {
|
||||||
b, err := item.TryBytes()
|
b, err := item.TryBytes()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return util.Uint160{}, err
|
return util.Uint160{}, err
|
||||||
|
@ -316,7 +318,7 @@ func (e *OnMintEvent) FromStackItem(item *stackitem.Array) error {
|
||||||
return util.Uint160{}, err
|
return util.Uint160{}, err
|
||||||
}
|
}
|
||||||
return u, nil
|
return u, nil
|
||||||
} (arr[index])
|
}(arr[index])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("field To: %w", err)
|
return fmt.Errorf("field To: %w", err)
|
||||||
}
|
}
|
||||||
|
|
2
cli/smartcontract/testdata/nonepiter/iter.go
vendored
2
cli/smartcontract/testdata/nonepiter/iter.go
vendored
|
@ -1,3 +1,5 @@
|
||||||
|
// Code generated by neo-go contract generate-rpcwrapper --manifest <file.json> --out <file.go> [--hash <hash>] [--config <config>]; DO NOT EDIT.
|
||||||
|
|
||||||
// Package nonnepxxcontractwithiterators contains RPC wrappers for Non-NEPXX contract with iterators contract.
|
// Package nonnepxxcontractwithiterators contains RPC wrappers for Non-NEPXX contract with iterators contract.
|
||||||
package nonnepxxcontractwithiterators
|
package nonnepxxcontractwithiterators
|
||||||
|
|
||||||
|
|
1032
cli/smartcontract/testdata/notifications/rpcbindings.out
vendored
1032
cli/smartcontract/testdata/notifications/rpcbindings.out
vendored
File diff suppressed because it is too large
Load diff
|
@ -1,4 +1,4 @@
|
||||||
package invalid5
|
package invalid1
|
||||||
|
|
||||||
import "github.com/nspcc-dev/neo-go/pkg/interop/runtime"
|
import "github.com/nspcc-dev/neo-go/pkg/interop/runtime"
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package invalid6
|
package invalid2
|
||||||
|
|
||||||
import "github.com/nspcc-dev/neo-go/pkg/interop/runtime"
|
import "github.com/nspcc-dev/neo-go/pkg/interop/runtime"
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package invalid7
|
package invalid3
|
||||||
|
|
||||||
import "github.com/nspcc-dev/neo-go/pkg/interop/runtime"
|
import "github.com/nspcc-dev/neo-go/pkg/interop/runtime"
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package invalid8
|
package invalid4
|
||||||
|
|
||||||
import "github.com/nspcc-dev/neo-go/pkg/interop/runtime"
|
import "github.com/nspcc-dev/neo-go/pkg/interop/runtime"
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package invalid9
|
package invalid5
|
||||||
|
|
||||||
import "github.com/nspcc-dev/neo-go/pkg/interop/runtime"
|
import "github.com/nspcc-dev/neo-go/pkg/interop/runtime"
|
||||||
|
|
|
@ -6,11 +6,11 @@ events:
|
||||||
type: Array
|
type: Array
|
||||||
extendedtype:
|
extendedtype:
|
||||||
base: Array
|
base: Array
|
||||||
name: invalid9.NamedStruct
|
name: invalid5.NamedStruct
|
||||||
namedtypes:
|
namedtypes:
|
||||||
invalid9.NamedStruct:
|
invalid5.NamedStruct:
|
||||||
base: Array
|
base: Array
|
||||||
name: invalid9.NamedStruct
|
name: invalid5.NamedStruct
|
||||||
fields:
|
fields:
|
||||||
- field: SomeInt
|
- field: SomeInt
|
||||||
base: Integer
|
base: Integer
|
14
cli/smartcontract/testdata/rpcbindings/invalid6/invalid.go
vendored
Normal file
14
cli/smartcontract/testdata/rpcbindings/invalid6/invalid.go
vendored
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
package invalid6
|
||||||
|
|
||||||
|
import "github.com/nspcc-dev/neo-go/pkg/interop/runtime"
|
||||||
|
|
||||||
|
type SomeStruct struct {
|
||||||
|
Field int
|
||||||
|
// RPC binding generator will convert this field into exported, which matches
|
||||||
|
// exactly the existing Field.
|
||||||
|
field int
|
||||||
|
}
|
||||||
|
|
||||||
|
func Main() {
|
||||||
|
runtime.Notify("SomeEvent", SomeStruct{Field: 123, field: 123})
|
||||||
|
}
|
18
cli/smartcontract/testdata/rpcbindings/invalid6/invalid.yml
vendored
Normal file
18
cli/smartcontract/testdata/rpcbindings/invalid6/invalid.yml
vendored
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
name: Test duplicating event fields
|
||||||
|
events:
|
||||||
|
- name: SomeEvent
|
||||||
|
parameters:
|
||||||
|
- name: p1
|
||||||
|
type: Struct
|
||||||
|
extendedtype:
|
||||||
|
base: Struct
|
||||||
|
name: SomeStruct
|
||||||
|
namedtypes:
|
||||||
|
SomeStruct:
|
||||||
|
base: Struct
|
||||||
|
name: SomeStruct
|
||||||
|
fields:
|
||||||
|
- field: Field
|
||||||
|
base: Integer
|
||||||
|
- field: field
|
||||||
|
base: Integer
|
14
cli/smartcontract/testdata/rpcbindings/invalid7/invalid.go
vendored
Normal file
14
cli/smartcontract/testdata/rpcbindings/invalid7/invalid.go
vendored
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
package invalid7
|
||||||
|
|
||||||
|
import "github.com/nspcc-dev/neo-go/pkg/interop/runtime"
|
||||||
|
|
||||||
|
type SomeStruct struct {
|
||||||
|
Field int
|
||||||
|
// RPC binding generator will convert this field into exported, which matches
|
||||||
|
// exactly the existing Field.
|
||||||
|
field int
|
||||||
|
}
|
||||||
|
|
||||||
|
func Main() {
|
||||||
|
runtime.Notify("SomeEvent", SomeStruct{Field: 123, field: 123})
|
||||||
|
}
|
6
cli/smartcontract/testdata/rpcbindings/invalid7/invalid.yml
vendored
Normal file
6
cli/smartcontract/testdata/rpcbindings/invalid7/invalid.yml
vendored
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
name: Test duplicating autogenerated event fields
|
||||||
|
events:
|
||||||
|
- name: SomeEvent
|
||||||
|
parameters:
|
||||||
|
- name: p1
|
||||||
|
type: Struct
|
16
cli/smartcontract/testdata/rpcbindings/invalid8/invalid.go
vendored
Normal file
16
cli/smartcontract/testdata/rpcbindings/invalid8/invalid.go
vendored
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
package invalid8
|
||||||
|
|
||||||
|
type SomeStruct struct {
|
||||||
|
Field int
|
||||||
|
// RPC binding generator will convert this field into exported, which matches
|
||||||
|
// exactly the existing Field.
|
||||||
|
field int
|
||||||
|
}
|
||||||
|
|
||||||
|
func Main() SomeStruct {
|
||||||
|
s := SomeStruct{
|
||||||
|
Field: 1,
|
||||||
|
field: 2,
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
1
cli/smartcontract/testdata/rpcbindings/invalid8/invalid.yml
vendored
Normal file
1
cli/smartcontract/testdata/rpcbindings/invalid8/invalid.yml
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
name: Test duplicating struct fields
|
|
@ -17,3 +17,7 @@ events:
|
||||||
parameters:
|
parameters:
|
||||||
- name: a
|
- name: a
|
||||||
type: Array
|
type: Array
|
||||||
|
- name: "SomeUnexportedField"
|
||||||
|
parameters:
|
||||||
|
- name: s
|
||||||
|
type: Struct
|
|
@ -36,6 +36,13 @@ events:
|
||||||
base: Array
|
base: Array
|
||||||
value:
|
value:
|
||||||
base: Integer
|
base: Integer
|
||||||
|
- name: "SomeUnexportedField"
|
||||||
|
parameters:
|
||||||
|
- name: s
|
||||||
|
type: Struct
|
||||||
|
extendedtype:
|
||||||
|
base: Struct
|
||||||
|
name: simpleStruct
|
||||||
namedtypes:
|
namedtypes:
|
||||||
crazyStruct:
|
crazyStruct:
|
||||||
base: Struct
|
base: Struct
|
||||||
|
@ -45,3 +52,9 @@ namedtypes:
|
||||||
base: Integer
|
base: Integer
|
||||||
- field: B
|
- field: B
|
||||||
base: Boolean
|
base: Boolean
|
||||||
|
simpleStruct:
|
||||||
|
base: Struct
|
||||||
|
name: simpleStruct
|
||||||
|
fields:
|
||||||
|
- field: i
|
||||||
|
base: Integer
|
|
@ -17,3 +17,7 @@ events:
|
||||||
parameters:
|
parameters:
|
||||||
- name: a
|
- name: a
|
||||||
type: Array
|
type: Array
|
||||||
|
- name: "SomeUnexportedField"
|
||||||
|
parameters:
|
||||||
|
- name: s
|
||||||
|
type: Struct
|
|
@ -23,3 +23,11 @@ func Struct() {
|
||||||
func Array() {
|
func Array() {
|
||||||
runtime.Notify("SomeArray", [][]int{})
|
runtime.Notify("SomeArray", [][]int{})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UnexportedField emits notification with unexported field that must be converted
|
||||||
|
// to exported in the resulting RPC binding.
|
||||||
|
func UnexportedField() {
|
||||||
|
runtime.Notify("SomeUnexportedField", struct {
|
||||||
|
i int
|
||||||
|
}{i: 123})
|
||||||
|
}
|
500
cli/smartcontract/testdata/rpcbindings/notifications/rpcbindings.out
vendored
Normal file
500
cli/smartcontract/testdata/rpcbindings/notifications/rpcbindings.out
vendored
Normal file
|
@ -0,0 +1,500 @@
|
||||||
|
// Code generated by neo-go contract generate-rpcwrapper --manifest <file.json> --out <file.go> [--hash <hash>] [--config <config>]; DO NOT EDIT.
|
||||||
|
|
||||||
|
// Package structs contains RPC wrappers for Notifications contract.
|
||||||
|
package structs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/neorpc/result"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||||
|
"unicode/utf8"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Hash contains contract hash.
|
||||||
|
var Hash = util.Uint160{0x33, 0x22, 0x11, 0x0, 0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x0}
|
||||||
|
|
||||||
|
// ComplicatedNameEvent represents "! complicated name %$#" event emitted by the contract.
|
||||||
|
type ComplicatedNameEvent struct {
|
||||||
|
ComplicatedParam string
|
||||||
|
}
|
||||||
|
|
||||||
|
// SomeMapEvent represents "SomeMap" event emitted by the contract.
|
||||||
|
type SomeMapEvent struct {
|
||||||
|
M map[any]any
|
||||||
|
}
|
||||||
|
|
||||||
|
// SomeStructEvent represents "SomeStruct" event emitted by the contract.
|
||||||
|
type SomeStructEvent struct {
|
||||||
|
S []any
|
||||||
|
}
|
||||||
|
|
||||||
|
// SomeArrayEvent represents "SomeArray" event emitted by the contract.
|
||||||
|
type SomeArrayEvent struct {
|
||||||
|
A []any
|
||||||
|
}
|
||||||
|
|
||||||
|
// SomeUnexportedFieldEvent represents "SomeUnexportedField" event emitted by the contract.
|
||||||
|
type SomeUnexportedFieldEvent struct {
|
||||||
|
S []any
|
||||||
|
}
|
||||||
|
|
||||||
|
// Actor is used by Contract to call state-changing methods.
|
||||||
|
type Actor interface {
|
||||||
|
MakeCall(contract util.Uint160, method string, params ...any) (*transaction.Transaction, error)
|
||||||
|
MakeRun(script []byte) (*transaction.Transaction, error)
|
||||||
|
MakeUnsignedCall(contract util.Uint160, method string, attrs []transaction.Attribute, params ...any) (*transaction.Transaction, error)
|
||||||
|
MakeUnsignedRun(script []byte, attrs []transaction.Attribute) (*transaction.Transaction, error)
|
||||||
|
SendCall(contract util.Uint160, method string, params ...any) (util.Uint256, uint32, error)
|
||||||
|
SendRun(script []byte) (util.Uint256, uint32, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Contract implements all contract methods.
|
||||||
|
type Contract struct {
|
||||||
|
actor Actor
|
||||||
|
hash util.Uint160
|
||||||
|
}
|
||||||
|
|
||||||
|
// New creates an instance of Contract using Hash and the given Actor.
|
||||||
|
func New(actor Actor) *Contract {
|
||||||
|
var hash = Hash
|
||||||
|
return &Contract{actor, hash}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Array creates a transaction invoking `array` method of the contract.
|
||||||
|
// This transaction is signed and immediately sent to the network.
|
||||||
|
// The values returned are its hash, ValidUntilBlock value and error if any.
|
||||||
|
func (c *Contract) Array() (util.Uint256, uint32, error) {
|
||||||
|
return c.actor.SendCall(c.hash, "array")
|
||||||
|
}
|
||||||
|
|
||||||
|
// ArrayTransaction creates a transaction invoking `array` method of the contract.
|
||||||
|
// This transaction is signed, but not sent to the network, instead it's
|
||||||
|
// returned to the caller.
|
||||||
|
func (c *Contract) ArrayTransaction() (*transaction.Transaction, error) {
|
||||||
|
return c.actor.MakeCall(c.hash, "array")
|
||||||
|
}
|
||||||
|
|
||||||
|
// ArrayUnsigned creates a transaction invoking `array` method of the contract.
|
||||||
|
// This transaction is not signed, it's simply returned to the caller.
|
||||||
|
// Any fields of it that do not affect fees can be changed (ValidUntilBlock,
|
||||||
|
// Nonce), fee values (NetworkFee, SystemFee) can be increased as well.
|
||||||
|
func (c *Contract) ArrayUnsigned() (*transaction.Transaction, error) {
|
||||||
|
return c.actor.MakeUnsignedCall(c.hash, "array", nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CrazyMap creates a transaction invoking `crazyMap` method of the contract.
|
||||||
|
// This transaction is signed and immediately sent to the network.
|
||||||
|
// The values returned are its hash, ValidUntilBlock value and error if any.
|
||||||
|
func (c *Contract) CrazyMap() (util.Uint256, uint32, error) {
|
||||||
|
return c.actor.SendCall(c.hash, "crazyMap")
|
||||||
|
}
|
||||||
|
|
||||||
|
// CrazyMapTransaction creates a transaction invoking `crazyMap` method of the contract.
|
||||||
|
// This transaction is signed, but not sent to the network, instead it's
|
||||||
|
// returned to the caller.
|
||||||
|
func (c *Contract) CrazyMapTransaction() (*transaction.Transaction, error) {
|
||||||
|
return c.actor.MakeCall(c.hash, "crazyMap")
|
||||||
|
}
|
||||||
|
|
||||||
|
// CrazyMapUnsigned creates a transaction invoking `crazyMap` method of the contract.
|
||||||
|
// This transaction is not signed, it's simply returned to the caller.
|
||||||
|
// Any fields of it that do not affect fees can be changed (ValidUntilBlock,
|
||||||
|
// Nonce), fee values (NetworkFee, SystemFee) can be increased as well.
|
||||||
|
func (c *Contract) CrazyMapUnsigned() (*transaction.Transaction, error) {
|
||||||
|
return c.actor.MakeUnsignedCall(c.hash, "crazyMap", nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Main creates a transaction invoking `main` method of the contract.
|
||||||
|
// This transaction is signed and immediately sent to the network.
|
||||||
|
// The values returned are its hash, ValidUntilBlock value and error if any.
|
||||||
|
func (c *Contract) Main() (util.Uint256, uint32, error) {
|
||||||
|
return c.actor.SendCall(c.hash, "main")
|
||||||
|
}
|
||||||
|
|
||||||
|
// MainTransaction creates a transaction invoking `main` method of the contract.
|
||||||
|
// This transaction is signed, but not sent to the network, instead it's
|
||||||
|
// returned to the caller.
|
||||||
|
func (c *Contract) MainTransaction() (*transaction.Transaction, error) {
|
||||||
|
return c.actor.MakeCall(c.hash, "main")
|
||||||
|
}
|
||||||
|
|
||||||
|
// MainUnsigned creates a transaction invoking `main` method of the contract.
|
||||||
|
// This transaction is not signed, it's simply returned to the caller.
|
||||||
|
// Any fields of it that do not affect fees can be changed (ValidUntilBlock,
|
||||||
|
// Nonce), fee values (NetworkFee, SystemFee) can be increased as well.
|
||||||
|
func (c *Contract) MainUnsigned() (*transaction.Transaction, error) {
|
||||||
|
return c.actor.MakeUnsignedCall(c.hash, "main", nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Struct creates a transaction invoking `struct` method of the contract.
|
||||||
|
// This transaction is signed and immediately sent to the network.
|
||||||
|
// The values returned are its hash, ValidUntilBlock value and error if any.
|
||||||
|
func (c *Contract) Struct() (util.Uint256, uint32, error) {
|
||||||
|
return c.actor.SendCall(c.hash, "struct")
|
||||||
|
}
|
||||||
|
|
||||||
|
// StructTransaction creates a transaction invoking `struct` method of the contract.
|
||||||
|
// This transaction is signed, but not sent to the network, instead it's
|
||||||
|
// returned to the caller.
|
||||||
|
func (c *Contract) StructTransaction() (*transaction.Transaction, error) {
|
||||||
|
return c.actor.MakeCall(c.hash, "struct")
|
||||||
|
}
|
||||||
|
|
||||||
|
// StructUnsigned creates a transaction invoking `struct` method of the contract.
|
||||||
|
// This transaction is not signed, it's simply returned to the caller.
|
||||||
|
// Any fields of it that do not affect fees can be changed (ValidUntilBlock,
|
||||||
|
// Nonce), fee values (NetworkFee, SystemFee) can be increased as well.
|
||||||
|
func (c *Contract) StructUnsigned() (*transaction.Transaction, error) {
|
||||||
|
return c.actor.MakeUnsignedCall(c.hash, "struct", nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnexportedField creates a transaction invoking `unexportedField` method of the contract.
|
||||||
|
// This transaction is signed and immediately sent to the network.
|
||||||
|
// The values returned are its hash, ValidUntilBlock value and error if any.
|
||||||
|
func (c *Contract) UnexportedField() (util.Uint256, uint32, error) {
|
||||||
|
return c.actor.SendCall(c.hash, "unexportedField")
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnexportedFieldTransaction creates a transaction invoking `unexportedField` method of the contract.
|
||||||
|
// This transaction is signed, but not sent to the network, instead it's
|
||||||
|
// returned to the caller.
|
||||||
|
func (c *Contract) UnexportedFieldTransaction() (*transaction.Transaction, error) {
|
||||||
|
return c.actor.MakeCall(c.hash, "unexportedField")
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnexportedFieldUnsigned creates a transaction invoking `unexportedField` method of the contract.
|
||||||
|
// This transaction is not signed, it's simply returned to the caller.
|
||||||
|
// Any fields of it that do not affect fees can be changed (ValidUntilBlock,
|
||||||
|
// Nonce), fee values (NetworkFee, SystemFee) can be increased as well.
|
||||||
|
func (c *Contract) UnexportedFieldUnsigned() (*transaction.Transaction, error) {
|
||||||
|
return c.actor.MakeUnsignedCall(c.hash, "unexportedField", nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ComplicatedNameEventsFromApplicationLog retrieves a set of all emitted events
|
||||||
|
// with "! complicated name %$#" name from the provided [result.ApplicationLog].
|
||||||
|
func ComplicatedNameEventsFromApplicationLog(log *result.ApplicationLog) ([]*ComplicatedNameEvent, error) {
|
||||||
|
if log == nil {
|
||||||
|
return nil, errors.New("nil application log")
|
||||||
|
}
|
||||||
|
|
||||||
|
var res []*ComplicatedNameEvent
|
||||||
|
for i, ex := range log.Executions {
|
||||||
|
for j, e := range ex.Events {
|
||||||
|
if e.Name != "! complicated name %$#" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
event := new(ComplicatedNameEvent)
|
||||||
|
err := event.FromStackItem(e.Item)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to deserialize ComplicatedNameEvent from stackitem (execution #%d, event #%d): %w", i, j, err)
|
||||||
|
}
|
||||||
|
res = append(res, event)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// FromStackItem converts provided [stackitem.Array] to ComplicatedNameEvent or
|
||||||
|
// returns an error if it's not possible to do to so.
|
||||||
|
func (e *ComplicatedNameEvent) FromStackItem(item *stackitem.Array) error {
|
||||||
|
if item == nil {
|
||||||
|
return errors.New("nil item")
|
||||||
|
}
|
||||||
|
arr, ok := item.Value().([]stackitem.Item)
|
||||||
|
if !ok {
|
||||||
|
return errors.New("not an array")
|
||||||
|
}
|
||||||
|
if len(arr) != 1 {
|
||||||
|
return errors.New("wrong number of structure elements")
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
index = -1
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
index++
|
||||||
|
e.ComplicatedParam, err = func(item stackitem.Item) (string, error) {
|
||||||
|
b, err := item.TryBytes()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
if !utf8.Valid(b) {
|
||||||
|
return "", errors.New("not a UTF-8 string")
|
||||||
|
}
|
||||||
|
return string(b), nil
|
||||||
|
}(arr[index])
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("field ComplicatedParam: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SomeMapEventsFromApplicationLog retrieves a set of all emitted events
|
||||||
|
// with "SomeMap" name from the provided [result.ApplicationLog].
|
||||||
|
func SomeMapEventsFromApplicationLog(log *result.ApplicationLog) ([]*SomeMapEvent, error) {
|
||||||
|
if log == nil {
|
||||||
|
return nil, errors.New("nil application log")
|
||||||
|
}
|
||||||
|
|
||||||
|
var res []*SomeMapEvent
|
||||||
|
for i, ex := range log.Executions {
|
||||||
|
for j, e := range ex.Events {
|
||||||
|
if e.Name != "SomeMap" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
event := new(SomeMapEvent)
|
||||||
|
err := event.FromStackItem(e.Item)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to deserialize SomeMapEvent from stackitem (execution #%d, event #%d): %w", i, j, err)
|
||||||
|
}
|
||||||
|
res = append(res, event)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// FromStackItem converts provided [stackitem.Array] to SomeMapEvent or
|
||||||
|
// returns an error if it's not possible to do to so.
|
||||||
|
func (e *SomeMapEvent) FromStackItem(item *stackitem.Array) error {
|
||||||
|
if item == nil {
|
||||||
|
return errors.New("nil item")
|
||||||
|
}
|
||||||
|
arr, ok := item.Value().([]stackitem.Item)
|
||||||
|
if !ok {
|
||||||
|
return errors.New("not an array")
|
||||||
|
}
|
||||||
|
if len(arr) != 1 {
|
||||||
|
return errors.New("wrong number of structure elements")
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
index = -1
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
index++
|
||||||
|
e.M, err = func(item stackitem.Item) (map[any]any, error) {
|
||||||
|
m, ok := item.Value().([]stackitem.MapElement)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("%s is not a map", item.Type().String())
|
||||||
|
}
|
||||||
|
res := make(map[any]any)
|
||||||
|
for i := range m {
|
||||||
|
k, err := m[i].Key.Value(), error(nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("key %d: %w", i, err)
|
||||||
|
}
|
||||||
|
v, err := m[i].Value.Value(), error(nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("value %d: %w", i, err)
|
||||||
|
}
|
||||||
|
res[k] = v
|
||||||
|
}
|
||||||
|
return res, nil
|
||||||
|
}(arr[index])
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("field M: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SomeStructEventsFromApplicationLog retrieves a set of all emitted events
|
||||||
|
// with "SomeStruct" name from the provided [result.ApplicationLog].
|
||||||
|
func SomeStructEventsFromApplicationLog(log *result.ApplicationLog) ([]*SomeStructEvent, error) {
|
||||||
|
if log == nil {
|
||||||
|
return nil, errors.New("nil application log")
|
||||||
|
}
|
||||||
|
|
||||||
|
var res []*SomeStructEvent
|
||||||
|
for i, ex := range log.Executions {
|
||||||
|
for j, e := range ex.Events {
|
||||||
|
if e.Name != "SomeStruct" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
event := new(SomeStructEvent)
|
||||||
|
err := event.FromStackItem(e.Item)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to deserialize SomeStructEvent from stackitem (execution #%d, event #%d): %w", i, j, err)
|
||||||
|
}
|
||||||
|
res = append(res, event)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// FromStackItem converts provided [stackitem.Array] to SomeStructEvent or
|
||||||
|
// returns an error if it's not possible to do to so.
|
||||||
|
func (e *SomeStructEvent) FromStackItem(item *stackitem.Array) error {
|
||||||
|
if item == nil {
|
||||||
|
return errors.New("nil item")
|
||||||
|
}
|
||||||
|
arr, ok := item.Value().([]stackitem.Item)
|
||||||
|
if !ok {
|
||||||
|
return errors.New("not an array")
|
||||||
|
}
|
||||||
|
if len(arr) != 1 {
|
||||||
|
return errors.New("wrong number of structure elements")
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
index = -1
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
index++
|
||||||
|
e.S, err = func(item stackitem.Item) ([]any, error) {
|
||||||
|
arr, ok := item.Value().([]stackitem.Item)
|
||||||
|
if !ok {
|
||||||
|
return nil, errors.New("not an array")
|
||||||
|
}
|
||||||
|
res := make([]any, len(arr))
|
||||||
|
for i := range res {
|
||||||
|
res[i], err = arr[i].Value(), error(nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("item %d: %w", i, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res, nil
|
||||||
|
}(arr[index])
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("field S: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SomeArrayEventsFromApplicationLog retrieves a set of all emitted events
|
||||||
|
// with "SomeArray" name from the provided [result.ApplicationLog].
|
||||||
|
func SomeArrayEventsFromApplicationLog(log *result.ApplicationLog) ([]*SomeArrayEvent, error) {
|
||||||
|
if log == nil {
|
||||||
|
return nil, errors.New("nil application log")
|
||||||
|
}
|
||||||
|
|
||||||
|
var res []*SomeArrayEvent
|
||||||
|
for i, ex := range log.Executions {
|
||||||
|
for j, e := range ex.Events {
|
||||||
|
if e.Name != "SomeArray" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
event := new(SomeArrayEvent)
|
||||||
|
err := event.FromStackItem(e.Item)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to deserialize SomeArrayEvent from stackitem (execution #%d, event #%d): %w", i, j, err)
|
||||||
|
}
|
||||||
|
res = append(res, event)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// FromStackItem converts provided [stackitem.Array] to SomeArrayEvent or
|
||||||
|
// returns an error if it's not possible to do to so.
|
||||||
|
func (e *SomeArrayEvent) FromStackItem(item *stackitem.Array) error {
|
||||||
|
if item == nil {
|
||||||
|
return errors.New("nil item")
|
||||||
|
}
|
||||||
|
arr, ok := item.Value().([]stackitem.Item)
|
||||||
|
if !ok {
|
||||||
|
return errors.New("not an array")
|
||||||
|
}
|
||||||
|
if len(arr) != 1 {
|
||||||
|
return errors.New("wrong number of structure elements")
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
index = -1
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
index++
|
||||||
|
e.A, err = func(item stackitem.Item) ([]any, error) {
|
||||||
|
arr, ok := item.Value().([]stackitem.Item)
|
||||||
|
if !ok {
|
||||||
|
return nil, errors.New("not an array")
|
||||||
|
}
|
||||||
|
res := make([]any, len(arr))
|
||||||
|
for i := range res {
|
||||||
|
res[i], err = arr[i].Value(), error(nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("item %d: %w", i, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res, nil
|
||||||
|
}(arr[index])
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("field A: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SomeUnexportedFieldEventsFromApplicationLog retrieves a set of all emitted events
|
||||||
|
// with "SomeUnexportedField" name from the provided [result.ApplicationLog].
|
||||||
|
func SomeUnexportedFieldEventsFromApplicationLog(log *result.ApplicationLog) ([]*SomeUnexportedFieldEvent, error) {
|
||||||
|
if log == nil {
|
||||||
|
return nil, errors.New("nil application log")
|
||||||
|
}
|
||||||
|
|
||||||
|
var res []*SomeUnexportedFieldEvent
|
||||||
|
for i, ex := range log.Executions {
|
||||||
|
for j, e := range ex.Events {
|
||||||
|
if e.Name != "SomeUnexportedField" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
event := new(SomeUnexportedFieldEvent)
|
||||||
|
err := event.FromStackItem(e.Item)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to deserialize SomeUnexportedFieldEvent from stackitem (execution #%d, event #%d): %w", i, j, err)
|
||||||
|
}
|
||||||
|
res = append(res, event)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// FromStackItem converts provided [stackitem.Array] to SomeUnexportedFieldEvent or
|
||||||
|
// returns an error if it's not possible to do to so.
|
||||||
|
func (e *SomeUnexportedFieldEvent) FromStackItem(item *stackitem.Array) error {
|
||||||
|
if item == nil {
|
||||||
|
return errors.New("nil item")
|
||||||
|
}
|
||||||
|
arr, ok := item.Value().([]stackitem.Item)
|
||||||
|
if !ok {
|
||||||
|
return errors.New("not an array")
|
||||||
|
}
|
||||||
|
if len(arr) != 1 {
|
||||||
|
return errors.New("wrong number of structure elements")
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
index = -1
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
index++
|
||||||
|
e.S, err = func(item stackitem.Item) ([]any, error) {
|
||||||
|
arr, ok := item.Value().([]stackitem.Item)
|
||||||
|
if !ok {
|
||||||
|
return nil, errors.New("not an array")
|
||||||
|
}
|
||||||
|
res := make([]any, len(arr))
|
||||||
|
for i := range res {
|
||||||
|
res[i], err = arr[i].Value(), error(nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("item %d: %w", i, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res, nil
|
||||||
|
}(arr[index])
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("field S: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -1,12 +1,12 @@
|
||||||
|
// Code generated by neo-go contract generate-rpcwrapper --manifest <file.json> --out <file.go> [--hash <hash>] [--config <config>]; DO NOT EDIT.
|
||||||
|
|
||||||
// Package structs contains RPC wrappers for Notifications contract.
|
// Package structs contains RPC wrappers for Notifications contract.
|
||||||
package structs
|
package structs
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/elliptic"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/neorpc/result"
|
"github.com/nspcc-dev/neo-go/pkg/neorpc/result"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||||
|
@ -23,64 +23,9 @@ type CrazyStruct struct {
|
||||||
B bool
|
B bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// LedgerBlock is a contract-specific ledger.Block type used by its methods.
|
// SimpleStruct is a contract-specific simpleStruct type used by its methods.
|
||||||
type LedgerBlock struct {
|
type SimpleStruct struct {
|
||||||
Hash util.Uint256
|
I *big.Int
|
||||||
Version *big.Int
|
|
||||||
PrevHash util.Uint256
|
|
||||||
MerkleRoot util.Uint256
|
|
||||||
Timestamp *big.Int
|
|
||||||
Nonce *big.Int
|
|
||||||
Index *big.Int
|
|
||||||
NextConsensus util.Uint160
|
|
||||||
TransactionsLength *big.Int
|
|
||||||
}
|
|
||||||
|
|
||||||
// LedgerBlockSR is a contract-specific ledger.BlockSR type used by its methods.
|
|
||||||
type LedgerBlockSR struct {
|
|
||||||
Hash util.Uint256
|
|
||||||
Version *big.Int
|
|
||||||
PrevHash util.Uint256
|
|
||||||
MerkleRoot util.Uint256
|
|
||||||
Timestamp *big.Int
|
|
||||||
Nonce *big.Int
|
|
||||||
Index *big.Int
|
|
||||||
NextConsensus util.Uint160
|
|
||||||
TransactionsLength *big.Int
|
|
||||||
PrevStateRoot util.Uint256
|
|
||||||
}
|
|
||||||
|
|
||||||
// LedgerTransaction is a contract-specific ledger.Transaction type used by its methods.
|
|
||||||
type LedgerTransaction struct {
|
|
||||||
Hash util.Uint256
|
|
||||||
Version *big.Int
|
|
||||||
Nonce *big.Int
|
|
||||||
Sender util.Uint160
|
|
||||||
SysFee *big.Int
|
|
||||||
NetFee *big.Int
|
|
||||||
ValidUntilBlock *big.Int
|
|
||||||
Script []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
// LedgerTransactionSigner is a contract-specific ledger.TransactionSigner type used by its methods.
|
|
||||||
type LedgerTransactionSigner struct {
|
|
||||||
Account util.Uint160
|
|
||||||
Scopes *big.Int
|
|
||||||
AllowedContracts []util.Uint160
|
|
||||||
AllowedGroups keys.PublicKeys
|
|
||||||
Rules []*LedgerWitnessRule
|
|
||||||
}
|
|
||||||
|
|
||||||
// LedgerWitnessCondition is a contract-specific ledger.WitnessCondition type used by its methods.
|
|
||||||
type LedgerWitnessCondition struct {
|
|
||||||
Type *big.Int
|
|
||||||
Value any
|
|
||||||
}
|
|
||||||
|
|
||||||
// LedgerWitnessRule is a contract-specific ledger.WitnessRule type used by its methods.
|
|
||||||
type LedgerWitnessRule struct {
|
|
||||||
Action *big.Int
|
|
||||||
Condition *LedgerWitnessCondition
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ComplicatedNameEvent represents "! complicated name %$#" event emitted by the contract.
|
// ComplicatedNameEvent represents "! complicated name %$#" event emitted by the contract.
|
||||||
|
@ -103,6 +48,11 @@ type SomeArrayEvent struct {
|
||||||
A [][]*big.Int
|
A [][]*big.Int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SomeUnexportedFieldEvent represents "SomeUnexportedField" event emitted by the contract.
|
||||||
|
type SomeUnexportedFieldEvent struct {
|
||||||
|
S *SimpleStruct
|
||||||
|
}
|
||||||
|
|
||||||
// Actor is used by Contract to call state-changing methods.
|
// Actor is used by Contract to call state-changing methods.
|
||||||
type Actor interface {
|
type Actor interface {
|
||||||
MakeCall(contract util.Uint160, method string, params ...any) (*transaction.Transaction, error)
|
MakeCall(contract util.Uint160, method string, params ...any) (*transaction.Transaction, error)
|
||||||
|
@ -213,6 +163,28 @@ func (c *Contract) StructUnsigned() (*transaction.Transaction, error) {
|
||||||
return c.actor.MakeUnsignedCall(c.hash, "struct", nil)
|
return c.actor.MakeUnsignedCall(c.hash, "struct", nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UnexportedField creates a transaction invoking `unexportedField` method of the contract.
|
||||||
|
// This transaction is signed and immediately sent to the network.
|
||||||
|
// The values returned are its hash, ValidUntilBlock value and error if any.
|
||||||
|
func (c *Contract) UnexportedField() (util.Uint256, uint32, error) {
|
||||||
|
return c.actor.SendCall(c.hash, "unexportedField")
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnexportedFieldTransaction creates a transaction invoking `unexportedField` method of the contract.
|
||||||
|
// This transaction is signed, but not sent to the network, instead it's
|
||||||
|
// returned to the caller.
|
||||||
|
func (c *Contract) UnexportedFieldTransaction() (*transaction.Transaction, error) {
|
||||||
|
return c.actor.MakeCall(c.hash, "unexportedField")
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnexportedFieldUnsigned creates a transaction invoking `unexportedField` method of the contract.
|
||||||
|
// This transaction is not signed, it's simply returned to the caller.
|
||||||
|
// Any fields of it that do not affect fees can be changed (ValidUntilBlock,
|
||||||
|
// Nonce), fee values (NetworkFee, SystemFee) can be increased as well.
|
||||||
|
func (c *Contract) UnexportedFieldUnsigned() (*transaction.Transaction, error) {
|
||||||
|
return c.actor.MakeUnsignedCall(c.hash, "unexportedField", nil)
|
||||||
|
}
|
||||||
|
|
||||||
// itemToCrazyStruct converts stack item into *CrazyStruct.
|
// itemToCrazyStruct converts stack item into *CrazyStruct.
|
||||||
func itemToCrazyStruct(item stackitem.Item, err error) (*CrazyStruct, error) {
|
func itemToCrazyStruct(item stackitem.Item, err error) (*CrazyStruct, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -253,24 +225,24 @@ func (res *CrazyStruct) FromStackItem(item stackitem.Item) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// itemToLedgerBlock converts stack item into *LedgerBlock.
|
// itemToSimpleStruct converts stack item into *SimpleStruct.
|
||||||
func itemToLedgerBlock(item stackitem.Item, err error) (*LedgerBlock, error) {
|
func itemToSimpleStruct(item stackitem.Item, err error) (*SimpleStruct, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
var res = new(LedgerBlock)
|
var res = new(SimpleStruct)
|
||||||
err = res.FromStackItem(item)
|
err = res.FromStackItem(item)
|
||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// FromStackItem retrieves fields of LedgerBlock from the given
|
// FromStackItem retrieves fields of SimpleStruct from the given
|
||||||
// [stackitem.Item] or returns an error if it's not possible to do to so.
|
// [stackitem.Item] or returns an error if it's not possible to do to so.
|
||||||
func (res *LedgerBlock) FromStackItem(item stackitem.Item) error {
|
func (res *SimpleStruct) FromStackItem(item stackitem.Item) error {
|
||||||
arr, ok := item.Value().([]stackitem.Item)
|
arr, ok := item.Value().([]stackitem.Item)
|
||||||
if !ok {
|
if !ok {
|
||||||
return errors.New("not an array")
|
return errors.New("not an array")
|
||||||
}
|
}
|
||||||
if len(arr) != 9 {
|
if len(arr) != 1 {
|
||||||
return errors.New("wrong number of structure elements")
|
return errors.New("wrong number of structure elements")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -279,538 +251,9 @@ func (res *LedgerBlock) FromStackItem(item stackitem.Item) error {
|
||||||
err error
|
err error
|
||||||
)
|
)
|
||||||
index++
|
index++
|
||||||
res.Hash, err = func (item stackitem.Item) (util.Uint256, error) {
|
res.I, err = arr[index].TryInteger()
|
||||||
b, err := item.TryBytes()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return util.Uint256{}, err
|
return fmt.Errorf("field I: %w", err)
|
||||||
}
|
|
||||||
u, err := util.Uint256DecodeBytesBE(b)
|
|
||||||
if err != nil {
|
|
||||||
return util.Uint256{}, err
|
|
||||||
}
|
|
||||||
return u, nil
|
|
||||||
} (arr[index])
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("field Hash: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
index++
|
|
||||||
res.Version, err = arr[index].TryInteger()
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("field Version: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
index++
|
|
||||||
res.PrevHash, err = func (item stackitem.Item) (util.Uint256, error) {
|
|
||||||
b, err := item.TryBytes()
|
|
||||||
if err != nil {
|
|
||||||
return util.Uint256{}, err
|
|
||||||
}
|
|
||||||
u, err := util.Uint256DecodeBytesBE(b)
|
|
||||||
if err != nil {
|
|
||||||
return util.Uint256{}, err
|
|
||||||
}
|
|
||||||
return u, nil
|
|
||||||
} (arr[index])
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("field PrevHash: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
index++
|
|
||||||
res.MerkleRoot, err = func (item stackitem.Item) (util.Uint256, error) {
|
|
||||||
b, err := item.TryBytes()
|
|
||||||
if err != nil {
|
|
||||||
return util.Uint256{}, err
|
|
||||||
}
|
|
||||||
u, err := util.Uint256DecodeBytesBE(b)
|
|
||||||
if err != nil {
|
|
||||||
return util.Uint256{}, err
|
|
||||||
}
|
|
||||||
return u, nil
|
|
||||||
} (arr[index])
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("field MerkleRoot: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
index++
|
|
||||||
res.Timestamp, err = arr[index].TryInteger()
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("field Timestamp: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
index++
|
|
||||||
res.Nonce, err = arr[index].TryInteger()
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("field Nonce: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
index++
|
|
||||||
res.Index, err = arr[index].TryInteger()
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("field Index: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
index++
|
|
||||||
res.NextConsensus, err = func (item stackitem.Item) (util.Uint160, error) {
|
|
||||||
b, err := item.TryBytes()
|
|
||||||
if err != nil {
|
|
||||||
return util.Uint160{}, err
|
|
||||||
}
|
|
||||||
u, err := util.Uint160DecodeBytesBE(b)
|
|
||||||
if err != nil {
|
|
||||||
return util.Uint160{}, err
|
|
||||||
}
|
|
||||||
return u, nil
|
|
||||||
} (arr[index])
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("field NextConsensus: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
index++
|
|
||||||
res.TransactionsLength, err = arr[index].TryInteger()
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("field TransactionsLength: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// itemToLedgerBlockSR converts stack item into *LedgerBlockSR.
|
|
||||||
func itemToLedgerBlockSR(item stackitem.Item, err error) (*LedgerBlockSR, error) {
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
var res = new(LedgerBlockSR)
|
|
||||||
err = res.FromStackItem(item)
|
|
||||||
return res, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// FromStackItem retrieves fields of LedgerBlockSR from the given
|
|
||||||
// [stackitem.Item] or returns an error if it's not possible to do to so.
|
|
||||||
func (res *LedgerBlockSR) FromStackItem(item stackitem.Item) error {
|
|
||||||
arr, ok := item.Value().([]stackitem.Item)
|
|
||||||
if !ok {
|
|
||||||
return errors.New("not an array")
|
|
||||||
}
|
|
||||||
if len(arr) != 10 {
|
|
||||||
return errors.New("wrong number of structure elements")
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
index = -1
|
|
||||||
err error
|
|
||||||
)
|
|
||||||
index++
|
|
||||||
res.Hash, err = func (item stackitem.Item) (util.Uint256, error) {
|
|
||||||
b, err := item.TryBytes()
|
|
||||||
if err != nil {
|
|
||||||
return util.Uint256{}, err
|
|
||||||
}
|
|
||||||
u, err := util.Uint256DecodeBytesBE(b)
|
|
||||||
if err != nil {
|
|
||||||
return util.Uint256{}, err
|
|
||||||
}
|
|
||||||
return u, nil
|
|
||||||
} (arr[index])
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("field Hash: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
index++
|
|
||||||
res.Version, err = arr[index].TryInteger()
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("field Version: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
index++
|
|
||||||
res.PrevHash, err = func (item stackitem.Item) (util.Uint256, error) {
|
|
||||||
b, err := item.TryBytes()
|
|
||||||
if err != nil {
|
|
||||||
return util.Uint256{}, err
|
|
||||||
}
|
|
||||||
u, err := util.Uint256DecodeBytesBE(b)
|
|
||||||
if err != nil {
|
|
||||||
return util.Uint256{}, err
|
|
||||||
}
|
|
||||||
return u, nil
|
|
||||||
} (arr[index])
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("field PrevHash: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
index++
|
|
||||||
res.MerkleRoot, err = func (item stackitem.Item) (util.Uint256, error) {
|
|
||||||
b, err := item.TryBytes()
|
|
||||||
if err != nil {
|
|
||||||
return util.Uint256{}, err
|
|
||||||
}
|
|
||||||
u, err := util.Uint256DecodeBytesBE(b)
|
|
||||||
if err != nil {
|
|
||||||
return util.Uint256{}, err
|
|
||||||
}
|
|
||||||
return u, nil
|
|
||||||
} (arr[index])
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("field MerkleRoot: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
index++
|
|
||||||
res.Timestamp, err = arr[index].TryInteger()
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("field Timestamp: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
index++
|
|
||||||
res.Nonce, err = arr[index].TryInteger()
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("field Nonce: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
index++
|
|
||||||
res.Index, err = arr[index].TryInteger()
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("field Index: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
index++
|
|
||||||
res.NextConsensus, err = func (item stackitem.Item) (util.Uint160, error) {
|
|
||||||
b, err := item.TryBytes()
|
|
||||||
if err != nil {
|
|
||||||
return util.Uint160{}, err
|
|
||||||
}
|
|
||||||
u, err := util.Uint160DecodeBytesBE(b)
|
|
||||||
if err != nil {
|
|
||||||
return util.Uint160{}, err
|
|
||||||
}
|
|
||||||
return u, nil
|
|
||||||
} (arr[index])
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("field NextConsensus: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
index++
|
|
||||||
res.TransactionsLength, err = arr[index].TryInteger()
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("field TransactionsLength: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
index++
|
|
||||||
res.PrevStateRoot, err = func (item stackitem.Item) (util.Uint256, error) {
|
|
||||||
b, err := item.TryBytes()
|
|
||||||
if err != nil {
|
|
||||||
return util.Uint256{}, err
|
|
||||||
}
|
|
||||||
u, err := util.Uint256DecodeBytesBE(b)
|
|
||||||
if err != nil {
|
|
||||||
return util.Uint256{}, err
|
|
||||||
}
|
|
||||||
return u, nil
|
|
||||||
} (arr[index])
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("field PrevStateRoot: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// itemToLedgerTransaction converts stack item into *LedgerTransaction.
|
|
||||||
func itemToLedgerTransaction(item stackitem.Item, err error) (*LedgerTransaction, error) {
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
var res = new(LedgerTransaction)
|
|
||||||
err = res.FromStackItem(item)
|
|
||||||
return res, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// FromStackItem retrieves fields of LedgerTransaction from the given
|
|
||||||
// [stackitem.Item] or returns an error if it's not possible to do to so.
|
|
||||||
func (res *LedgerTransaction) FromStackItem(item stackitem.Item) error {
|
|
||||||
arr, ok := item.Value().([]stackitem.Item)
|
|
||||||
if !ok {
|
|
||||||
return errors.New("not an array")
|
|
||||||
}
|
|
||||||
if len(arr) != 8 {
|
|
||||||
return errors.New("wrong number of structure elements")
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
index = -1
|
|
||||||
err error
|
|
||||||
)
|
|
||||||
index++
|
|
||||||
res.Hash, err = func (item stackitem.Item) (util.Uint256, error) {
|
|
||||||
b, err := item.TryBytes()
|
|
||||||
if err != nil {
|
|
||||||
return util.Uint256{}, err
|
|
||||||
}
|
|
||||||
u, err := util.Uint256DecodeBytesBE(b)
|
|
||||||
if err != nil {
|
|
||||||
return util.Uint256{}, err
|
|
||||||
}
|
|
||||||
return u, nil
|
|
||||||
} (arr[index])
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("field Hash: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
index++
|
|
||||||
res.Version, err = arr[index].TryInteger()
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("field Version: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
index++
|
|
||||||
res.Nonce, err = arr[index].TryInteger()
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("field Nonce: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
index++
|
|
||||||
res.Sender, err = func (item stackitem.Item) (util.Uint160, error) {
|
|
||||||
b, err := item.TryBytes()
|
|
||||||
if err != nil {
|
|
||||||
return util.Uint160{}, err
|
|
||||||
}
|
|
||||||
u, err := util.Uint160DecodeBytesBE(b)
|
|
||||||
if err != nil {
|
|
||||||
return util.Uint160{}, err
|
|
||||||
}
|
|
||||||
return u, nil
|
|
||||||
} (arr[index])
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("field Sender: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
index++
|
|
||||||
res.SysFee, err = arr[index].TryInteger()
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("field SysFee: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
index++
|
|
||||||
res.NetFee, err = arr[index].TryInteger()
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("field NetFee: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
index++
|
|
||||||
res.ValidUntilBlock, err = arr[index].TryInteger()
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("field ValidUntilBlock: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
index++
|
|
||||||
res.Script, err = arr[index].TryBytes()
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("field Script: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// itemToLedgerTransactionSigner converts stack item into *LedgerTransactionSigner.
|
|
||||||
func itemToLedgerTransactionSigner(item stackitem.Item, err error) (*LedgerTransactionSigner, error) {
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
var res = new(LedgerTransactionSigner)
|
|
||||||
err = res.FromStackItem(item)
|
|
||||||
return res, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// FromStackItem retrieves fields of LedgerTransactionSigner from the given
|
|
||||||
// [stackitem.Item] or returns an error if it's not possible to do to so.
|
|
||||||
func (res *LedgerTransactionSigner) FromStackItem(item stackitem.Item) error {
|
|
||||||
arr, ok := item.Value().([]stackitem.Item)
|
|
||||||
if !ok {
|
|
||||||
return errors.New("not an array")
|
|
||||||
}
|
|
||||||
if len(arr) != 5 {
|
|
||||||
return errors.New("wrong number of structure elements")
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
index = -1
|
|
||||||
err error
|
|
||||||
)
|
|
||||||
index++
|
|
||||||
res.Account, err = func (item stackitem.Item) (util.Uint160, error) {
|
|
||||||
b, err := item.TryBytes()
|
|
||||||
if err != nil {
|
|
||||||
return util.Uint160{}, err
|
|
||||||
}
|
|
||||||
u, err := util.Uint160DecodeBytesBE(b)
|
|
||||||
if err != nil {
|
|
||||||
return util.Uint160{}, err
|
|
||||||
}
|
|
||||||
return u, nil
|
|
||||||
} (arr[index])
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("field Account: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
index++
|
|
||||||
res.Scopes, err = arr[index].TryInteger()
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("field Scopes: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
index++
|
|
||||||
res.AllowedContracts, err = func (item stackitem.Item) ([]util.Uint160, error) {
|
|
||||||
arr, ok := item.Value().([]stackitem.Item)
|
|
||||||
if !ok {
|
|
||||||
return nil, errors.New("not an array")
|
|
||||||
}
|
|
||||||
res := make([]util.Uint160, len(arr))
|
|
||||||
for i := range res {
|
|
||||||
res[i], err = func (item stackitem.Item) (util.Uint160, error) {
|
|
||||||
b, err := item.TryBytes()
|
|
||||||
if err != nil {
|
|
||||||
return util.Uint160{}, err
|
|
||||||
}
|
|
||||||
u, err := util.Uint160DecodeBytesBE(b)
|
|
||||||
if err != nil {
|
|
||||||
return util.Uint160{}, err
|
|
||||||
}
|
|
||||||
return u, nil
|
|
||||||
} (arr[i])
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("item %d: %w", i, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return res, nil
|
|
||||||
} (arr[index])
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("field AllowedContracts: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
index++
|
|
||||||
res.AllowedGroups, err = func (item stackitem.Item) (keys.PublicKeys, error) {
|
|
||||||
arr, ok := item.Value().([]stackitem.Item)
|
|
||||||
if !ok {
|
|
||||||
return nil, errors.New("not an array")
|
|
||||||
}
|
|
||||||
res := make(keys.PublicKeys, len(arr))
|
|
||||||
for i := range res {
|
|
||||||
res[i], err = func (item stackitem.Item) (*keys.PublicKey, error) {
|
|
||||||
b, err := item.TryBytes()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
k, err := keys.NewPublicKeyFromBytes(b, elliptic.P256())
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return k, nil
|
|
||||||
} (arr[i])
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("item %d: %w", i, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return res, nil
|
|
||||||
} (arr[index])
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("field AllowedGroups: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
index++
|
|
||||||
res.Rules, err = func (item stackitem.Item) ([]*LedgerWitnessRule, error) {
|
|
||||||
arr, ok := item.Value().([]stackitem.Item)
|
|
||||||
if !ok {
|
|
||||||
return nil, errors.New("not an array")
|
|
||||||
}
|
|
||||||
res := make([]*LedgerWitnessRule, len(arr))
|
|
||||||
for i := range res {
|
|
||||||
res[i], err = itemToLedgerWitnessRule(arr[i], nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("item %d: %w", i, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return res, nil
|
|
||||||
} (arr[index])
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("field Rules: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// itemToLedgerWitnessCondition converts stack item into *LedgerWitnessCondition.
|
|
||||||
func itemToLedgerWitnessCondition(item stackitem.Item, err error) (*LedgerWitnessCondition, error) {
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
var res = new(LedgerWitnessCondition)
|
|
||||||
err = res.FromStackItem(item)
|
|
||||||
return res, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// FromStackItem retrieves fields of LedgerWitnessCondition from the given
|
|
||||||
// [stackitem.Item] or returns an error if it's not possible to do to so.
|
|
||||||
func (res *LedgerWitnessCondition) FromStackItem(item stackitem.Item) error {
|
|
||||||
arr, ok := item.Value().([]stackitem.Item)
|
|
||||||
if !ok {
|
|
||||||
return errors.New("not an array")
|
|
||||||
}
|
|
||||||
if len(arr) != 2 {
|
|
||||||
return errors.New("wrong number of structure elements")
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
index = -1
|
|
||||||
err error
|
|
||||||
)
|
|
||||||
index++
|
|
||||||
res.Type, err = arr[index].TryInteger()
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("field Type: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
index++
|
|
||||||
res.Value, err = arr[index].Value(), error(nil)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("field Value: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// itemToLedgerWitnessRule converts stack item into *LedgerWitnessRule.
|
|
||||||
func itemToLedgerWitnessRule(item stackitem.Item, err error) (*LedgerWitnessRule, error) {
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
var res = new(LedgerWitnessRule)
|
|
||||||
err = res.FromStackItem(item)
|
|
||||||
return res, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// FromStackItem retrieves fields of LedgerWitnessRule from the given
|
|
||||||
// [stackitem.Item] or returns an error if it's not possible to do to so.
|
|
||||||
func (res *LedgerWitnessRule) FromStackItem(item stackitem.Item) error {
|
|
||||||
arr, ok := item.Value().([]stackitem.Item)
|
|
||||||
if !ok {
|
|
||||||
return errors.New("not an array")
|
|
||||||
}
|
|
||||||
if len(arr) != 2 {
|
|
||||||
return errors.New("wrong number of structure elements")
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
index = -1
|
|
||||||
err error
|
|
||||||
)
|
|
||||||
index++
|
|
||||||
res.Action, err = arr[index].TryInteger()
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("field Action: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
index++
|
|
||||||
res.Condition, err = itemToLedgerWitnessCondition(arr[index], nil)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("field Condition: %w", err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -860,7 +303,7 @@ func (e *ComplicatedNameEvent) FromStackItem(item *stackitem.Array) error {
|
||||||
err error
|
err error
|
||||||
)
|
)
|
||||||
index++
|
index++
|
||||||
e.ComplicatedParam, err = func (item stackitem.Item) (string, error) {
|
e.ComplicatedParam, err = func(item stackitem.Item) (string, error) {
|
||||||
b, err := item.TryBytes()
|
b, err := item.TryBytes()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
|
@ -869,7 +312,7 @@ func (e *ComplicatedNameEvent) FromStackItem(item *stackitem.Array) error {
|
||||||
return "", errors.New("not a UTF-8 string")
|
return "", errors.New("not a UTF-8 string")
|
||||||
}
|
}
|
||||||
return string(b), nil
|
return string(b), nil
|
||||||
} (arr[index])
|
}(arr[index])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("field ComplicatedParam: %w", err)
|
return fmt.Errorf("field ComplicatedParam: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -921,7 +364,7 @@ func (e *SomeMapEvent) FromStackItem(item *stackitem.Array) error {
|
||||||
err error
|
err error
|
||||||
)
|
)
|
||||||
index++
|
index++
|
||||||
e.M, err = func (item stackitem.Item) (map[*big.Int]map[string][]util.Uint160, error) {
|
e.M, err = func(item stackitem.Item) (map[*big.Int]map[string][]util.Uint160, error) {
|
||||||
m, ok := item.Value().([]stackitem.MapElement)
|
m, ok := item.Value().([]stackitem.MapElement)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("%s is not a map", item.Type().String())
|
return nil, fmt.Errorf("%s is not a map", item.Type().String())
|
||||||
|
@ -932,14 +375,14 @@ func (e *SomeMapEvent) FromStackItem(item *stackitem.Array) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("key %d: %w", i, err)
|
return nil, fmt.Errorf("key %d: %w", i, err)
|
||||||
}
|
}
|
||||||
v, err := func (item stackitem.Item) (map[string][]util.Uint160, error) {
|
v, err := func(item stackitem.Item) (map[string][]util.Uint160, error) {
|
||||||
m, ok := item.Value().([]stackitem.MapElement)
|
m, ok := item.Value().([]stackitem.MapElement)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("%s is not a map", item.Type().String())
|
return nil, fmt.Errorf("%s is not a map", item.Type().String())
|
||||||
}
|
}
|
||||||
res := make(map[string][]util.Uint160)
|
res := make(map[string][]util.Uint160)
|
||||||
for i := range m {
|
for i := range m {
|
||||||
k, err := func (item stackitem.Item) (string, error) {
|
k, err := func(item stackitem.Item) (string, error) {
|
||||||
b, err := item.TryBytes()
|
b, err := item.TryBytes()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
|
@ -948,18 +391,18 @@ func (e *SomeMapEvent) FromStackItem(item *stackitem.Array) error {
|
||||||
return "", errors.New("not a UTF-8 string")
|
return "", errors.New("not a UTF-8 string")
|
||||||
}
|
}
|
||||||
return string(b), nil
|
return string(b), nil
|
||||||
} (m[i].Key)
|
}(m[i].Key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("key %d: %w", i, err)
|
return nil, fmt.Errorf("key %d: %w", i, err)
|
||||||
}
|
}
|
||||||
v, err := func (item stackitem.Item) ([]util.Uint160, error) {
|
v, err := func(item stackitem.Item) ([]util.Uint160, error) {
|
||||||
arr, ok := item.Value().([]stackitem.Item)
|
arr, ok := item.Value().([]stackitem.Item)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, errors.New("not an array")
|
return nil, errors.New("not an array")
|
||||||
}
|
}
|
||||||
res := make([]util.Uint160, len(arr))
|
res := make([]util.Uint160, len(arr))
|
||||||
for i := range res {
|
for i := range res {
|
||||||
res[i], err = func (item stackitem.Item) (util.Uint160, error) {
|
res[i], err = func(item stackitem.Item) (util.Uint160, error) {
|
||||||
b, err := item.TryBytes()
|
b, err := item.TryBytes()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return util.Uint160{}, err
|
return util.Uint160{}, err
|
||||||
|
@ -969,27 +412,27 @@ func (e *SomeMapEvent) FromStackItem(item *stackitem.Array) error {
|
||||||
return util.Uint160{}, err
|
return util.Uint160{}, err
|
||||||
}
|
}
|
||||||
return u, nil
|
return u, nil
|
||||||
} (arr[i])
|
}(arr[i])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("item %d: %w", i, err)
|
return nil, fmt.Errorf("item %d: %w", i, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return res, nil
|
return res, nil
|
||||||
} (m[i].Value)
|
}(m[i].Value)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("value %d: %w", i, err)
|
return nil, fmt.Errorf("value %d: %w", i, err)
|
||||||
}
|
}
|
||||||
res[k] = v
|
res[k] = v
|
||||||
}
|
}
|
||||||
return res, nil
|
return res, nil
|
||||||
} (m[i].Value)
|
}(m[i].Value)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("value %d: %w", i, err)
|
return nil, fmt.Errorf("value %d: %w", i, err)
|
||||||
}
|
}
|
||||||
res[k] = v
|
res[k] = v
|
||||||
}
|
}
|
||||||
return res, nil
|
return res, nil
|
||||||
} (arr[index])
|
}(arr[index])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("field M: %w", err)
|
return fmt.Errorf("field M: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -1093,14 +536,14 @@ func (e *SomeArrayEvent) FromStackItem(item *stackitem.Array) error {
|
||||||
err error
|
err error
|
||||||
)
|
)
|
||||||
index++
|
index++
|
||||||
e.A, err = func (item stackitem.Item) ([][]*big.Int, error) {
|
e.A, err = func(item stackitem.Item) ([][]*big.Int, error) {
|
||||||
arr, ok := item.Value().([]stackitem.Item)
|
arr, ok := item.Value().([]stackitem.Item)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, errors.New("not an array")
|
return nil, errors.New("not an array")
|
||||||
}
|
}
|
||||||
res := make([][]*big.Int, len(arr))
|
res := make([][]*big.Int, len(arr))
|
||||||
for i := range res {
|
for i := range res {
|
||||||
res[i], err = func (item stackitem.Item) ([]*big.Int, error) {
|
res[i], err = func(item stackitem.Item) ([]*big.Int, error) {
|
||||||
arr, ok := item.Value().([]stackitem.Item)
|
arr, ok := item.Value().([]stackitem.Item)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, errors.New("not an array")
|
return nil, errors.New("not an array")
|
||||||
|
@ -1113,16 +556,68 @@ func (e *SomeArrayEvent) FromStackItem(item *stackitem.Array) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return res, nil
|
return res, nil
|
||||||
} (arr[i])
|
}(arr[i])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("item %d: %w", i, err)
|
return nil, fmt.Errorf("item %d: %w", i, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return res, nil
|
return res, nil
|
||||||
} (arr[index])
|
}(arr[index])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("field A: %w", err)
|
return fmt.Errorf("field A: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SomeUnexportedFieldEventsFromApplicationLog retrieves a set of all emitted events
|
||||||
|
// with "SomeUnexportedField" name from the provided [result.ApplicationLog].
|
||||||
|
func SomeUnexportedFieldEventsFromApplicationLog(log *result.ApplicationLog) ([]*SomeUnexportedFieldEvent, error) {
|
||||||
|
if log == nil {
|
||||||
|
return nil, errors.New("nil application log")
|
||||||
|
}
|
||||||
|
|
||||||
|
var res []*SomeUnexportedFieldEvent
|
||||||
|
for i, ex := range log.Executions {
|
||||||
|
for j, e := range ex.Events {
|
||||||
|
if e.Name != "SomeUnexportedField" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
event := new(SomeUnexportedFieldEvent)
|
||||||
|
err := event.FromStackItem(e.Item)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to deserialize SomeUnexportedFieldEvent from stackitem (execution #%d, event #%d): %w", i, j, err)
|
||||||
|
}
|
||||||
|
res = append(res, event)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// FromStackItem converts provided [stackitem.Array] to SomeUnexportedFieldEvent or
|
||||||
|
// returns an error if it's not possible to do to so.
|
||||||
|
func (e *SomeUnexportedFieldEvent) FromStackItem(item *stackitem.Array) error {
|
||||||
|
if item == nil {
|
||||||
|
return errors.New("nil item")
|
||||||
|
}
|
||||||
|
arr, ok := item.Value().([]stackitem.Item)
|
||||||
|
if !ok {
|
||||||
|
return errors.New("not an array")
|
||||||
|
}
|
||||||
|
if len(arr) != 1 {
|
||||||
|
return errors.New("wrong number of structure elements")
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
index = -1
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
index++
|
||||||
|
e.S, err = itemToSimpleStruct(arr[index], nil)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("field S: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -1,12 +1,12 @@
|
||||||
|
// Code generated by neo-go contract generate-rpcwrapper --manifest <file.json> --out <file.go> [--hash <hash>] [--config <config>]; DO NOT EDIT.
|
||||||
|
|
||||||
// Package structs contains RPC wrappers for Notifications contract.
|
// Package structs contains RPC wrappers for Notifications contract.
|
||||||
package structs
|
package structs
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/elliptic"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/neorpc/result"
|
"github.com/nspcc-dev/neo-go/pkg/neorpc/result"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||||
|
@ -17,72 +17,17 @@ import (
|
||||||
// Hash contains contract hash.
|
// Hash contains contract hash.
|
||||||
var Hash = util.Uint160{0x33, 0x22, 0x11, 0x0, 0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x0}
|
var Hash = util.Uint160{0x33, 0x22, 0x11, 0x0, 0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x0}
|
||||||
|
|
||||||
// LedgerBlock is a contract-specific ledger.Block type used by its methods.
|
|
||||||
type LedgerBlock struct {
|
|
||||||
Hash util.Uint256
|
|
||||||
Version *big.Int
|
|
||||||
PrevHash util.Uint256
|
|
||||||
MerkleRoot util.Uint256
|
|
||||||
Timestamp *big.Int
|
|
||||||
Nonce *big.Int
|
|
||||||
Index *big.Int
|
|
||||||
NextConsensus util.Uint160
|
|
||||||
TransactionsLength *big.Int
|
|
||||||
}
|
|
||||||
|
|
||||||
// LedgerBlockSR is a contract-specific ledger.BlockSR type used by its methods.
|
|
||||||
type LedgerBlockSR struct {
|
|
||||||
Hash util.Uint256
|
|
||||||
Version *big.Int
|
|
||||||
PrevHash util.Uint256
|
|
||||||
MerkleRoot util.Uint256
|
|
||||||
Timestamp *big.Int
|
|
||||||
Nonce *big.Int
|
|
||||||
Index *big.Int
|
|
||||||
NextConsensus util.Uint160
|
|
||||||
TransactionsLength *big.Int
|
|
||||||
PrevStateRoot util.Uint256
|
|
||||||
}
|
|
||||||
|
|
||||||
// LedgerTransaction is a contract-specific ledger.Transaction type used by its methods.
|
|
||||||
type LedgerTransaction struct {
|
|
||||||
Hash util.Uint256
|
|
||||||
Version *big.Int
|
|
||||||
Nonce *big.Int
|
|
||||||
Sender util.Uint160
|
|
||||||
SysFee *big.Int
|
|
||||||
NetFee *big.Int
|
|
||||||
ValidUntilBlock *big.Int
|
|
||||||
Script []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
// LedgerTransactionSigner is a contract-specific ledger.TransactionSigner type used by its methods.
|
|
||||||
type LedgerTransactionSigner struct {
|
|
||||||
Account util.Uint160
|
|
||||||
Scopes *big.Int
|
|
||||||
AllowedContracts []util.Uint160
|
|
||||||
AllowedGroups keys.PublicKeys
|
|
||||||
Rules []*LedgerWitnessRule
|
|
||||||
}
|
|
||||||
|
|
||||||
// LedgerWitnessCondition is a contract-specific ledger.WitnessCondition type used by its methods.
|
|
||||||
type LedgerWitnessCondition struct {
|
|
||||||
Type *big.Int
|
|
||||||
Value any
|
|
||||||
}
|
|
||||||
|
|
||||||
// LedgerWitnessRule is a contract-specific ledger.WitnessRule type used by its methods.
|
|
||||||
type LedgerWitnessRule struct {
|
|
||||||
Action *big.Int
|
|
||||||
Condition *LedgerWitnessCondition
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unnamed is a contract-specific unnamed type used by its methods.
|
// Unnamed is a contract-specific unnamed type used by its methods.
|
||||||
type Unnamed struct {
|
type Unnamed struct {
|
||||||
I *big.Int
|
I *big.Int
|
||||||
B bool
|
B bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UnnamedX is a contract-specific unnamedX type used by its methods.
|
||||||
|
type UnnamedX struct {
|
||||||
|
I *big.Int
|
||||||
|
}
|
||||||
|
|
||||||
// ComplicatedNameEvent represents "! complicated name %$#" event emitted by the contract.
|
// ComplicatedNameEvent represents "! complicated name %$#" event emitted by the contract.
|
||||||
type ComplicatedNameEvent struct {
|
type ComplicatedNameEvent struct {
|
||||||
ComplicatedParam string
|
ComplicatedParam string
|
||||||
|
@ -103,6 +48,11 @@ type SomeArrayEvent struct {
|
||||||
A [][]*big.Int
|
A [][]*big.Int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SomeUnexportedFieldEvent represents "SomeUnexportedField" event emitted by the contract.
|
||||||
|
type SomeUnexportedFieldEvent struct {
|
||||||
|
S *UnnamedX
|
||||||
|
}
|
||||||
|
|
||||||
// Actor is used by Contract to call state-changing methods.
|
// Actor is used by Contract to call state-changing methods.
|
||||||
type Actor interface {
|
type Actor interface {
|
||||||
MakeCall(contract util.Uint160, method string, params ...any) (*transaction.Transaction, error)
|
MakeCall(contract util.Uint160, method string, params ...any) (*transaction.Transaction, error)
|
||||||
|
@ -213,567 +163,26 @@ func (c *Contract) StructUnsigned() (*transaction.Transaction, error) {
|
||||||
return c.actor.MakeUnsignedCall(c.hash, "struct", nil)
|
return c.actor.MakeUnsignedCall(c.hash, "struct", nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// itemToLedgerBlock converts stack item into *LedgerBlock.
|
// UnexportedField creates a transaction invoking `unexportedField` method of the contract.
|
||||||
func itemToLedgerBlock(item stackitem.Item, err error) (*LedgerBlock, error) {
|
// This transaction is signed and immediately sent to the network.
|
||||||
if err != nil {
|
// The values returned are its hash, ValidUntilBlock value and error if any.
|
||||||
return nil, err
|
func (c *Contract) UnexportedField() (util.Uint256, uint32, error) {
|
||||||
}
|
return c.actor.SendCall(c.hash, "unexportedField")
|
||||||
var res = new(LedgerBlock)
|
|
||||||
err = res.FromStackItem(item)
|
|
||||||
return res, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// FromStackItem retrieves fields of LedgerBlock from the given
|
// UnexportedFieldTransaction creates a transaction invoking `unexportedField` method of the contract.
|
||||||
// [stackitem.Item] or returns an error if it's not possible to do to so.
|
// This transaction is signed, but not sent to the network, instead it's
|
||||||
func (res *LedgerBlock) FromStackItem(item stackitem.Item) error {
|
// returned to the caller.
|
||||||
arr, ok := item.Value().([]stackitem.Item)
|
func (c *Contract) UnexportedFieldTransaction() (*transaction.Transaction, error) {
|
||||||
if !ok {
|
return c.actor.MakeCall(c.hash, "unexportedField")
|
||||||
return errors.New("not an array")
|
|
||||||
}
|
|
||||||
if len(arr) != 9 {
|
|
||||||
return errors.New("wrong number of structure elements")
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
index = -1
|
|
||||||
err error
|
|
||||||
)
|
|
||||||
index++
|
|
||||||
res.Hash, err = func (item stackitem.Item) (util.Uint256, error) {
|
|
||||||
b, err := item.TryBytes()
|
|
||||||
if err != nil {
|
|
||||||
return util.Uint256{}, err
|
|
||||||
}
|
|
||||||
u, err := util.Uint256DecodeBytesBE(b)
|
|
||||||
if err != nil {
|
|
||||||
return util.Uint256{}, err
|
|
||||||
}
|
|
||||||
return u, nil
|
|
||||||
} (arr[index])
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("field Hash: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
index++
|
|
||||||
res.Version, err = arr[index].TryInteger()
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("field Version: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
index++
|
|
||||||
res.PrevHash, err = func (item stackitem.Item) (util.Uint256, error) {
|
|
||||||
b, err := item.TryBytes()
|
|
||||||
if err != nil {
|
|
||||||
return util.Uint256{}, err
|
|
||||||
}
|
|
||||||
u, err := util.Uint256DecodeBytesBE(b)
|
|
||||||
if err != nil {
|
|
||||||
return util.Uint256{}, err
|
|
||||||
}
|
|
||||||
return u, nil
|
|
||||||
} (arr[index])
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("field PrevHash: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
index++
|
|
||||||
res.MerkleRoot, err = func (item stackitem.Item) (util.Uint256, error) {
|
|
||||||
b, err := item.TryBytes()
|
|
||||||
if err != nil {
|
|
||||||
return util.Uint256{}, err
|
|
||||||
}
|
|
||||||
u, err := util.Uint256DecodeBytesBE(b)
|
|
||||||
if err != nil {
|
|
||||||
return util.Uint256{}, err
|
|
||||||
}
|
|
||||||
return u, nil
|
|
||||||
} (arr[index])
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("field MerkleRoot: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
index++
|
|
||||||
res.Timestamp, err = arr[index].TryInteger()
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("field Timestamp: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
index++
|
|
||||||
res.Nonce, err = arr[index].TryInteger()
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("field Nonce: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
index++
|
|
||||||
res.Index, err = arr[index].TryInteger()
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("field Index: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
index++
|
|
||||||
res.NextConsensus, err = func (item stackitem.Item) (util.Uint160, error) {
|
|
||||||
b, err := item.TryBytes()
|
|
||||||
if err != nil {
|
|
||||||
return util.Uint160{}, err
|
|
||||||
}
|
|
||||||
u, err := util.Uint160DecodeBytesBE(b)
|
|
||||||
if err != nil {
|
|
||||||
return util.Uint160{}, err
|
|
||||||
}
|
|
||||||
return u, nil
|
|
||||||
} (arr[index])
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("field NextConsensus: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
index++
|
|
||||||
res.TransactionsLength, err = arr[index].TryInteger()
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("field TransactionsLength: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// itemToLedgerBlockSR converts stack item into *LedgerBlockSR.
|
// UnexportedFieldUnsigned creates a transaction invoking `unexportedField` method of the contract.
|
||||||
func itemToLedgerBlockSR(item stackitem.Item, err error) (*LedgerBlockSR, error) {
|
// This transaction is not signed, it's simply returned to the caller.
|
||||||
if err != nil {
|
// Any fields of it that do not affect fees can be changed (ValidUntilBlock,
|
||||||
return nil, err
|
// Nonce), fee values (NetworkFee, SystemFee) can be increased as well.
|
||||||
}
|
func (c *Contract) UnexportedFieldUnsigned() (*transaction.Transaction, error) {
|
||||||
var res = new(LedgerBlockSR)
|
return c.actor.MakeUnsignedCall(c.hash, "unexportedField", nil)
|
||||||
err = res.FromStackItem(item)
|
|
||||||
return res, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// FromStackItem retrieves fields of LedgerBlockSR from the given
|
|
||||||
// [stackitem.Item] or returns an error if it's not possible to do to so.
|
|
||||||
func (res *LedgerBlockSR) FromStackItem(item stackitem.Item) error {
|
|
||||||
arr, ok := item.Value().([]stackitem.Item)
|
|
||||||
if !ok {
|
|
||||||
return errors.New("not an array")
|
|
||||||
}
|
|
||||||
if len(arr) != 10 {
|
|
||||||
return errors.New("wrong number of structure elements")
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
index = -1
|
|
||||||
err error
|
|
||||||
)
|
|
||||||
index++
|
|
||||||
res.Hash, err = func (item stackitem.Item) (util.Uint256, error) {
|
|
||||||
b, err := item.TryBytes()
|
|
||||||
if err != nil {
|
|
||||||
return util.Uint256{}, err
|
|
||||||
}
|
|
||||||
u, err := util.Uint256DecodeBytesBE(b)
|
|
||||||
if err != nil {
|
|
||||||
return util.Uint256{}, err
|
|
||||||
}
|
|
||||||
return u, nil
|
|
||||||
} (arr[index])
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("field Hash: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
index++
|
|
||||||
res.Version, err = arr[index].TryInteger()
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("field Version: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
index++
|
|
||||||
res.PrevHash, err = func (item stackitem.Item) (util.Uint256, error) {
|
|
||||||
b, err := item.TryBytes()
|
|
||||||
if err != nil {
|
|
||||||
return util.Uint256{}, err
|
|
||||||
}
|
|
||||||
u, err := util.Uint256DecodeBytesBE(b)
|
|
||||||
if err != nil {
|
|
||||||
return util.Uint256{}, err
|
|
||||||
}
|
|
||||||
return u, nil
|
|
||||||
} (arr[index])
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("field PrevHash: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
index++
|
|
||||||
res.MerkleRoot, err = func (item stackitem.Item) (util.Uint256, error) {
|
|
||||||
b, err := item.TryBytes()
|
|
||||||
if err != nil {
|
|
||||||
return util.Uint256{}, err
|
|
||||||
}
|
|
||||||
u, err := util.Uint256DecodeBytesBE(b)
|
|
||||||
if err != nil {
|
|
||||||
return util.Uint256{}, err
|
|
||||||
}
|
|
||||||
return u, nil
|
|
||||||
} (arr[index])
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("field MerkleRoot: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
index++
|
|
||||||
res.Timestamp, err = arr[index].TryInteger()
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("field Timestamp: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
index++
|
|
||||||
res.Nonce, err = arr[index].TryInteger()
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("field Nonce: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
index++
|
|
||||||
res.Index, err = arr[index].TryInteger()
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("field Index: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
index++
|
|
||||||
res.NextConsensus, err = func (item stackitem.Item) (util.Uint160, error) {
|
|
||||||
b, err := item.TryBytes()
|
|
||||||
if err != nil {
|
|
||||||
return util.Uint160{}, err
|
|
||||||
}
|
|
||||||
u, err := util.Uint160DecodeBytesBE(b)
|
|
||||||
if err != nil {
|
|
||||||
return util.Uint160{}, err
|
|
||||||
}
|
|
||||||
return u, nil
|
|
||||||
} (arr[index])
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("field NextConsensus: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
index++
|
|
||||||
res.TransactionsLength, err = arr[index].TryInteger()
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("field TransactionsLength: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
index++
|
|
||||||
res.PrevStateRoot, err = func (item stackitem.Item) (util.Uint256, error) {
|
|
||||||
b, err := item.TryBytes()
|
|
||||||
if err != nil {
|
|
||||||
return util.Uint256{}, err
|
|
||||||
}
|
|
||||||
u, err := util.Uint256DecodeBytesBE(b)
|
|
||||||
if err != nil {
|
|
||||||
return util.Uint256{}, err
|
|
||||||
}
|
|
||||||
return u, nil
|
|
||||||
} (arr[index])
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("field PrevStateRoot: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// itemToLedgerTransaction converts stack item into *LedgerTransaction.
|
|
||||||
func itemToLedgerTransaction(item stackitem.Item, err error) (*LedgerTransaction, error) {
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
var res = new(LedgerTransaction)
|
|
||||||
err = res.FromStackItem(item)
|
|
||||||
return res, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// FromStackItem retrieves fields of LedgerTransaction from the given
|
|
||||||
// [stackitem.Item] or returns an error if it's not possible to do to so.
|
|
||||||
func (res *LedgerTransaction) FromStackItem(item stackitem.Item) error {
|
|
||||||
arr, ok := item.Value().([]stackitem.Item)
|
|
||||||
if !ok {
|
|
||||||
return errors.New("not an array")
|
|
||||||
}
|
|
||||||
if len(arr) != 8 {
|
|
||||||
return errors.New("wrong number of structure elements")
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
index = -1
|
|
||||||
err error
|
|
||||||
)
|
|
||||||
index++
|
|
||||||
res.Hash, err = func (item stackitem.Item) (util.Uint256, error) {
|
|
||||||
b, err := item.TryBytes()
|
|
||||||
if err != nil {
|
|
||||||
return util.Uint256{}, err
|
|
||||||
}
|
|
||||||
u, err := util.Uint256DecodeBytesBE(b)
|
|
||||||
if err != nil {
|
|
||||||
return util.Uint256{}, err
|
|
||||||
}
|
|
||||||
return u, nil
|
|
||||||
} (arr[index])
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("field Hash: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
index++
|
|
||||||
res.Version, err = arr[index].TryInteger()
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("field Version: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
index++
|
|
||||||
res.Nonce, err = arr[index].TryInteger()
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("field Nonce: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
index++
|
|
||||||
res.Sender, err = func (item stackitem.Item) (util.Uint160, error) {
|
|
||||||
b, err := item.TryBytes()
|
|
||||||
if err != nil {
|
|
||||||
return util.Uint160{}, err
|
|
||||||
}
|
|
||||||
u, err := util.Uint160DecodeBytesBE(b)
|
|
||||||
if err != nil {
|
|
||||||
return util.Uint160{}, err
|
|
||||||
}
|
|
||||||
return u, nil
|
|
||||||
} (arr[index])
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("field Sender: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
index++
|
|
||||||
res.SysFee, err = arr[index].TryInteger()
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("field SysFee: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
index++
|
|
||||||
res.NetFee, err = arr[index].TryInteger()
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("field NetFee: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
index++
|
|
||||||
res.ValidUntilBlock, err = arr[index].TryInteger()
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("field ValidUntilBlock: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
index++
|
|
||||||
res.Script, err = arr[index].TryBytes()
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("field Script: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// itemToLedgerTransactionSigner converts stack item into *LedgerTransactionSigner.
|
|
||||||
func itemToLedgerTransactionSigner(item stackitem.Item, err error) (*LedgerTransactionSigner, error) {
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
var res = new(LedgerTransactionSigner)
|
|
||||||
err = res.FromStackItem(item)
|
|
||||||
return res, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// FromStackItem retrieves fields of LedgerTransactionSigner from the given
|
|
||||||
// [stackitem.Item] or returns an error if it's not possible to do to so.
|
|
||||||
func (res *LedgerTransactionSigner) FromStackItem(item stackitem.Item) error {
|
|
||||||
arr, ok := item.Value().([]stackitem.Item)
|
|
||||||
if !ok {
|
|
||||||
return errors.New("not an array")
|
|
||||||
}
|
|
||||||
if len(arr) != 5 {
|
|
||||||
return errors.New("wrong number of structure elements")
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
index = -1
|
|
||||||
err error
|
|
||||||
)
|
|
||||||
index++
|
|
||||||
res.Account, err = func (item stackitem.Item) (util.Uint160, error) {
|
|
||||||
b, err := item.TryBytes()
|
|
||||||
if err != nil {
|
|
||||||
return util.Uint160{}, err
|
|
||||||
}
|
|
||||||
u, err := util.Uint160DecodeBytesBE(b)
|
|
||||||
if err != nil {
|
|
||||||
return util.Uint160{}, err
|
|
||||||
}
|
|
||||||
return u, nil
|
|
||||||
} (arr[index])
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("field Account: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
index++
|
|
||||||
res.Scopes, err = arr[index].TryInteger()
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("field Scopes: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
index++
|
|
||||||
res.AllowedContracts, err = func (item stackitem.Item) ([]util.Uint160, error) {
|
|
||||||
arr, ok := item.Value().([]stackitem.Item)
|
|
||||||
if !ok {
|
|
||||||
return nil, errors.New("not an array")
|
|
||||||
}
|
|
||||||
res := make([]util.Uint160, len(arr))
|
|
||||||
for i := range res {
|
|
||||||
res[i], err = func (item stackitem.Item) (util.Uint160, error) {
|
|
||||||
b, err := item.TryBytes()
|
|
||||||
if err != nil {
|
|
||||||
return util.Uint160{}, err
|
|
||||||
}
|
|
||||||
u, err := util.Uint160DecodeBytesBE(b)
|
|
||||||
if err != nil {
|
|
||||||
return util.Uint160{}, err
|
|
||||||
}
|
|
||||||
return u, nil
|
|
||||||
} (arr[i])
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("item %d: %w", i, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return res, nil
|
|
||||||
} (arr[index])
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("field AllowedContracts: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
index++
|
|
||||||
res.AllowedGroups, err = func (item stackitem.Item) (keys.PublicKeys, error) {
|
|
||||||
arr, ok := item.Value().([]stackitem.Item)
|
|
||||||
if !ok {
|
|
||||||
return nil, errors.New("not an array")
|
|
||||||
}
|
|
||||||
res := make(keys.PublicKeys, len(arr))
|
|
||||||
for i := range res {
|
|
||||||
res[i], err = func (item stackitem.Item) (*keys.PublicKey, error) {
|
|
||||||
b, err := item.TryBytes()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
k, err := keys.NewPublicKeyFromBytes(b, elliptic.P256())
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return k, nil
|
|
||||||
} (arr[i])
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("item %d: %w", i, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return res, nil
|
|
||||||
} (arr[index])
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("field AllowedGroups: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
index++
|
|
||||||
res.Rules, err = func (item stackitem.Item) ([]*LedgerWitnessRule, error) {
|
|
||||||
arr, ok := item.Value().([]stackitem.Item)
|
|
||||||
if !ok {
|
|
||||||
return nil, errors.New("not an array")
|
|
||||||
}
|
|
||||||
res := make([]*LedgerWitnessRule, len(arr))
|
|
||||||
for i := range res {
|
|
||||||
res[i], err = itemToLedgerWitnessRule(arr[i], nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("item %d: %w", i, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return res, nil
|
|
||||||
} (arr[index])
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("field Rules: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// itemToLedgerWitnessCondition converts stack item into *LedgerWitnessCondition.
|
|
||||||
func itemToLedgerWitnessCondition(item stackitem.Item, err error) (*LedgerWitnessCondition, error) {
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
var res = new(LedgerWitnessCondition)
|
|
||||||
err = res.FromStackItem(item)
|
|
||||||
return res, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// FromStackItem retrieves fields of LedgerWitnessCondition from the given
|
|
||||||
// [stackitem.Item] or returns an error if it's not possible to do to so.
|
|
||||||
func (res *LedgerWitnessCondition) FromStackItem(item stackitem.Item) error {
|
|
||||||
arr, ok := item.Value().([]stackitem.Item)
|
|
||||||
if !ok {
|
|
||||||
return errors.New("not an array")
|
|
||||||
}
|
|
||||||
if len(arr) != 2 {
|
|
||||||
return errors.New("wrong number of structure elements")
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
index = -1
|
|
||||||
err error
|
|
||||||
)
|
|
||||||
index++
|
|
||||||
res.Type, err = arr[index].TryInteger()
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("field Type: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
index++
|
|
||||||
res.Value, err = arr[index].Value(), error(nil)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("field Value: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// itemToLedgerWitnessRule converts stack item into *LedgerWitnessRule.
|
|
||||||
func itemToLedgerWitnessRule(item stackitem.Item, err error) (*LedgerWitnessRule, error) {
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
var res = new(LedgerWitnessRule)
|
|
||||||
err = res.FromStackItem(item)
|
|
||||||
return res, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// FromStackItem retrieves fields of LedgerWitnessRule from the given
|
|
||||||
// [stackitem.Item] or returns an error if it's not possible to do to so.
|
|
||||||
func (res *LedgerWitnessRule) FromStackItem(item stackitem.Item) error {
|
|
||||||
arr, ok := item.Value().([]stackitem.Item)
|
|
||||||
if !ok {
|
|
||||||
return errors.New("not an array")
|
|
||||||
}
|
|
||||||
if len(arr) != 2 {
|
|
||||||
return errors.New("wrong number of structure elements")
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
index = -1
|
|
||||||
err error
|
|
||||||
)
|
|
||||||
index++
|
|
||||||
res.Action, err = arr[index].TryInteger()
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("field Action: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
index++
|
|
||||||
res.Condition, err = itemToLedgerWitnessCondition(arr[index], nil)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("field Condition: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// itemToUnnamed converts stack item into *Unnamed.
|
// itemToUnnamed converts stack item into *Unnamed.
|
||||||
|
@ -816,6 +225,40 @@ func (res *Unnamed) FromStackItem(item stackitem.Item) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// itemToUnnamedX converts stack item into *UnnamedX.
|
||||||
|
func itemToUnnamedX(item stackitem.Item, err error) (*UnnamedX, error) {
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var res = new(UnnamedX)
|
||||||
|
err = res.FromStackItem(item)
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// FromStackItem retrieves fields of UnnamedX from the given
|
||||||
|
// [stackitem.Item] or returns an error if it's not possible to do to so.
|
||||||
|
func (res *UnnamedX) FromStackItem(item stackitem.Item) error {
|
||||||
|
arr, ok := item.Value().([]stackitem.Item)
|
||||||
|
if !ok {
|
||||||
|
return errors.New("not an array")
|
||||||
|
}
|
||||||
|
if len(arr) != 1 {
|
||||||
|
return errors.New("wrong number of structure elements")
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
index = -1
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
index++
|
||||||
|
res.I, err = arr[index].TryInteger()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("field I: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// ComplicatedNameEventsFromApplicationLog retrieves a set of all emitted events
|
// ComplicatedNameEventsFromApplicationLog retrieves a set of all emitted events
|
||||||
// with "! complicated name %$#" name from the provided [result.ApplicationLog].
|
// with "! complicated name %$#" name from the provided [result.ApplicationLog].
|
||||||
func ComplicatedNameEventsFromApplicationLog(log *result.ApplicationLog) ([]*ComplicatedNameEvent, error) {
|
func ComplicatedNameEventsFromApplicationLog(log *result.ApplicationLog) ([]*ComplicatedNameEvent, error) {
|
||||||
|
@ -860,7 +303,7 @@ func (e *ComplicatedNameEvent) FromStackItem(item *stackitem.Array) error {
|
||||||
err error
|
err error
|
||||||
)
|
)
|
||||||
index++
|
index++
|
||||||
e.ComplicatedParam, err = func (item stackitem.Item) (string, error) {
|
e.ComplicatedParam, err = func(item stackitem.Item) (string, error) {
|
||||||
b, err := item.TryBytes()
|
b, err := item.TryBytes()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
|
@ -869,7 +312,7 @@ func (e *ComplicatedNameEvent) FromStackItem(item *stackitem.Array) error {
|
||||||
return "", errors.New("not a UTF-8 string")
|
return "", errors.New("not a UTF-8 string")
|
||||||
}
|
}
|
||||||
return string(b), nil
|
return string(b), nil
|
||||||
} (arr[index])
|
}(arr[index])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("field ComplicatedParam: %w", err)
|
return fmt.Errorf("field ComplicatedParam: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -921,7 +364,7 @@ func (e *SomeMapEvent) FromStackItem(item *stackitem.Array) error {
|
||||||
err error
|
err error
|
||||||
)
|
)
|
||||||
index++
|
index++
|
||||||
e.M, err = func (item stackitem.Item) (map[*big.Int][]map[string][]util.Uint160, error) {
|
e.M, err = func(item stackitem.Item) (map[*big.Int][]map[string][]util.Uint160, error) {
|
||||||
m, ok := item.Value().([]stackitem.MapElement)
|
m, ok := item.Value().([]stackitem.MapElement)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("%s is not a map", item.Type().String())
|
return nil, fmt.Errorf("%s is not a map", item.Type().String())
|
||||||
|
@ -932,21 +375,21 @@ func (e *SomeMapEvent) FromStackItem(item *stackitem.Array) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("key %d: %w", i, err)
|
return nil, fmt.Errorf("key %d: %w", i, err)
|
||||||
}
|
}
|
||||||
v, err := func (item stackitem.Item) ([]map[string][]util.Uint160, error) {
|
v, err := func(item stackitem.Item) ([]map[string][]util.Uint160, error) {
|
||||||
arr, ok := item.Value().([]stackitem.Item)
|
arr, ok := item.Value().([]stackitem.Item)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, errors.New("not an array")
|
return nil, errors.New("not an array")
|
||||||
}
|
}
|
||||||
res := make([]map[string][]util.Uint160, len(arr))
|
res := make([]map[string][]util.Uint160, len(arr))
|
||||||
for i := range res {
|
for i := range res {
|
||||||
res[i], err = func (item stackitem.Item) (map[string][]util.Uint160, error) {
|
res[i], err = func(item stackitem.Item) (map[string][]util.Uint160, error) {
|
||||||
m, ok := item.Value().([]stackitem.MapElement)
|
m, ok := item.Value().([]stackitem.MapElement)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("%s is not a map", item.Type().String())
|
return nil, fmt.Errorf("%s is not a map", item.Type().String())
|
||||||
}
|
}
|
||||||
res := make(map[string][]util.Uint160)
|
res := make(map[string][]util.Uint160)
|
||||||
for i := range m {
|
for i := range m {
|
||||||
k, err := func (item stackitem.Item) (string, error) {
|
k, err := func(item stackitem.Item) (string, error) {
|
||||||
b, err := item.TryBytes()
|
b, err := item.TryBytes()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
|
@ -955,18 +398,18 @@ func (e *SomeMapEvent) FromStackItem(item *stackitem.Array) error {
|
||||||
return "", errors.New("not a UTF-8 string")
|
return "", errors.New("not a UTF-8 string")
|
||||||
}
|
}
|
||||||
return string(b), nil
|
return string(b), nil
|
||||||
} (m[i].Key)
|
}(m[i].Key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("key %d: %w", i, err)
|
return nil, fmt.Errorf("key %d: %w", i, err)
|
||||||
}
|
}
|
||||||
v, err := func (item stackitem.Item) ([]util.Uint160, error) {
|
v, err := func(item stackitem.Item) ([]util.Uint160, error) {
|
||||||
arr, ok := item.Value().([]stackitem.Item)
|
arr, ok := item.Value().([]stackitem.Item)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, errors.New("not an array")
|
return nil, errors.New("not an array")
|
||||||
}
|
}
|
||||||
res := make([]util.Uint160, len(arr))
|
res := make([]util.Uint160, len(arr))
|
||||||
for i := range res {
|
for i := range res {
|
||||||
res[i], err = func (item stackitem.Item) (util.Uint160, error) {
|
res[i], err = func(item stackitem.Item) (util.Uint160, error) {
|
||||||
b, err := item.TryBytes()
|
b, err := item.TryBytes()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return util.Uint160{}, err
|
return util.Uint160{}, err
|
||||||
|
@ -976,33 +419,33 @@ func (e *SomeMapEvent) FromStackItem(item *stackitem.Array) error {
|
||||||
return util.Uint160{}, err
|
return util.Uint160{}, err
|
||||||
}
|
}
|
||||||
return u, nil
|
return u, nil
|
||||||
} (arr[i])
|
}(arr[i])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("item %d: %w", i, err)
|
return nil, fmt.Errorf("item %d: %w", i, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return res, nil
|
return res, nil
|
||||||
} (m[i].Value)
|
}(m[i].Value)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("value %d: %w", i, err)
|
return nil, fmt.Errorf("value %d: %w", i, err)
|
||||||
}
|
}
|
||||||
res[k] = v
|
res[k] = v
|
||||||
}
|
}
|
||||||
return res, nil
|
return res, nil
|
||||||
} (arr[i])
|
}(arr[i])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("item %d: %w", i, err)
|
return nil, fmt.Errorf("item %d: %w", i, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return res, nil
|
return res, nil
|
||||||
} (m[i].Value)
|
}(m[i].Value)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("value %d: %w", i, err)
|
return nil, fmt.Errorf("value %d: %w", i, err)
|
||||||
}
|
}
|
||||||
res[k] = v
|
res[k] = v
|
||||||
}
|
}
|
||||||
return res, nil
|
return res, nil
|
||||||
} (arr[index])
|
}(arr[index])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("field M: %w", err)
|
return fmt.Errorf("field M: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -1106,14 +549,14 @@ func (e *SomeArrayEvent) FromStackItem(item *stackitem.Array) error {
|
||||||
err error
|
err error
|
||||||
)
|
)
|
||||||
index++
|
index++
|
||||||
e.A, err = func (item stackitem.Item) ([][]*big.Int, error) {
|
e.A, err = func(item stackitem.Item) ([][]*big.Int, error) {
|
||||||
arr, ok := item.Value().([]stackitem.Item)
|
arr, ok := item.Value().([]stackitem.Item)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, errors.New("not an array")
|
return nil, errors.New("not an array")
|
||||||
}
|
}
|
||||||
res := make([][]*big.Int, len(arr))
|
res := make([][]*big.Int, len(arr))
|
||||||
for i := range res {
|
for i := range res {
|
||||||
res[i], err = func (item stackitem.Item) ([]*big.Int, error) {
|
res[i], err = func(item stackitem.Item) ([]*big.Int, error) {
|
||||||
arr, ok := item.Value().([]stackitem.Item)
|
arr, ok := item.Value().([]stackitem.Item)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, errors.New("not an array")
|
return nil, errors.New("not an array")
|
||||||
|
@ -1126,16 +569,68 @@ func (e *SomeArrayEvent) FromStackItem(item *stackitem.Array) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return res, nil
|
return res, nil
|
||||||
} (arr[i])
|
}(arr[i])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("item %d: %w", i, err)
|
return nil, fmt.Errorf("item %d: %w", i, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return res, nil
|
return res, nil
|
||||||
} (arr[index])
|
}(arr[index])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("field A: %w", err)
|
return fmt.Errorf("field A: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SomeUnexportedFieldEventsFromApplicationLog retrieves a set of all emitted events
|
||||||
|
// with "SomeUnexportedField" name from the provided [result.ApplicationLog].
|
||||||
|
func SomeUnexportedFieldEventsFromApplicationLog(log *result.ApplicationLog) ([]*SomeUnexportedFieldEvent, error) {
|
||||||
|
if log == nil {
|
||||||
|
return nil, errors.New("nil application log")
|
||||||
|
}
|
||||||
|
|
||||||
|
var res []*SomeUnexportedFieldEvent
|
||||||
|
for i, ex := range log.Executions {
|
||||||
|
for j, e := range ex.Events {
|
||||||
|
if e.Name != "SomeUnexportedField" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
event := new(SomeUnexportedFieldEvent)
|
||||||
|
err := event.FromStackItem(e.Item)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to deserialize SomeUnexportedFieldEvent from stackitem (execution #%d, event #%d): %w", i, j, err)
|
||||||
|
}
|
||||||
|
res = append(res, event)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// FromStackItem converts provided [stackitem.Array] to SomeUnexportedFieldEvent or
|
||||||
|
// returns an error if it's not possible to do to so.
|
||||||
|
func (e *SomeUnexportedFieldEvent) FromStackItem(item *stackitem.Array) error {
|
||||||
|
if item == nil {
|
||||||
|
return errors.New("nil item")
|
||||||
|
}
|
||||||
|
arr, ok := item.Value().([]stackitem.Item)
|
||||||
|
if !ok {
|
||||||
|
return errors.New("not an array")
|
||||||
|
}
|
||||||
|
if len(arr) != 1 {
|
||||||
|
return errors.New("wrong number of structure elements")
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
index = -1
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
index++
|
||||||
|
e.S, err = itemToUnnamedX(arr[index], nil)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("field S: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
40
cli/smartcontract/testdata/rpcbindings/structs/structs.go
vendored
Normal file
40
cli/smartcontract/testdata/rpcbindings/structs/structs.go
vendored
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
package structs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/interop"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/interop/native/ledger"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/interop/native/management"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Internal struct {
|
||||||
|
Bool bool
|
||||||
|
Int int
|
||||||
|
Bytes []byte
|
||||||
|
String string
|
||||||
|
H160 interop.Hash160
|
||||||
|
H256 interop.Hash256
|
||||||
|
PK interop.PublicKey
|
||||||
|
PubKey interop.PublicKey
|
||||||
|
Sign interop.Signature
|
||||||
|
ArrOfBytes [][]byte
|
||||||
|
ArrOfH160 []interop.Hash160
|
||||||
|
Map map[int][]interop.PublicKey
|
||||||
|
Struct *Internal
|
||||||
|
unexportedField int // this one should be exported in the resulting RPC binding.
|
||||||
|
}
|
||||||
|
|
||||||
|
func Contract(mc management.Contract) management.Contract {
|
||||||
|
return mc
|
||||||
|
}
|
||||||
|
|
||||||
|
func Block(b *ledger.Block) *ledger.Block {
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func Transaction(t *ledger.Transaction) *ledger.Transaction {
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
|
||||||
|
func Struct(s *Internal) *Internal {
|
||||||
|
return s
|
||||||
|
}
|
|
@ -1,3 +1,3 @@
|
||||||
name: "Types"
|
name: "Types"
|
||||||
sourceurl: https://github.com/nspcc-dev/neo-go/
|
sourceurl: https://github.com/nspcc-dev/neo-go/
|
||||||
safemethods: ["bool", "int", "bytes", "string", "any", "hash160", "hash256", "publicKey", "signature", "bools", "ints", "bytess", "strings", "hash160s", "hash256s", "publicKeys", "signatures", "aAAStrings", "maps", "crazyMaps", "anyMaps"]
|
safemethods: ["bool", "int", "bytes", "string", "any", "hash160", "hash256", "publicKey", "signature", "bools", "ints", "bytess", "strings", "hash160s", "hash256s", "publicKeys", "signatures", "aAAStrings", "maps", "crazyMaps", "anyMaps", "unnamedStructs", "unnamedStructsX"]
|
|
@ -1,3 +1,5 @@
|
||||||
|
// Code generated by neo-go contract generate-rpcwrapper --manifest <file.json> --out <file.go> [--hash <hash>] [--config <config>]; DO NOT EDIT.
|
||||||
|
|
||||||
// Package types contains RPC wrappers for Types contract.
|
// Package types contains RPC wrappers for Types contract.
|
||||||
package types
|
package types
|
||||||
|
|
||||||
|
@ -16,6 +18,17 @@ import (
|
||||||
// Hash contains contract hash.
|
// Hash contains contract hash.
|
||||||
var Hash = util.Uint160{0x33, 0x22, 0x11, 0x0, 0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x0}
|
var Hash = util.Uint160{0x33, 0x22, 0x11, 0x0, 0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x0}
|
||||||
|
|
||||||
|
// Unnamed is a contract-specific unnamed type used by its methods.
|
||||||
|
type Unnamed struct {
|
||||||
|
I *big.Int
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnnamedX is a contract-specific unnamedX type used by its methods.
|
||||||
|
type UnnamedX struct {
|
||||||
|
I *big.Int
|
||||||
|
B bool
|
||||||
|
}
|
||||||
|
|
||||||
// Invoker is used by ContractReader to call various safe methods.
|
// Invoker is used by ContractReader to call various safe methods.
|
||||||
type Invoker interface {
|
type Invoker interface {
|
||||||
Call(contract util.Uint160, operation string, params ...any) (*result.Invoke, error)
|
Call(contract util.Uint160, operation string, params ...any) (*result.Invoke, error)
|
||||||
|
@ -35,32 +48,32 @@ func NewReader(invoker Invoker) *ContractReader {
|
||||||
|
|
||||||
// AAAStrings invokes `aAAStrings` method of contract.
|
// AAAStrings invokes `aAAStrings` method of contract.
|
||||||
func (c *ContractReader) AAAStrings(s [][][]string) ([][][]string, error) {
|
func (c *ContractReader) AAAStrings(s [][][]string) ([][][]string, error) {
|
||||||
return func (item stackitem.Item, err error) ([][][]string, error) {
|
return func(item stackitem.Item, err error) ([][][]string, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return func (item stackitem.Item) ([][][]string, error) {
|
return func(item stackitem.Item) ([][][]string, error) {
|
||||||
arr, ok := item.Value().([]stackitem.Item)
|
arr, ok := item.Value().([]stackitem.Item)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, errors.New("not an array")
|
return nil, errors.New("not an array")
|
||||||
}
|
}
|
||||||
res := make([][][]string, len(arr))
|
res := make([][][]string, len(arr))
|
||||||
for i := range res {
|
for i := range res {
|
||||||
res[i], err = func (item stackitem.Item) ([][]string, error) {
|
res[i], err = func(item stackitem.Item) ([][]string, error) {
|
||||||
arr, ok := item.Value().([]stackitem.Item)
|
arr, ok := item.Value().([]stackitem.Item)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, errors.New("not an array")
|
return nil, errors.New("not an array")
|
||||||
}
|
}
|
||||||
res := make([][]string, len(arr))
|
res := make([][]string, len(arr))
|
||||||
for i := range res {
|
for i := range res {
|
||||||
res[i], err = func (item stackitem.Item) ([]string, error) {
|
res[i], err = func(item stackitem.Item) ([]string, error) {
|
||||||
arr, ok := item.Value().([]stackitem.Item)
|
arr, ok := item.Value().([]stackitem.Item)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, errors.New("not an array")
|
return nil, errors.New("not an array")
|
||||||
}
|
}
|
||||||
res := make([]string, len(arr))
|
res := make([]string, len(arr))
|
||||||
for i := range res {
|
for i := range res {
|
||||||
res[i], err = func (item stackitem.Item) (string, error) {
|
res[i], err = func(item stackitem.Item) (string, error) {
|
||||||
b, err := item.TryBytes()
|
b, err := item.TryBytes()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
|
@ -69,45 +82,45 @@ func (c *ContractReader) AAAStrings(s [][][]string) ([][][]string, error) {
|
||||||
return "", errors.New("not a UTF-8 string")
|
return "", errors.New("not a UTF-8 string")
|
||||||
}
|
}
|
||||||
return string(b), nil
|
return string(b), nil
|
||||||
} (arr[i])
|
}(arr[i])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("item %d: %w", i, err)
|
return nil, fmt.Errorf("item %d: %w", i, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return res, nil
|
return res, nil
|
||||||
} (arr[i])
|
}(arr[i])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("item %d: %w", i, err)
|
return nil, fmt.Errorf("item %d: %w", i, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return res, nil
|
return res, nil
|
||||||
} (arr[i])
|
}(arr[i])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("item %d: %w", i, err)
|
return nil, fmt.Errorf("item %d: %w", i, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return res, nil
|
return res, nil
|
||||||
} (item)
|
}(item)
|
||||||
} (unwrap.Item(c.invoker.Call(c.hash, "aAAStrings", s)))
|
}(unwrap.Item(c.invoker.Call(c.hash, "aAAStrings", s)))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Any invokes `any` method of contract.
|
// Any invokes `any` method of contract.
|
||||||
func (c *ContractReader) Any(a any) (any, error) {
|
func (c *ContractReader) Any(a any) (any, error) {
|
||||||
return func (item stackitem.Item, err error) (any, error) {
|
return func(item stackitem.Item, err error) (any, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return item.Value(), error(nil)
|
return item.Value(), error(nil)
|
||||||
} (unwrap.Item(c.invoker.Call(c.hash, "any", a)))
|
}(unwrap.Item(c.invoker.Call(c.hash, "any", a)))
|
||||||
}
|
}
|
||||||
|
|
||||||
// AnyMaps invokes `anyMaps` method of contract.
|
// AnyMaps invokes `anyMaps` method of contract.
|
||||||
func (c *ContractReader) AnyMaps(m map[*big.Int]any) (map[*big.Int]any, error) {
|
func (c *ContractReader) AnyMaps(m map[*big.Int]any) (map[*big.Int]any, error) {
|
||||||
return func (item stackitem.Item, err error) (map[*big.Int]any, error) {
|
return func(item stackitem.Item, err error) (map[*big.Int]any, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return func (item stackitem.Item) (map[*big.Int]any, error) {
|
return func(item stackitem.Item) (map[*big.Int]any, error) {
|
||||||
m, ok := item.Value().([]stackitem.MapElement)
|
m, ok := item.Value().([]stackitem.MapElement)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("%s is not a map", item.Type().String())
|
return nil, fmt.Errorf("%s is not a map", item.Type().String())
|
||||||
|
@ -125,8 +138,8 @@ func (c *ContractReader) AnyMaps(m map[*big.Int]any) (map[*big.Int]any, error) {
|
||||||
res[k] = v
|
res[k] = v
|
||||||
}
|
}
|
||||||
return res, nil
|
return res, nil
|
||||||
} (item)
|
}(item)
|
||||||
} (unwrap.Item(c.invoker.Call(c.hash, "anyMaps", m)))
|
}(unwrap.Item(c.invoker.Call(c.hash, "anyMaps", m)))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bool invokes `bool` method of contract.
|
// Bool invokes `bool` method of contract.
|
||||||
|
@ -151,11 +164,11 @@ func (c *ContractReader) Bytess(b [][]byte) ([][]byte, error) {
|
||||||
|
|
||||||
// CrazyMaps invokes `crazyMaps` method of contract.
|
// CrazyMaps invokes `crazyMaps` method of contract.
|
||||||
func (c *ContractReader) CrazyMaps(m map[*big.Int][]map[string][]util.Uint160) (map[*big.Int][]map[string][]util.Uint160, error) {
|
func (c *ContractReader) CrazyMaps(m map[*big.Int][]map[string][]util.Uint160) (map[*big.Int][]map[string][]util.Uint160, error) {
|
||||||
return func (item stackitem.Item, err error) (map[*big.Int][]map[string][]util.Uint160, error) {
|
return func(item stackitem.Item, err error) (map[*big.Int][]map[string][]util.Uint160, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return func (item stackitem.Item) (map[*big.Int][]map[string][]util.Uint160, error) {
|
return func(item stackitem.Item) (map[*big.Int][]map[string][]util.Uint160, error) {
|
||||||
m, ok := item.Value().([]stackitem.MapElement)
|
m, ok := item.Value().([]stackitem.MapElement)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("%s is not a map", item.Type().String())
|
return nil, fmt.Errorf("%s is not a map", item.Type().String())
|
||||||
|
@ -166,21 +179,21 @@ func (c *ContractReader) CrazyMaps(m map[*big.Int][]map[string][]util.Uint160) (
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("key %d: %w", i, err)
|
return nil, fmt.Errorf("key %d: %w", i, err)
|
||||||
}
|
}
|
||||||
v, err := func (item stackitem.Item) ([]map[string][]util.Uint160, error) {
|
v, err := func(item stackitem.Item) ([]map[string][]util.Uint160, error) {
|
||||||
arr, ok := item.Value().([]stackitem.Item)
|
arr, ok := item.Value().([]stackitem.Item)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, errors.New("not an array")
|
return nil, errors.New("not an array")
|
||||||
}
|
}
|
||||||
res := make([]map[string][]util.Uint160, len(arr))
|
res := make([]map[string][]util.Uint160, len(arr))
|
||||||
for i := range res {
|
for i := range res {
|
||||||
res[i], err = func (item stackitem.Item) (map[string][]util.Uint160, error) {
|
res[i], err = func(item stackitem.Item) (map[string][]util.Uint160, error) {
|
||||||
m, ok := item.Value().([]stackitem.MapElement)
|
m, ok := item.Value().([]stackitem.MapElement)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("%s is not a map", item.Type().String())
|
return nil, fmt.Errorf("%s is not a map", item.Type().String())
|
||||||
}
|
}
|
||||||
res := make(map[string][]util.Uint160)
|
res := make(map[string][]util.Uint160)
|
||||||
for i := range m {
|
for i := range m {
|
||||||
k, err := func (item stackitem.Item) (string, error) {
|
k, err := func(item stackitem.Item) (string, error) {
|
||||||
b, err := item.TryBytes()
|
b, err := item.TryBytes()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
|
@ -189,18 +202,18 @@ func (c *ContractReader) CrazyMaps(m map[*big.Int][]map[string][]util.Uint160) (
|
||||||
return "", errors.New("not a UTF-8 string")
|
return "", errors.New("not a UTF-8 string")
|
||||||
}
|
}
|
||||||
return string(b), nil
|
return string(b), nil
|
||||||
} (m[i].Key)
|
}(m[i].Key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("key %d: %w", i, err)
|
return nil, fmt.Errorf("key %d: %w", i, err)
|
||||||
}
|
}
|
||||||
v, err := func (item stackitem.Item) ([]util.Uint160, error) {
|
v, err := func(item stackitem.Item) ([]util.Uint160, error) {
|
||||||
arr, ok := item.Value().([]stackitem.Item)
|
arr, ok := item.Value().([]stackitem.Item)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, errors.New("not an array")
|
return nil, errors.New("not an array")
|
||||||
}
|
}
|
||||||
res := make([]util.Uint160, len(arr))
|
res := make([]util.Uint160, len(arr))
|
||||||
for i := range res {
|
for i := range res {
|
||||||
res[i], err = func (item stackitem.Item) (util.Uint160, error) {
|
res[i], err = func(item stackitem.Item) (util.Uint160, error) {
|
||||||
b, err := item.TryBytes()
|
b, err := item.TryBytes()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return util.Uint160{}, err
|
return util.Uint160{}, err
|
||||||
|
@ -210,34 +223,34 @@ func (c *ContractReader) CrazyMaps(m map[*big.Int][]map[string][]util.Uint160) (
|
||||||
return util.Uint160{}, err
|
return util.Uint160{}, err
|
||||||
}
|
}
|
||||||
return u, nil
|
return u, nil
|
||||||
} (arr[i])
|
}(arr[i])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("item %d: %w", i, err)
|
return nil, fmt.Errorf("item %d: %w", i, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return res, nil
|
return res, nil
|
||||||
} (m[i].Value)
|
}(m[i].Value)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("value %d: %w", i, err)
|
return nil, fmt.Errorf("value %d: %w", i, err)
|
||||||
}
|
}
|
||||||
res[k] = v
|
res[k] = v
|
||||||
}
|
}
|
||||||
return res, nil
|
return res, nil
|
||||||
} (arr[i])
|
}(arr[i])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("item %d: %w", i, err)
|
return nil, fmt.Errorf("item %d: %w", i, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return res, nil
|
return res, nil
|
||||||
} (m[i].Value)
|
}(m[i].Value)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("value %d: %w", i, err)
|
return nil, fmt.Errorf("value %d: %w", i, err)
|
||||||
}
|
}
|
||||||
res[k] = v
|
res[k] = v
|
||||||
}
|
}
|
||||||
return res, nil
|
return res, nil
|
||||||
} (item)
|
}(item)
|
||||||
} (unwrap.Item(c.invoker.Call(c.hash, "crazyMaps", m)))
|
}(unwrap.Item(c.invoker.Call(c.hash, "crazyMaps", m)))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hash160 invokes `hash160` method of contract.
|
// Hash160 invokes `hash160` method of contract.
|
||||||
|
@ -272,18 +285,18 @@ func (c *ContractReader) Ints(i []*big.Int) ([]*big.Int, error) {
|
||||||
|
|
||||||
// Maps invokes `maps` method of contract.
|
// Maps invokes `maps` method of contract.
|
||||||
func (c *ContractReader) Maps(m map[string]string) (map[string]string, error) {
|
func (c *ContractReader) Maps(m map[string]string) (map[string]string, error) {
|
||||||
return func (item stackitem.Item, err error) (map[string]string, error) {
|
return func(item stackitem.Item, err error) (map[string]string, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return func (item stackitem.Item) (map[string]string, error) {
|
return func(item stackitem.Item) (map[string]string, error) {
|
||||||
m, ok := item.Value().([]stackitem.MapElement)
|
m, ok := item.Value().([]stackitem.MapElement)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("%s is not a map", item.Type().String())
|
return nil, fmt.Errorf("%s is not a map", item.Type().String())
|
||||||
}
|
}
|
||||||
res := make(map[string]string)
|
res := make(map[string]string)
|
||||||
for i := range m {
|
for i := range m {
|
||||||
k, err := func (item stackitem.Item) (string, error) {
|
k, err := func(item stackitem.Item) (string, error) {
|
||||||
b, err := item.TryBytes()
|
b, err := item.TryBytes()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
|
@ -292,11 +305,11 @@ func (c *ContractReader) Maps(m map[string]string) (map[string]string, error) {
|
||||||
return "", errors.New("not a UTF-8 string")
|
return "", errors.New("not a UTF-8 string")
|
||||||
}
|
}
|
||||||
return string(b), nil
|
return string(b), nil
|
||||||
} (m[i].Key)
|
}(m[i].Key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("key %d: %w", i, err)
|
return nil, fmt.Errorf("key %d: %w", i, err)
|
||||||
}
|
}
|
||||||
v, err := func (item stackitem.Item) (string, error) {
|
v, err := func(item stackitem.Item) (string, error) {
|
||||||
b, err := item.TryBytes()
|
b, err := item.TryBytes()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
|
@ -305,15 +318,15 @@ func (c *ContractReader) Maps(m map[string]string) (map[string]string, error) {
|
||||||
return "", errors.New("not a UTF-8 string")
|
return "", errors.New("not a UTF-8 string")
|
||||||
}
|
}
|
||||||
return string(b), nil
|
return string(b), nil
|
||||||
} (m[i].Value)
|
}(m[i].Value)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("value %d: %w", i, err)
|
return nil, fmt.Errorf("value %d: %w", i, err)
|
||||||
}
|
}
|
||||||
res[k] = v
|
res[k] = v
|
||||||
}
|
}
|
||||||
return res, nil
|
return res, nil
|
||||||
} (item)
|
}(item)
|
||||||
} (unwrap.Item(c.invoker.Call(c.hash, "maps", m)))
|
}(unwrap.Item(c.invoker.Call(c.hash, "maps", m)))
|
||||||
}
|
}
|
||||||
|
|
||||||
// PublicKey invokes `publicKey` method of contract.
|
// PublicKey invokes `publicKey` method of contract.
|
||||||
|
@ -345,3 +358,87 @@ func (c *ContractReader) String(s string) (string, error) {
|
||||||
func (c *ContractReader) Strings(s []string) ([]string, error) {
|
func (c *ContractReader) Strings(s []string) ([]string, error) {
|
||||||
return unwrap.ArrayOfUTF8Strings(c.invoker.Call(c.hash, "strings", s))
|
return unwrap.ArrayOfUTF8Strings(c.invoker.Call(c.hash, "strings", s))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UnnamedStructs invokes `unnamedStructs` method of contract.
|
||||||
|
func (c *ContractReader) UnnamedStructs() (*Unnamed, error) {
|
||||||
|
return itemToUnnamed(unwrap.Item(c.invoker.Call(c.hash, "unnamedStructs")))
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnnamedStructsX invokes `unnamedStructsX` method of contract.
|
||||||
|
func (c *ContractReader) UnnamedStructsX() (*UnnamedX, error) {
|
||||||
|
return itemToUnnamedX(unwrap.Item(c.invoker.Call(c.hash, "unnamedStructsX")))
|
||||||
|
}
|
||||||
|
|
||||||
|
// itemToUnnamed converts stack item into *Unnamed.
|
||||||
|
func itemToUnnamed(item stackitem.Item, err error) (*Unnamed, error) {
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var res = new(Unnamed)
|
||||||
|
err = res.FromStackItem(item)
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// FromStackItem retrieves fields of Unnamed from the given
|
||||||
|
// [stackitem.Item] or returns an error if it's not possible to do to so.
|
||||||
|
func (res *Unnamed) FromStackItem(item stackitem.Item) error {
|
||||||
|
arr, ok := item.Value().([]stackitem.Item)
|
||||||
|
if !ok {
|
||||||
|
return errors.New("not an array")
|
||||||
|
}
|
||||||
|
if len(arr) != 1 {
|
||||||
|
return errors.New("wrong number of structure elements")
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
index = -1
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
index++
|
||||||
|
res.I, err = arr[index].TryInteger()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("field I: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// itemToUnnamedX converts stack item into *UnnamedX.
|
||||||
|
func itemToUnnamedX(item stackitem.Item, err error) (*UnnamedX, error) {
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var res = new(UnnamedX)
|
||||||
|
err = res.FromStackItem(item)
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// FromStackItem retrieves fields of UnnamedX from the given
|
||||||
|
// [stackitem.Item] or returns an error if it's not possible to do to so.
|
||||||
|
func (res *UnnamedX) FromStackItem(item stackitem.Item) error {
|
||||||
|
arr, ok := item.Value().([]stackitem.Item)
|
||||||
|
if !ok {
|
||||||
|
return errors.New("not an array")
|
||||||
|
}
|
||||||
|
if len(arr) != 2 {
|
||||||
|
return errors.New("wrong number of structure elements")
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
index = -1
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
index++
|
||||||
|
res.I, err = arr[index].TryInteger()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("field I: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
index++
|
||||||
|
res.B, err = arr[index].TryBool()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("field B: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -1,3 +1,5 @@
|
||||||
|
// Code generated by neo-go contract generate-rpcwrapper --manifest <file.json> --out <file.go> [--hash <hash>] [--config <config>]; DO NOT EDIT.
|
||||||
|
|
||||||
// Package types contains RPC wrappers for Types contract.
|
// Package types contains RPC wrappers for Types contract.
|
||||||
package types
|
package types
|
||||||
|
|
||||||
|
@ -13,6 +15,17 @@ import (
|
||||||
"unicode/utf8"
|
"unicode/utf8"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Unnamed is a contract-specific unnamed type used by its methods.
|
||||||
|
type Unnamed struct {
|
||||||
|
I *big.Int
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnnamedX is a contract-specific unnamedX type used by its methods.
|
||||||
|
type UnnamedX struct {
|
||||||
|
I *big.Int
|
||||||
|
B bool
|
||||||
|
}
|
||||||
|
|
||||||
// Invoker is used by ContractReader to call various safe methods.
|
// Invoker is used by ContractReader to call various safe methods.
|
||||||
type Invoker interface {
|
type Invoker interface {
|
||||||
Call(contract util.Uint160, operation string, params ...any) (*result.Invoke, error)
|
Call(contract util.Uint160, operation string, params ...any) (*result.Invoke, error)
|
||||||
|
@ -31,32 +44,32 @@ func NewReader(invoker Invoker, hash util.Uint160) *ContractReader {
|
||||||
|
|
||||||
// AAAStrings invokes `aAAStrings` method of contract.
|
// AAAStrings invokes `aAAStrings` method of contract.
|
||||||
func (c *ContractReader) AAAStrings(s [][][]string) ([][][]string, error) {
|
func (c *ContractReader) AAAStrings(s [][][]string) ([][][]string, error) {
|
||||||
return func (item stackitem.Item, err error) ([][][]string, error) {
|
return func(item stackitem.Item, err error) ([][][]string, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return func (item stackitem.Item) ([][][]string, error) {
|
return func(item stackitem.Item) ([][][]string, error) {
|
||||||
arr, ok := item.Value().([]stackitem.Item)
|
arr, ok := item.Value().([]stackitem.Item)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, errors.New("not an array")
|
return nil, errors.New("not an array")
|
||||||
}
|
}
|
||||||
res := make([][][]string, len(arr))
|
res := make([][][]string, len(arr))
|
||||||
for i := range res {
|
for i := range res {
|
||||||
res[i], err = func (item stackitem.Item) ([][]string, error) {
|
res[i], err = func(item stackitem.Item) ([][]string, error) {
|
||||||
arr, ok := item.Value().([]stackitem.Item)
|
arr, ok := item.Value().([]stackitem.Item)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, errors.New("not an array")
|
return nil, errors.New("not an array")
|
||||||
}
|
}
|
||||||
res := make([][]string, len(arr))
|
res := make([][]string, len(arr))
|
||||||
for i := range res {
|
for i := range res {
|
||||||
res[i], err = func (item stackitem.Item) ([]string, error) {
|
res[i], err = func(item stackitem.Item) ([]string, error) {
|
||||||
arr, ok := item.Value().([]stackitem.Item)
|
arr, ok := item.Value().([]stackitem.Item)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, errors.New("not an array")
|
return nil, errors.New("not an array")
|
||||||
}
|
}
|
||||||
res := make([]string, len(arr))
|
res := make([]string, len(arr))
|
||||||
for i := range res {
|
for i := range res {
|
||||||
res[i], err = func (item stackitem.Item) (string, error) {
|
res[i], err = func(item stackitem.Item) (string, error) {
|
||||||
b, err := item.TryBytes()
|
b, err := item.TryBytes()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
|
@ -65,45 +78,45 @@ func (c *ContractReader) AAAStrings(s [][][]string) ([][][]string, error) {
|
||||||
return "", errors.New("not a UTF-8 string")
|
return "", errors.New("not a UTF-8 string")
|
||||||
}
|
}
|
||||||
return string(b), nil
|
return string(b), nil
|
||||||
} (arr[i])
|
}(arr[i])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("item %d: %w", i, err)
|
return nil, fmt.Errorf("item %d: %w", i, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return res, nil
|
return res, nil
|
||||||
} (arr[i])
|
}(arr[i])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("item %d: %w", i, err)
|
return nil, fmt.Errorf("item %d: %w", i, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return res, nil
|
return res, nil
|
||||||
} (arr[i])
|
}(arr[i])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("item %d: %w", i, err)
|
return nil, fmt.Errorf("item %d: %w", i, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return res, nil
|
return res, nil
|
||||||
} (item)
|
}(item)
|
||||||
} (unwrap.Item(c.invoker.Call(c.hash, "aAAStrings", s)))
|
}(unwrap.Item(c.invoker.Call(c.hash, "aAAStrings", s)))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Any invokes `any` method of contract.
|
// Any invokes `any` method of contract.
|
||||||
func (c *ContractReader) Any(a any) (any, error) {
|
func (c *ContractReader) Any(a any) (any, error) {
|
||||||
return func (item stackitem.Item, err error) (any, error) {
|
return func(item stackitem.Item, err error) (any, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return item.Value(), error(nil)
|
return item.Value(), error(nil)
|
||||||
} (unwrap.Item(c.invoker.Call(c.hash, "any", a)))
|
}(unwrap.Item(c.invoker.Call(c.hash, "any", a)))
|
||||||
}
|
}
|
||||||
|
|
||||||
// AnyMaps invokes `anyMaps` method of contract.
|
// AnyMaps invokes `anyMaps` method of contract.
|
||||||
func (c *ContractReader) AnyMaps(m map[*big.Int]any) (map[*big.Int]any, error) {
|
func (c *ContractReader) AnyMaps(m map[*big.Int]any) (map[*big.Int]any, error) {
|
||||||
return func (item stackitem.Item, err error) (map[*big.Int]any, error) {
|
return func(item stackitem.Item, err error) (map[*big.Int]any, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return func (item stackitem.Item) (map[*big.Int]any, error) {
|
return func(item stackitem.Item) (map[*big.Int]any, error) {
|
||||||
m, ok := item.Value().([]stackitem.MapElement)
|
m, ok := item.Value().([]stackitem.MapElement)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("%s is not a map", item.Type().String())
|
return nil, fmt.Errorf("%s is not a map", item.Type().String())
|
||||||
|
@ -121,8 +134,8 @@ func (c *ContractReader) AnyMaps(m map[*big.Int]any) (map[*big.Int]any, error) {
|
||||||
res[k] = v
|
res[k] = v
|
||||||
}
|
}
|
||||||
return res, nil
|
return res, nil
|
||||||
} (item)
|
}(item)
|
||||||
} (unwrap.Item(c.invoker.Call(c.hash, "anyMaps", m)))
|
}(unwrap.Item(c.invoker.Call(c.hash, "anyMaps", m)))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bool invokes `bool` method of contract.
|
// Bool invokes `bool` method of contract.
|
||||||
|
@ -147,11 +160,11 @@ func (c *ContractReader) Bytess(b [][]byte) ([][]byte, error) {
|
||||||
|
|
||||||
// CrazyMaps invokes `crazyMaps` method of contract.
|
// CrazyMaps invokes `crazyMaps` method of contract.
|
||||||
func (c *ContractReader) CrazyMaps(m map[*big.Int][]map[string][]util.Uint160) (map[*big.Int][]map[string][]util.Uint160, error) {
|
func (c *ContractReader) CrazyMaps(m map[*big.Int][]map[string][]util.Uint160) (map[*big.Int][]map[string][]util.Uint160, error) {
|
||||||
return func (item stackitem.Item, err error) (map[*big.Int][]map[string][]util.Uint160, error) {
|
return func(item stackitem.Item, err error) (map[*big.Int][]map[string][]util.Uint160, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return func (item stackitem.Item) (map[*big.Int][]map[string][]util.Uint160, error) {
|
return func(item stackitem.Item) (map[*big.Int][]map[string][]util.Uint160, error) {
|
||||||
m, ok := item.Value().([]stackitem.MapElement)
|
m, ok := item.Value().([]stackitem.MapElement)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("%s is not a map", item.Type().String())
|
return nil, fmt.Errorf("%s is not a map", item.Type().String())
|
||||||
|
@ -162,21 +175,21 @@ func (c *ContractReader) CrazyMaps(m map[*big.Int][]map[string][]util.Uint160) (
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("key %d: %w", i, err)
|
return nil, fmt.Errorf("key %d: %w", i, err)
|
||||||
}
|
}
|
||||||
v, err := func (item stackitem.Item) ([]map[string][]util.Uint160, error) {
|
v, err := func(item stackitem.Item) ([]map[string][]util.Uint160, error) {
|
||||||
arr, ok := item.Value().([]stackitem.Item)
|
arr, ok := item.Value().([]stackitem.Item)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, errors.New("not an array")
|
return nil, errors.New("not an array")
|
||||||
}
|
}
|
||||||
res := make([]map[string][]util.Uint160, len(arr))
|
res := make([]map[string][]util.Uint160, len(arr))
|
||||||
for i := range res {
|
for i := range res {
|
||||||
res[i], err = func (item stackitem.Item) (map[string][]util.Uint160, error) {
|
res[i], err = func(item stackitem.Item) (map[string][]util.Uint160, error) {
|
||||||
m, ok := item.Value().([]stackitem.MapElement)
|
m, ok := item.Value().([]stackitem.MapElement)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("%s is not a map", item.Type().String())
|
return nil, fmt.Errorf("%s is not a map", item.Type().String())
|
||||||
}
|
}
|
||||||
res := make(map[string][]util.Uint160)
|
res := make(map[string][]util.Uint160)
|
||||||
for i := range m {
|
for i := range m {
|
||||||
k, err := func (item stackitem.Item) (string, error) {
|
k, err := func(item stackitem.Item) (string, error) {
|
||||||
b, err := item.TryBytes()
|
b, err := item.TryBytes()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
|
@ -185,18 +198,18 @@ func (c *ContractReader) CrazyMaps(m map[*big.Int][]map[string][]util.Uint160) (
|
||||||
return "", errors.New("not a UTF-8 string")
|
return "", errors.New("not a UTF-8 string")
|
||||||
}
|
}
|
||||||
return string(b), nil
|
return string(b), nil
|
||||||
} (m[i].Key)
|
}(m[i].Key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("key %d: %w", i, err)
|
return nil, fmt.Errorf("key %d: %w", i, err)
|
||||||
}
|
}
|
||||||
v, err := func (item stackitem.Item) ([]util.Uint160, error) {
|
v, err := func(item stackitem.Item) ([]util.Uint160, error) {
|
||||||
arr, ok := item.Value().([]stackitem.Item)
|
arr, ok := item.Value().([]stackitem.Item)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, errors.New("not an array")
|
return nil, errors.New("not an array")
|
||||||
}
|
}
|
||||||
res := make([]util.Uint160, len(arr))
|
res := make([]util.Uint160, len(arr))
|
||||||
for i := range res {
|
for i := range res {
|
||||||
res[i], err = func (item stackitem.Item) (util.Uint160, error) {
|
res[i], err = func(item stackitem.Item) (util.Uint160, error) {
|
||||||
b, err := item.TryBytes()
|
b, err := item.TryBytes()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return util.Uint160{}, err
|
return util.Uint160{}, err
|
||||||
|
@ -206,34 +219,34 @@ func (c *ContractReader) CrazyMaps(m map[*big.Int][]map[string][]util.Uint160) (
|
||||||
return util.Uint160{}, err
|
return util.Uint160{}, err
|
||||||
}
|
}
|
||||||
return u, nil
|
return u, nil
|
||||||
} (arr[i])
|
}(arr[i])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("item %d: %w", i, err)
|
return nil, fmt.Errorf("item %d: %w", i, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return res, nil
|
return res, nil
|
||||||
} (m[i].Value)
|
}(m[i].Value)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("value %d: %w", i, err)
|
return nil, fmt.Errorf("value %d: %w", i, err)
|
||||||
}
|
}
|
||||||
res[k] = v
|
res[k] = v
|
||||||
}
|
}
|
||||||
return res, nil
|
return res, nil
|
||||||
} (arr[i])
|
}(arr[i])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("item %d: %w", i, err)
|
return nil, fmt.Errorf("item %d: %w", i, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return res, nil
|
return res, nil
|
||||||
} (m[i].Value)
|
}(m[i].Value)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("value %d: %w", i, err)
|
return nil, fmt.Errorf("value %d: %w", i, err)
|
||||||
}
|
}
|
||||||
res[k] = v
|
res[k] = v
|
||||||
}
|
}
|
||||||
return res, nil
|
return res, nil
|
||||||
} (item)
|
}(item)
|
||||||
} (unwrap.Item(c.invoker.Call(c.hash, "crazyMaps", m)))
|
}(unwrap.Item(c.invoker.Call(c.hash, "crazyMaps", m)))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hash160 invokes `hash160` method of contract.
|
// Hash160 invokes `hash160` method of contract.
|
||||||
|
@ -268,18 +281,18 @@ func (c *ContractReader) Ints(i []*big.Int) ([]*big.Int, error) {
|
||||||
|
|
||||||
// Maps invokes `maps` method of contract.
|
// Maps invokes `maps` method of contract.
|
||||||
func (c *ContractReader) Maps(m map[string]string) (map[string]string, error) {
|
func (c *ContractReader) Maps(m map[string]string) (map[string]string, error) {
|
||||||
return func (item stackitem.Item, err error) (map[string]string, error) {
|
return func(item stackitem.Item, err error) (map[string]string, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return func (item stackitem.Item) (map[string]string, error) {
|
return func(item stackitem.Item) (map[string]string, error) {
|
||||||
m, ok := item.Value().([]stackitem.MapElement)
|
m, ok := item.Value().([]stackitem.MapElement)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("%s is not a map", item.Type().String())
|
return nil, fmt.Errorf("%s is not a map", item.Type().String())
|
||||||
}
|
}
|
||||||
res := make(map[string]string)
|
res := make(map[string]string)
|
||||||
for i := range m {
|
for i := range m {
|
||||||
k, err := func (item stackitem.Item) (string, error) {
|
k, err := func(item stackitem.Item) (string, error) {
|
||||||
b, err := item.TryBytes()
|
b, err := item.TryBytes()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
|
@ -288,11 +301,11 @@ func (c *ContractReader) Maps(m map[string]string) (map[string]string, error) {
|
||||||
return "", errors.New("not a UTF-8 string")
|
return "", errors.New("not a UTF-8 string")
|
||||||
}
|
}
|
||||||
return string(b), nil
|
return string(b), nil
|
||||||
} (m[i].Key)
|
}(m[i].Key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("key %d: %w", i, err)
|
return nil, fmt.Errorf("key %d: %w", i, err)
|
||||||
}
|
}
|
||||||
v, err := func (item stackitem.Item) (string, error) {
|
v, err := func(item stackitem.Item) (string, error) {
|
||||||
b, err := item.TryBytes()
|
b, err := item.TryBytes()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
|
@ -301,15 +314,15 @@ func (c *ContractReader) Maps(m map[string]string) (map[string]string, error) {
|
||||||
return "", errors.New("not a UTF-8 string")
|
return "", errors.New("not a UTF-8 string")
|
||||||
}
|
}
|
||||||
return string(b), nil
|
return string(b), nil
|
||||||
} (m[i].Value)
|
}(m[i].Value)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("value %d: %w", i, err)
|
return nil, fmt.Errorf("value %d: %w", i, err)
|
||||||
}
|
}
|
||||||
res[k] = v
|
res[k] = v
|
||||||
}
|
}
|
||||||
return res, nil
|
return res, nil
|
||||||
} (item)
|
}(item)
|
||||||
} (unwrap.Item(c.invoker.Call(c.hash, "maps", m)))
|
}(unwrap.Item(c.invoker.Call(c.hash, "maps", m)))
|
||||||
}
|
}
|
||||||
|
|
||||||
// PublicKey invokes `publicKey` method of contract.
|
// PublicKey invokes `publicKey` method of contract.
|
||||||
|
@ -341,3 +354,87 @@ func (c *ContractReader) String(s string) (string, error) {
|
||||||
func (c *ContractReader) Strings(s []string) ([]string, error) {
|
func (c *ContractReader) Strings(s []string) ([]string, error) {
|
||||||
return unwrap.ArrayOfUTF8Strings(c.invoker.Call(c.hash, "strings", s))
|
return unwrap.ArrayOfUTF8Strings(c.invoker.Call(c.hash, "strings", s))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UnnamedStructs invokes `unnamedStructs` method of contract.
|
||||||
|
func (c *ContractReader) UnnamedStructs() (*Unnamed, error) {
|
||||||
|
return itemToUnnamed(unwrap.Item(c.invoker.Call(c.hash, "unnamedStructs")))
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnnamedStructsX invokes `unnamedStructsX` method of contract.
|
||||||
|
func (c *ContractReader) UnnamedStructsX() (*UnnamedX, error) {
|
||||||
|
return itemToUnnamedX(unwrap.Item(c.invoker.Call(c.hash, "unnamedStructsX")))
|
||||||
|
}
|
||||||
|
|
||||||
|
// itemToUnnamed converts stack item into *Unnamed.
|
||||||
|
func itemToUnnamed(item stackitem.Item, err error) (*Unnamed, error) {
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var res = new(Unnamed)
|
||||||
|
err = res.FromStackItem(item)
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// FromStackItem retrieves fields of Unnamed from the given
|
||||||
|
// [stackitem.Item] or returns an error if it's not possible to do to so.
|
||||||
|
func (res *Unnamed) FromStackItem(item stackitem.Item) error {
|
||||||
|
arr, ok := item.Value().([]stackitem.Item)
|
||||||
|
if !ok {
|
||||||
|
return errors.New("not an array")
|
||||||
|
}
|
||||||
|
if len(arr) != 1 {
|
||||||
|
return errors.New("wrong number of structure elements")
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
index = -1
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
index++
|
||||||
|
res.I, err = arr[index].TryInteger()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("field I: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// itemToUnnamedX converts stack item into *UnnamedX.
|
||||||
|
func itemToUnnamedX(item stackitem.Item, err error) (*UnnamedX, error) {
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var res = new(UnnamedX)
|
||||||
|
err = res.FromStackItem(item)
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// FromStackItem retrieves fields of UnnamedX from the given
|
||||||
|
// [stackitem.Item] or returns an error if it's not possible to do to so.
|
||||||
|
func (res *UnnamedX) FromStackItem(item stackitem.Item) error {
|
||||||
|
arr, ok := item.Value().([]stackitem.Item)
|
||||||
|
if !ok {
|
||||||
|
return errors.New("not an array")
|
||||||
|
}
|
||||||
|
if len(arr) != 2 {
|
||||||
|
return errors.New("wrong number of structure elements")
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
index = -1
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
index++
|
||||||
|
res.I, err = arr[index].TryInteger()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("field I: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
index++
|
||||||
|
res.B, err = arr[index].TryBool()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("field B: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -87,3 +87,17 @@ func CrazyMaps(m map[int][]map[string][]interop.Hash160) map[int][]map[string][]
|
||||||
func AnyMaps(m map[int]any) map[int]any {
|
func AnyMaps(m map[int]any) map[int]any {
|
||||||
return m
|
return m
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func UnnamedStructs() struct{ I int } {
|
||||||
|
return struct{ I int }{I: 123}
|
||||||
|
}
|
||||||
|
|
||||||
|
func UnnamedStructsX() struct {
|
||||||
|
I int
|
||||||
|
B bool
|
||||||
|
} {
|
||||||
|
return struct {
|
||||||
|
I int
|
||||||
|
B bool
|
||||||
|
}{I: 123, B: true}
|
||||||
|
}
|
39
cli/smartcontract/testdata/structs/structs.go
vendored
39
cli/smartcontract/testdata/structs/structs.go
vendored
|
@ -1,39 +0,0 @@
|
||||||
package structs
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/interop"
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/interop/native/ledger"
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/interop/native/management"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Internal struct {
|
|
||||||
Bool bool
|
|
||||||
Int int
|
|
||||||
Bytes []byte
|
|
||||||
String string
|
|
||||||
H160 interop.Hash160
|
|
||||||
H256 interop.Hash256
|
|
||||||
PK interop.PublicKey
|
|
||||||
PubKey interop.PublicKey
|
|
||||||
Sign interop.Signature
|
|
||||||
ArrOfBytes [][]byte
|
|
||||||
ArrOfH160 []interop.Hash160
|
|
||||||
Map map[int][]interop.PublicKey
|
|
||||||
Struct *Internal
|
|
||||||
}
|
|
||||||
|
|
||||||
func Contract(mc management.Contract) management.Contract {
|
|
||||||
return mc
|
|
||||||
}
|
|
||||||
|
|
||||||
func Block(b *ledger.Block) *ledger.Block {
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
|
|
||||||
func Transaction(t *ledger.Transaction) *ledger.Transaction {
|
|
||||||
return t
|
|
||||||
}
|
|
||||||
|
|
||||||
func Struct(s *Internal) *Internal {
|
|
||||||
return s
|
|
||||||
}
|
|
297
cli/smartcontract/testdata/verify.bindings.yml
vendored
Executable file
297
cli/smartcontract/testdata/verify.bindings.yml
vendored
Executable file
|
@ -0,0 +1,297 @@
|
||||||
|
package: testdata
|
||||||
|
hash: "0x0000000000000000000000000000000000000000"
|
||||||
|
overrides:
|
||||||
|
burnGas.gas: int
|
||||||
|
call: any
|
||||||
|
call.args: '[]any'
|
||||||
|
call.f: any
|
||||||
|
call.method: string
|
||||||
|
call.scriptHash: github.com/nspcc-dev/neo-go/pkg/interop.Hash160
|
||||||
|
callWithToken: any
|
||||||
|
callWithToken.args: '[]any'
|
||||||
|
callWithToken.flags: int
|
||||||
|
callWithToken.method: string
|
||||||
|
callWithToken.scriptHash: string
|
||||||
|
callWithTokenNoRet.args: '[]any'
|
||||||
|
callWithTokenNoRet.flags: int
|
||||||
|
callWithTokenNoRet.method: string
|
||||||
|
callWithTokenNoRet.scriptHash: string
|
||||||
|
checkWitness: bool
|
||||||
|
checkWitness.hashOrKey: '[]byte'
|
||||||
|
createMultisigAccount: '[]byte'
|
||||||
|
createMultisigAccount.m: int
|
||||||
|
createMultisigAccount.pubs: '[]github.com/nspcc-dev/neo-go/pkg/interop.PublicKey'
|
||||||
|
createStandardAccount: '[]byte'
|
||||||
|
createStandardAccount.pub: github.com/nspcc-dev/neo-go/pkg/interop.PublicKey
|
||||||
|
currentHash: github.com/nspcc-dev/neo-go/pkg/interop.Hash256
|
||||||
|
currentIndex: int
|
||||||
|
currentSigners: '[]github.com/nspcc-dev/neo-go/pkg/interop/native/ledger.TransactionSigner'
|
||||||
|
equals: bool
|
||||||
|
equals.b: any
|
||||||
|
gasLeft: int
|
||||||
|
getAddressVersion: int
|
||||||
|
getBlock: '*github.com/nspcc-dev/neo-go/pkg/interop/native/ledger.Block'
|
||||||
|
getBlock.indexOrHash: any
|
||||||
|
getCallFlags: any
|
||||||
|
getCallingScriptHash: github.com/nspcc-dev/neo-go/pkg/interop.Hash160
|
||||||
|
getEntryScriptHash: github.com/nspcc-dev/neo-go/pkg/interop.Hash160
|
||||||
|
getExecutingScriptHash: github.com/nspcc-dev/neo-go/pkg/interop.Hash160
|
||||||
|
getInvocationCounter: int
|
||||||
|
getNetwork: int
|
||||||
|
getNotifications: '[][]any'
|
||||||
|
getNotifications.h: github.com/nspcc-dev/neo-go/pkg/interop.Hash160
|
||||||
|
getRandom: int
|
||||||
|
getScriptContainer: '*github.com/nspcc-dev/neo-go/pkg/interop/native/ledger.Transaction'
|
||||||
|
getTime: int
|
||||||
|
getTransaction: '*github.com/nspcc-dev/neo-go/pkg/interop/native/ledger.Transaction'
|
||||||
|
getTransaction.hash: github.com/nspcc-dev/neo-go/pkg/interop.Hash256
|
||||||
|
getTransactionFromBlock: '*github.com/nspcc-dev/neo-go/pkg/interop/native/ledger.Transaction'
|
||||||
|
getTransactionFromBlock.indexOrHash: any
|
||||||
|
getTransactionFromBlock.txIndex: int
|
||||||
|
getTransactionHeight: int
|
||||||
|
getTransactionHeight.hash: github.com/nspcc-dev/neo-go/pkg/interop.Hash256
|
||||||
|
getTransactionSigners: '[]github.com/nspcc-dev/neo-go/pkg/interop/native/ledger.TransactionSigner'
|
||||||
|
getTransactionSigners.hash: github.com/nspcc-dev/neo-go/pkg/interop.Hash256
|
||||||
|
getTransactionVMState: int
|
||||||
|
getTransactionVMState.hash: github.com/nspcc-dev/neo-go/pkg/interop.Hash256
|
||||||
|
getTrigger: int
|
||||||
|
loadScript: any
|
||||||
|
loadScript.args: '[]any'
|
||||||
|
loadScript.f: any
|
||||||
|
loadScript.script: '[]byte'
|
||||||
|
log.message: string
|
||||||
|
notify.args: '[]any'
|
||||||
|
notify.name: string
|
||||||
|
onNEP11Payment.amount: int
|
||||||
|
onNEP11Payment.data: any
|
||||||
|
onNEP11Payment.from: github.com/nspcc-dev/neo-go/pkg/interop.Hash160
|
||||||
|
onNEP11Payment.token: '[]byte'
|
||||||
|
onNEP17Payment.amount: int
|
||||||
|
onNEP17Payment.data: any
|
||||||
|
onNEP17Payment.from: github.com/nspcc-dev/neo-go/pkg/interop.Hash160
|
||||||
|
opcode0NoReturn.op: string
|
||||||
|
opcode1: any
|
||||||
|
opcode1NoReturn.arg: any
|
||||||
|
opcode1NoReturn.op: string
|
||||||
|
opcode1.arg: any
|
||||||
|
opcode1.op: string
|
||||||
|
opcode2: any
|
||||||
|
opcode2NoReturn.arg1: any
|
||||||
|
opcode2NoReturn.arg2: any
|
||||||
|
opcode2NoReturn.op: string
|
||||||
|
opcode2.arg1: any
|
||||||
|
opcode2.arg2: any
|
||||||
|
opcode2.op: string
|
||||||
|
opcode3: any
|
||||||
|
opcode3.arg1: any
|
||||||
|
opcode3.arg2: any
|
||||||
|
opcode3.arg3: any
|
||||||
|
opcode3.op: string
|
||||||
|
platform: '[]byte'
|
||||||
|
syscall0: any
|
||||||
|
syscall0NoReturn.name: string
|
||||||
|
syscall0.name: string
|
||||||
|
syscall1: any
|
||||||
|
syscall1NoReturn.arg: any
|
||||||
|
syscall1NoReturn.name: string
|
||||||
|
syscall1.arg: any
|
||||||
|
syscall1.name: string
|
||||||
|
syscall2: any
|
||||||
|
syscall2NoReturn.arg1: any
|
||||||
|
syscall2NoReturn.arg2: any
|
||||||
|
syscall2NoReturn.name: string
|
||||||
|
syscall2.arg1: any
|
||||||
|
syscall2.arg2: any
|
||||||
|
syscall2.name: string
|
||||||
|
syscall3: any
|
||||||
|
syscall3NoReturn.arg1: any
|
||||||
|
syscall3NoReturn.arg2: any
|
||||||
|
syscall3NoReturn.arg3: any
|
||||||
|
syscall3NoReturn.name: string
|
||||||
|
syscall3.arg1: any
|
||||||
|
syscall3.arg2: any
|
||||||
|
syscall3.arg3: any
|
||||||
|
syscall3.name: string
|
||||||
|
syscall4: any
|
||||||
|
syscall4NoReturn.arg1: any
|
||||||
|
syscall4NoReturn.arg2: any
|
||||||
|
syscall4NoReturn.arg3: any
|
||||||
|
syscall4NoReturn.arg4: any
|
||||||
|
syscall4NoReturn.name: string
|
||||||
|
syscall4.arg1: any
|
||||||
|
syscall4.arg2: any
|
||||||
|
syscall4.arg3: any
|
||||||
|
syscall4.arg4: any
|
||||||
|
syscall4.name: string
|
||||||
|
toBlockSR: '*github.com/nspcc-dev/neo-go/pkg/interop/native/ledger.BlockSR'
|
||||||
|
verify: bool
|
||||||
|
namedtypes:
|
||||||
|
ledger.Block:
|
||||||
|
base: Array
|
||||||
|
name: ledger.Block
|
||||||
|
fields:
|
||||||
|
- field: Hash
|
||||||
|
base: Hash256
|
||||||
|
- field: Version
|
||||||
|
base: Integer
|
||||||
|
- field: PrevHash
|
||||||
|
base: Hash256
|
||||||
|
- field: MerkleRoot
|
||||||
|
base: Hash256
|
||||||
|
- field: Timestamp
|
||||||
|
base: Integer
|
||||||
|
- field: Nonce
|
||||||
|
base: Integer
|
||||||
|
- field: Index
|
||||||
|
base: Integer
|
||||||
|
- field: NextConsensus
|
||||||
|
base: Hash160
|
||||||
|
- field: TransactionsLength
|
||||||
|
base: Integer
|
||||||
|
ledger.BlockSR:
|
||||||
|
base: Array
|
||||||
|
name: ledger.BlockSR
|
||||||
|
fields:
|
||||||
|
- field: Hash
|
||||||
|
base: Hash256
|
||||||
|
- field: Version
|
||||||
|
base: Integer
|
||||||
|
- field: PrevHash
|
||||||
|
base: Hash256
|
||||||
|
- field: MerkleRoot
|
||||||
|
base: Hash256
|
||||||
|
- field: Timestamp
|
||||||
|
base: Integer
|
||||||
|
- field: Nonce
|
||||||
|
base: Integer
|
||||||
|
- field: Index
|
||||||
|
base: Integer
|
||||||
|
- field: NextConsensus
|
||||||
|
base: Hash160
|
||||||
|
- field: TransactionsLength
|
||||||
|
base: Integer
|
||||||
|
- field: PrevStateRoot
|
||||||
|
base: Hash256
|
||||||
|
ledger.Transaction:
|
||||||
|
base: Array
|
||||||
|
name: ledger.Transaction
|
||||||
|
fields:
|
||||||
|
- field: Hash
|
||||||
|
base: Hash256
|
||||||
|
- field: Version
|
||||||
|
base: Integer
|
||||||
|
- field: Nonce
|
||||||
|
base: Integer
|
||||||
|
- field: Sender
|
||||||
|
base: Hash160
|
||||||
|
- field: SysFee
|
||||||
|
base: Integer
|
||||||
|
- field: NetFee
|
||||||
|
base: Integer
|
||||||
|
- field: ValidUntilBlock
|
||||||
|
base: Integer
|
||||||
|
- field: Script
|
||||||
|
base: ByteArray
|
||||||
|
ledger.TransactionSigner:
|
||||||
|
base: Array
|
||||||
|
name: ledger.TransactionSigner
|
||||||
|
fields:
|
||||||
|
- field: Account
|
||||||
|
base: Hash160
|
||||||
|
- field: Scopes
|
||||||
|
base: Integer
|
||||||
|
- field: AllowedContracts
|
||||||
|
base: Array
|
||||||
|
value:
|
||||||
|
base: Hash160
|
||||||
|
- field: AllowedGroups
|
||||||
|
base: Array
|
||||||
|
value:
|
||||||
|
base: PublicKey
|
||||||
|
- field: Rules
|
||||||
|
base: Array
|
||||||
|
value:
|
||||||
|
base: Array
|
||||||
|
name: ledger.WitnessRule
|
||||||
|
ledger.WitnessCondition:
|
||||||
|
base: Array
|
||||||
|
name: ledger.WitnessCondition
|
||||||
|
fields:
|
||||||
|
- field: Type
|
||||||
|
base: Integer
|
||||||
|
- field: Value
|
||||||
|
base: Any
|
||||||
|
ledger.WitnessRule:
|
||||||
|
base: Array
|
||||||
|
name: ledger.WitnessRule
|
||||||
|
fields:
|
||||||
|
- field: Action
|
||||||
|
base: Integer
|
||||||
|
- field: Condition
|
||||||
|
base: Array
|
||||||
|
name: ledger.WitnessCondition
|
||||||
|
types:
|
||||||
|
call.args:
|
||||||
|
base: Array
|
||||||
|
value:
|
||||||
|
base: Any
|
||||||
|
call.f:
|
||||||
|
base: InteropInterface
|
||||||
|
interface: iterator
|
||||||
|
callWithToken.args:
|
||||||
|
base: Array
|
||||||
|
value:
|
||||||
|
base: Any
|
||||||
|
callWithTokenNoRet.args:
|
||||||
|
base: Array
|
||||||
|
value:
|
||||||
|
base: Any
|
||||||
|
createMultisigAccount.pubs:
|
||||||
|
base: Array
|
||||||
|
value:
|
||||||
|
base: PublicKey
|
||||||
|
currentSigners:
|
||||||
|
base: Array
|
||||||
|
value:
|
||||||
|
base: Array
|
||||||
|
name: ledger.TransactionSigner
|
||||||
|
getBlock:
|
||||||
|
base: Array
|
||||||
|
name: ledger.Block
|
||||||
|
getCallFlags:
|
||||||
|
base: InteropInterface
|
||||||
|
interface: iterator
|
||||||
|
getNotifications:
|
||||||
|
base: Array
|
||||||
|
value:
|
||||||
|
base: Array
|
||||||
|
value:
|
||||||
|
base: Any
|
||||||
|
getScriptContainer:
|
||||||
|
base: Array
|
||||||
|
name: ledger.Transaction
|
||||||
|
getTransaction:
|
||||||
|
base: Array
|
||||||
|
name: ledger.Transaction
|
||||||
|
getTransactionFromBlock:
|
||||||
|
base: Array
|
||||||
|
name: ledger.Transaction
|
||||||
|
getTransactionSigners:
|
||||||
|
base: Array
|
||||||
|
value:
|
||||||
|
base: Array
|
||||||
|
name: ledger.TransactionSigner
|
||||||
|
loadScript.args:
|
||||||
|
base: Array
|
||||||
|
value:
|
||||||
|
base: Any
|
||||||
|
loadScript.f:
|
||||||
|
base: InteropInterface
|
||||||
|
interface: iterator
|
||||||
|
notify.args:
|
||||||
|
base: Array
|
||||||
|
value:
|
||||||
|
base: Any
|
||||||
|
toBlockSR:
|
||||||
|
base: Array
|
||||||
|
name: ledger.BlockSR
|
|
@ -1,3 +1,5 @@
|
||||||
|
// Code generated by neo-go contract generate-rpcwrapper --manifest <file.json> --out <file.go> [--hash <hash>] [--config <config>]; DO NOT EDIT.
|
||||||
|
|
||||||
// Package verify contains RPC wrappers for verify contract.
|
// Package verify contains RPC wrappers for verify contract.
|
||||||
package verify
|
package verify
|
||||||
|
|
||||||
|
@ -123,7 +125,7 @@ func (e *HelloWorldEvent) FromStackItem(item *stackitem.Array) error {
|
||||||
err error
|
err error
|
||||||
)
|
)
|
||||||
index++
|
index++
|
||||||
e.Args, err = func (item stackitem.Item) ([]any, error) {
|
e.Args, err = func(item stackitem.Item) ([]any, error) {
|
||||||
arr, ok := item.Value().([]stackitem.Item)
|
arr, ok := item.Value().([]stackitem.Item)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, errors.New("not an array")
|
return nil, errors.New("not an array")
|
||||||
|
@ -136,7 +138,7 @@ func (e *HelloWorldEvent) FromStackItem(item *stackitem.Array) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return res, nil
|
return res, nil
|
||||||
} (arr[index])
|
}(arr[index])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("field Args: %w", err)
|
return fmt.Errorf("field Args: %w", err)
|
||||||
}
|
}
|
||||||
|
|
64
cli/testdata/testwallet_multi.json
vendored
Normal file
64
cli/testdata/testwallet_multi.json
vendored
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
{
|
||||||
|
"version": "1.0",
|
||||||
|
"accounts": [
|
||||||
|
{
|
||||||
|
"address": "NgHcPxgEKZQV4QBedzyASJrgiANhJqBVLw",
|
||||||
|
"key": "6PYTbVq2P3AJQwWU5SFMKLjHYco7QABtNRo4ZvLvXhyaYjwMcuZm6xKokT",
|
||||||
|
"label": "one",
|
||||||
|
"contract": {
|
||||||
|
"script": "DCECnmSGVirDOqMr57EHaYz0YMTjaHQtO9FQYu8DMTCDw6VBVuezJw==",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "parameter0",
|
||||||
|
"type": "Signature"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"deployed": false
|
||||||
|
},
|
||||||
|
"lock": false,
|
||||||
|
"isDefault": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "NLvHRfKAifjio2z9HiwLo9ZnpRPHUbAHgH",
|
||||||
|
"key": "6PYUjQ8TgR3cduEpG5niUNuPEWi3tYiQsnC4Jha9nGAJ6tAQGUmcrZXsLF",
|
||||||
|
"label": "two",
|
||||||
|
"contract": {
|
||||||
|
"script": "DCECgk91c1ABAX3A1uJNnxhGlp7NwUJScwJzJhrsYrXIbgNBVuezJw==",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "parameter0",
|
||||||
|
"type": "Signature"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"deployed": false
|
||||||
|
},
|
||||||
|
"lock": false,
|
||||||
|
"isDefault": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "NcDfG8foJx79XSihcDDrx1df7cHAoJBfXj",
|
||||||
|
"key": "6PYRkUQKWFrTovHyeQZ7X4nWoDXKohtFRKW51LiCz317pwCjmB1cVwpcxz",
|
||||||
|
"label": "three",
|
||||||
|
"contract": {
|
||||||
|
"script": "DCEC9v0ZqBg8f4jJX9WR891M0bazf0FYTNu7MEgpSHrb9CVBVuezJw==",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "parameter0",
|
||||||
|
"type": "Signature"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"deployed": false
|
||||||
|
},
|
||||||
|
"lock": false,
|
||||||
|
"isDefault": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"scrypt": {
|
||||||
|
"n": 2,
|
||||||
|
"r": 1,
|
||||||
|
"p": 1
|
||||||
|
},
|
||||||
|
"extra": {
|
||||||
|
"Tokens": null
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,13 +5,16 @@ package txctx
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/cli/flags"
|
"github.com/nspcc-dev/neo-go/cli/flags"
|
||||||
"github.com/nspcc-dev/neo-go/cli/input"
|
"github.com/nspcc-dev/neo-go/cli/input"
|
||||||
"github.com/nspcc-dev/neo-go/cli/paramcontext"
|
"github.com/nspcc-dev/neo-go/cli/paramcontext"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/core/state"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/rpcclient/actor"
|
"github.com/nspcc-dev/neo-go/pkg/rpcclient/actor"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
||||||
"github.com/urfave/cli"
|
"github.com/urfave/cli"
|
||||||
)
|
)
|
||||||
|
@ -37,6 +40,11 @@ var (
|
||||||
Name: "force",
|
Name: "force",
|
||||||
Usage: "Do not ask for a confirmation (and ignore errors)",
|
Usage: "Do not ask for a confirmation (and ignore errors)",
|
||||||
}
|
}
|
||||||
|
// AwaitFlag is a flag used to wait for the transaction to be included in a block.
|
||||||
|
AwaitFlag = cli.BoolFlag{
|
||||||
|
Name: "await",
|
||||||
|
Usage: "wait for the transaction to be included in a block",
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
// SignAndSend adds network and system fees to the provided transaction and
|
// SignAndSend adds network and system fees to the provided transaction and
|
||||||
|
@ -48,6 +56,7 @@ func SignAndSend(ctx *cli.Context, act *actor.Actor, acc *wallet.Account, tx *tr
|
||||||
gas = flags.Fixed8FromContext(ctx, "gas")
|
gas = flags.Fixed8FromContext(ctx, "gas")
|
||||||
sysgas = flags.Fixed8FromContext(ctx, "sysgas")
|
sysgas = flags.Fixed8FromContext(ctx, "sysgas")
|
||||||
ver = act.GetVersion()
|
ver = act.GetVersion()
|
||||||
|
aer *state.AppExecResult
|
||||||
)
|
)
|
||||||
|
|
||||||
tx.SystemFee += int64(sysgas)
|
tx.SystemFee += int64(sysgas)
|
||||||
|
@ -66,14 +75,39 @@ func SignAndSend(ctx *cli.Context, act *actor.Actor, acc *wallet.Account, tx *tr
|
||||||
}
|
}
|
||||||
waitTime := time.Since(promptTime)
|
waitTime := time.Since(promptTime)
|
||||||
// Compensate for confirmation waiting.
|
// Compensate for confirmation waiting.
|
||||||
tx.ValidUntilBlock += uint32((waitTime.Milliseconds() / int64(ver.Protocol.MillisecondsPerBlock))) + 1
|
tx.ValidUntilBlock += uint32(waitTime.Milliseconds()/int64(ver.Protocol.MillisecondsPerBlock)) + 2
|
||||||
|
}
|
||||||
|
var (
|
||||||
|
resTx util.Uint256
|
||||||
|
vub uint32
|
||||||
|
)
|
||||||
|
resTx, vub, err = act.SignAndSend(tx)
|
||||||
|
if err != nil {
|
||||||
|
return cli.NewExitError(err, 1)
|
||||||
|
}
|
||||||
|
if ctx.Bool("await") {
|
||||||
|
aer, err = act.Wait(resTx, vub, err)
|
||||||
|
if err != nil {
|
||||||
|
return cli.NewExitError(fmt.Errorf("failed to await transaction %s: %w", resTx.StringLE(), err), 1)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_, _, err = act.SignAndSend(tx)
|
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.NewExitError(err, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Fprintln(ctx.App.Writer, tx.Hash().StringLE())
|
DumpTransactionInfo(ctx.App.Writer, tx.Hash(), aer)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DumpTransactionInfo prints transaction info to the given writer.
|
||||||
|
func DumpTransactionInfo(w io.Writer, h util.Uint256, res *state.AppExecResult) {
|
||||||
|
fmt.Fprintln(w, h.StringLE())
|
||||||
|
if res != nil {
|
||||||
|
fmt.Fprintf(w, "OnChain:\t%t\n", res != nil)
|
||||||
|
fmt.Fprintf(w, "VMState:\t%s\n", res.VMState.String())
|
||||||
|
if res.FaultException != "" {
|
||||||
|
fmt.Fprintf(w, "FaultException:\t%s\n", res.FaultException)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
103
cli/util/cancel.go
Normal file
103
cli/util/cancel.go
Normal file
|
@ -0,0 +1,103 @@
|
||||||
|
package util
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/nspcc-dev/neo-go/cli/cmdargs"
|
||||||
|
"github.com/nspcc-dev/neo-go/cli/flags"
|
||||||
|
"github.com/nspcc-dev/neo-go/cli/options"
|
||||||
|
"github.com/nspcc-dev/neo-go/cli/txctx"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/core/state"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/neorpc/result"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/rpcclient/actor"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/rpcclient/waiter"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
|
||||||
|
"github.com/urfave/cli"
|
||||||
|
)
|
||||||
|
|
||||||
|
func cancelTx(ctx *cli.Context) error {
|
||||||
|
args := ctx.Args()
|
||||||
|
if len(args) == 0 {
|
||||||
|
return cli.NewExitError("transaction hash is missing", 1)
|
||||||
|
} else if len(args) > 1 {
|
||||||
|
return cli.NewExitError("only one transaction hash is accepted", 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
txHash, err := util.Uint256DecodeStringLE(strings.TrimPrefix(args[0], "0x"))
|
||||||
|
if err != nil {
|
||||||
|
return cli.NewExitError(fmt.Sprintf("invalid tx hash: %s", args[0]), 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
gctx, cancel := options.GetTimeoutContext(ctx)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
acc, w, err := options.GetAccFromContext(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return cli.NewExitError(fmt.Errorf("failed to get account from context to sign the conflicting transaction: %w", err), 1)
|
||||||
|
}
|
||||||
|
defer w.Close()
|
||||||
|
|
||||||
|
signers, err := cmdargs.GetSignersAccounts(acc, w, nil, transaction.CalledByEntry)
|
||||||
|
if err != nil {
|
||||||
|
return cli.NewExitError(fmt.Errorf("invalid signers: %w", err), 1)
|
||||||
|
}
|
||||||
|
c, a, exitErr := options.GetRPCWithActor(gctx, ctx, signers)
|
||||||
|
if exitErr != nil {
|
||||||
|
return exitErr
|
||||||
|
}
|
||||||
|
|
||||||
|
mainTx, _ := c.GetRawTransactionVerbose(txHash)
|
||||||
|
if mainTx != nil && !mainTx.Blockhash.Equals(util.Uint256{}) {
|
||||||
|
return cli.NewExitError(fmt.Errorf("target transaction %s is accepted at block %s", txHash, mainTx.Blockhash.StringLE()), 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if mainTx != nil && !mainTx.HasSigner(acc.ScriptHash()) {
|
||||||
|
return cli.NewExitError(fmt.Errorf("account %s is not a signer of the conflicting transaction", acc.Address), 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
resHash, resVub, err := a.SendTunedRun([]byte{byte(opcode.RET)}, []transaction.Attribute{{Type: transaction.ConflictsT, Value: &transaction.Conflicts{Hash: txHash}}}, func(r *result.Invoke, t *transaction.Transaction) error {
|
||||||
|
err := actor.DefaultCheckerModifier(r, t)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if mainTx != nil && t.NetworkFee < mainTx.NetworkFee+1 {
|
||||||
|
t.NetworkFee = mainTx.NetworkFee + 1
|
||||||
|
}
|
||||||
|
t.NetworkFee += int64(flags.Fixed8FromContext(ctx, "gas"))
|
||||||
|
if mainTx != nil {
|
||||||
|
t.ValidUntilBlock = mainTx.ValidUntilBlock
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return cli.NewExitError(fmt.Errorf("failed to send conflicting transaction: %w", err), 1)
|
||||||
|
}
|
||||||
|
var res *state.AppExecResult
|
||||||
|
if ctx.Bool("await") {
|
||||||
|
res, err = a.WaitAny(gctx, resVub, txHash, resHash)
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, waiter.ErrTxNotAccepted) {
|
||||||
|
if mainTx == nil {
|
||||||
|
return cli.NewExitError(fmt.Errorf("neither target nor conflicting transaction is accepted before the current height %d (ValidUntilBlock value of conlicting transaction). Main transaction is unknown to the provided RPC node, thus still has chances to be accepted, you may try cancellation again", resVub), 1)
|
||||||
|
}
|
||||||
|
fmt.Fprintf(ctx.App.Writer, "Neither target nor conflicting transaction is accepted before the current height %d (ValidUntilBlock value of both target and conflicting transactions). Main transaction is not valid anymore, cancellation is successful\n", resVub)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return cli.NewExitError(fmt.Errorf("failed to await target/ conflicting transaction %s/ %s: %w", txHash.StringLE(), resHash.StringLE(), err), 1)
|
||||||
|
}
|
||||||
|
if txHash.Equals(res.Container) {
|
||||||
|
tx, err := c.GetRawTransactionVerbose(txHash)
|
||||||
|
if err != nil {
|
||||||
|
return cli.NewExitError(fmt.Errorf("target transaction %s is accepted", txHash), 1)
|
||||||
|
}
|
||||||
|
return cli.NewExitError(fmt.Errorf("target transaction %s is accepted at block %s", txHash, tx.Blockhash.StringLE()), 1)
|
||||||
|
}
|
||||||
|
fmt.Fprintln(ctx.App.Writer, "Conflicting transaction accepted")
|
||||||
|
}
|
||||||
|
txctx.DumpTransactionInfo(ctx.App.Writer, resHash, res)
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -6,7 +6,9 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
"github.com/nspcc-dev/neo-go/cli/flags"
|
||||||
"github.com/nspcc-dev/neo-go/cli/options"
|
"github.com/nspcc-dev/neo-go/cli/options"
|
||||||
|
"github.com/nspcc-dev/neo-go/cli/txctx"
|
||||||
vmcli "github.com/nspcc-dev/neo-go/cli/vm"
|
vmcli "github.com/nspcc-dev/neo-go/cli/vm"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/vm"
|
"github.com/nspcc-dev/neo-go/pkg/vm"
|
||||||
"github.com/urfave/cli"
|
"github.com/urfave/cli"
|
||||||
|
@ -15,6 +17,16 @@ import (
|
||||||
// NewCommands returns util commands for neo-go CLI.
|
// NewCommands returns util commands for neo-go CLI.
|
||||||
func NewCommands() []cli.Command {
|
func NewCommands() []cli.Command {
|
||||||
txDumpFlags := append([]cli.Flag{}, options.RPC...)
|
txDumpFlags := append([]cli.Flag{}, options.RPC...)
|
||||||
|
txSendFlags := append(txDumpFlags, txctx.AwaitFlag)
|
||||||
|
txCancelFlags := append([]cli.Flag{
|
||||||
|
flags.AddressFlag{
|
||||||
|
Name: "address, a",
|
||||||
|
Usage: "address to use as conflicting transaction signee (and gas source)",
|
||||||
|
},
|
||||||
|
txctx.GasFlag,
|
||||||
|
txctx.AwaitFlag,
|
||||||
|
}, options.RPC...)
|
||||||
|
txCancelFlags = append(txCancelFlags, options.Wallet...)
|
||||||
return []cli.Command{
|
return []cli.Command{
|
||||||
{
|
{
|
||||||
Name: "util",
|
Name: "util",
|
||||||
|
@ -32,14 +44,35 @@ func NewCommands() []cli.Command {
|
||||||
{
|
{
|
||||||
Name: "sendtx",
|
Name: "sendtx",
|
||||||
Usage: "Send complete transaction stored in a context file",
|
Usage: "Send complete transaction stored in a context file",
|
||||||
UsageText: "sendtx [-r <endpoint>] <file.in>",
|
UsageText: "sendtx [-r <endpoint>] <file.in> [--await]",
|
||||||
Description: `Sends the transaction from the given context file to the given RPC node if it's
|
Description: `Sends the transaction from the given context file to the given RPC node if it's
|
||||||
completely signed and ready. This command expects a ContractParametersContext
|
completely signed and ready. This command expects a ContractParametersContext
|
||||||
JSON file for input, it can't handle binary (or hex- or base64-encoded)
|
JSON file for input, it can't handle binary (or hex- or base64-encoded)
|
||||||
transactions.
|
transactions. If the --await flag is included, the command waits for the
|
||||||
|
transaction to be included in a block before exiting.
|
||||||
`,
|
`,
|
||||||
Action: sendTx,
|
Action: sendTx,
|
||||||
Flags: txDumpFlags,
|
Flags: txSendFlags,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "canceltx",
|
||||||
|
Usage: "Cancel transaction by sending conflicting transaction",
|
||||||
|
UsageText: "canceltx <txid> -r <endpoint> --wallet <wallet> [--account <account>] [--wallet-config <path>] [--gas <gas>] [--await]",
|
||||||
|
Description: `Aims to prevent a transaction from being added to the blockchain by dispatching a more
|
||||||
|
prioritized conflicting transaction to the specified RPC node. The input for this command should
|
||||||
|
be the transaction hash. If another account is not specified, the conflicting transaction is
|
||||||
|
automatically generated and signed by the default account in the wallet. If the target transaction
|
||||||
|
is in the memory pool of the provided RPC node, the NetworkFee value of the conflicting transaction
|
||||||
|
is set to the target transaction's NetworkFee value plus one (if it's sufficient for the
|
||||||
|
conflicting transaction itself), the ValidUntilBlock value of the conflicting transaction is set to the
|
||||||
|
target transaction's ValidUntilBlock value. If the target transaction is not in the memory pool, standard
|
||||||
|
NetworkFee calculations are performed based on the calculatenetworkfee RPC request. If the --gas
|
||||||
|
flag is included, the specified value is added to the resulting conflicting transaction network fee
|
||||||
|
in both scenarios. When the --await flag is included, the command waits for one of the conflicting
|
||||||
|
or target transactions to be included in a block.
|
||||||
|
`,
|
||||||
|
Action: cancelTx,
|
||||||
|
Flags: txCancelFlags,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "txdump",
|
Name: "txdump",
|
||||||
|
@ -47,6 +80,12 @@ func NewCommands() []cli.Command {
|
||||||
UsageText: "txdump [-r <endpoint>] <file.in>",
|
UsageText: "txdump [-r <endpoint>] <file.in>",
|
||||||
Action: txDump,
|
Action: txDump,
|
||||||
Flags: txDumpFlags,
|
Flags: txDumpFlags,
|
||||||
|
Description: `Dumps the transaction from the given parameter context file to
|
||||||
|
the output. This command expects a ContractParametersContext JSON file for input, it can't handle
|
||||||
|
binary (or hex- or base64-encoded) transactions. If --rpc-endpoint flag is specified the result
|
||||||
|
of the given script after running it true the VM will be printed. Otherwise only transaction will
|
||||||
|
be printed.
|
||||||
|
`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "ops",
|
Name: "ops",
|
||||||
|
|
|
@ -29,7 +29,10 @@ func txDump(ctx *cli.Context) error {
|
||||||
return cli.NewExitError("verifiable item is not a transaction", 1)
|
return cli.NewExitError("verifiable item is not a transaction", 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
query.DumpApplicationLog(ctx, nil, tx, nil, true)
|
err = query.DumpApplicationLog(ctx, nil, tx, nil, true)
|
||||||
|
if err != nil {
|
||||||
|
return cli.NewExitError(err, 1)
|
||||||
|
}
|
||||||
|
|
||||||
if ctx.String(options.RPCEndpointFlag) != "" {
|
if ctx.String(options.RPCEndpointFlag) != "" {
|
||||||
gctx, cancel := options.GetTimeoutContext(ctx)
|
gctx, cancel := options.GetTimeoutContext(ctx)
|
||||||
|
|
|
@ -5,6 +5,9 @@ import (
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/cli/options"
|
"github.com/nspcc-dev/neo-go/cli/options"
|
||||||
"github.com/nspcc-dev/neo-go/cli/paramcontext"
|
"github.com/nspcc-dev/neo-go/cli/paramcontext"
|
||||||
|
"github.com/nspcc-dev/neo-go/cli/txctx"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/core/state"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/rpcclient/waiter"
|
||||||
"github.com/urfave/cli"
|
"github.com/urfave/cli"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -37,6 +40,14 @@ func sendTx(ctx *cli.Context) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(fmt.Errorf("failed to submit transaction to RPC node: %w", err), 1)
|
return cli.NewExitError(fmt.Errorf("failed to submit transaction to RPC node: %w", err), 1)
|
||||||
}
|
}
|
||||||
fmt.Fprintln(ctx.App.Writer, res.StringLE())
|
var aer *state.AppExecResult
|
||||||
|
if ctx.Bool("await") {
|
||||||
|
version, err := c.GetVersion()
|
||||||
|
aer, err = waiter.New(c, version).Wait(res, tx.ValidUntilBlock, err)
|
||||||
|
if err != nil {
|
||||||
|
return cli.NewExitError(fmt.Errorf("failed to await transaction %s: %w", res.StringLE(), err), 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
txctx.DumpTransactionInfo(ctx.App.Writer, res, aer)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,18 @@
|
||||||
package util_test
|
package util_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/internal/testcli"
|
"github.com/nspcc-dev/neo-go/internal/testcli"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/vm/vmstate"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -63,3 +69,124 @@ func TestUtilOps(t *testing.T) {
|
||||||
e.Run(t, "neo-go", "util", "ops", "--hex", "--in", tmp) // hex from file
|
e.Run(t, "neo-go", "util", "ops", "--hex", "--in", tmp) // hex from file
|
||||||
check(t)
|
check(t)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestUtilCancelTx(t *testing.T) {
|
||||||
|
e := testcli.NewExecutorSuspended(t)
|
||||||
|
|
||||||
|
w, err := wallet.NewWalletFromFile("../testdata/testwallet.json")
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
transferArgs := []string{
|
||||||
|
"neo-go", "wallet", "nep17", "transfer",
|
||||||
|
"--rpc-endpoint", "http://" + e.RPC.Addresses()[0],
|
||||||
|
"--wallet", testcli.ValidatorWallet,
|
||||||
|
"--to", w.Accounts[0].Address,
|
||||||
|
"--token", "NEO",
|
||||||
|
"--from", testcli.ValidatorAddr,
|
||||||
|
"--force",
|
||||||
|
}
|
||||||
|
args := []string{"neo-go", "util", "canceltx",
|
||||||
|
"-r", "http://" + e.RPC.Addresses()[0],
|
||||||
|
"--wallet", testcli.ValidatorWallet,
|
||||||
|
"--address", testcli.ValidatorAddr}
|
||||||
|
|
||||||
|
e.In.WriteString("one\r")
|
||||||
|
e.Run(t, append(transferArgs, "--amount", "1")...)
|
||||||
|
line := e.GetNextLine(t)
|
||||||
|
txHash, err := util.Uint256DecodeStringLE(line)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
_, ok := e.Chain.GetMemPool().TryGetValue(txHash)
|
||||||
|
require.True(t, ok)
|
||||||
|
|
||||||
|
t.Run("invalid", func(t *testing.T) {
|
||||||
|
t.Run("missing tx argument", func(t *testing.T) {
|
||||||
|
e.RunWithError(t, args...)
|
||||||
|
})
|
||||||
|
t.Run("excessive arguments", func(t *testing.T) {
|
||||||
|
e.RunWithError(t, append(args, txHash.StringLE(), txHash.StringLE())...)
|
||||||
|
})
|
||||||
|
t.Run("invalid hash", func(t *testing.T) {
|
||||||
|
e.RunWithError(t, append(args, "notahash")...)
|
||||||
|
})
|
||||||
|
t.Run("not signed by main signer", func(t *testing.T) {
|
||||||
|
e.In.WriteString("one\r")
|
||||||
|
e.RunWithError(t, "neo-go", "util", "canceltx",
|
||||||
|
"-r", "http://"+e.RPC.Addresses()[0],
|
||||||
|
"--wallet", testcli.ValidatorWallet,
|
||||||
|
"--address", testcli.MultisigAddr, txHash.StringLE())
|
||||||
|
})
|
||||||
|
t.Run("wrong rpc endpoint", func(t *testing.T) {
|
||||||
|
e.In.WriteString("one\r")
|
||||||
|
e.RunWithError(t, "neo-go", "util", "canceltx",
|
||||||
|
"-r", "http://localhost:20331",
|
||||||
|
"--wallet", testcli.ValidatorWallet, txHash.StringLE())
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
e.In.WriteString("one\r")
|
||||||
|
e.Run(t, append(args, txHash.StringLE())...)
|
||||||
|
resHash, err := util.Uint256DecodeStringLE(e.GetNextLine(t))
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
_, _, err = e.Chain.GetTransaction(resHash)
|
||||||
|
require.NoError(t, err)
|
||||||
|
e.CheckEOF(t)
|
||||||
|
go e.Chain.Run()
|
||||||
|
|
||||||
|
require.Eventually(t, func() bool {
|
||||||
|
_, aerErr := e.Chain.GetAppExecResults(resHash, trigger.Application)
|
||||||
|
return aerErr == nil
|
||||||
|
}, time.Second*2, time.Millisecond*50)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAwaitUtilCancelTx(t *testing.T) {
|
||||||
|
e := testcli.NewExecutor(t, true)
|
||||||
|
|
||||||
|
w, err := wallet.NewWalletFromFile("../testdata/testwallet.json")
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
transferArgs := []string{
|
||||||
|
"neo-go", "wallet", "nep17", "transfer",
|
||||||
|
"--rpc-endpoint", "http://" + e.RPC.Addresses()[0],
|
||||||
|
"--wallet", testcli.ValidatorWallet,
|
||||||
|
"--to", w.Accounts[0].Address,
|
||||||
|
"--token", "NEO",
|
||||||
|
"--from", testcli.ValidatorAddr,
|
||||||
|
"--force",
|
||||||
|
}
|
||||||
|
args := []string{"neo-go", "util", "canceltx",
|
||||||
|
"-r", "http://" + e.RPC.Addresses()[0],
|
||||||
|
"--wallet", testcli.ValidatorWallet,
|
||||||
|
"--address", testcli.ValidatorAddr,
|
||||||
|
"--await"}
|
||||||
|
|
||||||
|
e.In.WriteString("one\r")
|
||||||
|
e.Run(t, append(transferArgs, "--amount", "1")...)
|
||||||
|
line := e.GetNextLine(t)
|
||||||
|
txHash, err := util.Uint256DecodeStringLE(line)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
_, ok := e.Chain.GetMemPool().TryGetValue(txHash)
|
||||||
|
require.True(t, ok)
|
||||||
|
|
||||||
|
// Allow both cases: either target or conflicting tx acceptance.
|
||||||
|
e.In.WriteString("one\r")
|
||||||
|
err = e.RunUnchecked(t, append(args, txHash.StringLE())...)
|
||||||
|
switch {
|
||||||
|
case err == nil:
|
||||||
|
response := e.GetNextLine(t)
|
||||||
|
require.Equal(t, "Conflicting transaction accepted", response)
|
||||||
|
resHash, _ := e.CheckAwaitableTxPersisted(t)
|
||||||
|
require.NotEqual(t, resHash, txHash)
|
||||||
|
case strings.Contains(err.Error(), fmt.Sprintf("target transaction %s is accepted", txHash)) ||
|
||||||
|
strings.Contains(err.Error(), fmt.Sprintf("failed to send conflicting transaction: Invalid transaction attribute (-507) - invalid attribute: conflicting transaction %s is already on chain", txHash)):
|
||||||
|
tx, _ := e.GetTransaction(t, txHash)
|
||||||
|
aer, err := e.Chain.GetAppExecResults(tx.Hash(), trigger.Application)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, 1, len(aer))
|
||||||
|
require.Equal(t, vmstate.Halt, aer[0].VMState)
|
||||||
|
default:
|
||||||
|
t.Fatal(fmt.Errorf("unexpected error: %w", err))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -616,7 +616,7 @@ func getInstructionParameter(c *cli.Context) (int, error) {
|
||||||
}
|
}
|
||||||
n, err := strconv.Atoi(args[0])
|
n, err := strconv.Atoi(args[0])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, fmt.Errorf("%w: %s", ErrInvalidParameter, err) //nolint:errorlint // errorlint: non-wrapping format verb for fmt.Errorf. Use `%w` to format errors
|
return 0, fmt.Errorf("%w: %w", ErrInvalidParameter, err)
|
||||||
}
|
}
|
||||||
return n, nil
|
return n, nil
|
||||||
}
|
}
|
||||||
|
@ -736,7 +736,7 @@ func handleLoadNEF(c *cli.Context) error {
|
||||||
if signersStartOffset != 0 && len(args) > signersStartOffset {
|
if signersStartOffset != 0 && len(args) > signersStartOffset {
|
||||||
signers, err = cmdargs.ParseSigners(c.Args()[signersStartOffset:])
|
signers, err = cmdargs.ParseSigners(c.Args()[signersStartOffset:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("%w: failed to parse signers: %v", ErrInvalidParameter, err) //nolint:errorlint // errorlint: non-wrapping format verb for fmt.Errorf. Use `%w` to format errors
|
return fmt.Errorf("%w: failed to parse signers: %w", ErrInvalidParameter, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
err = prepareVM(c, createFakeTransaction(nef.Script, signers))
|
err = prepareVM(c, createFakeTransaction(nef.Script, signers))
|
||||||
|
@ -767,7 +767,7 @@ func handleLoadBase64(c *cli.Context) error {
|
||||||
}
|
}
|
||||||
b, err := base64.StdEncoding.DecodeString(args[0])
|
b, err := base64.StdEncoding.DecodeString(args[0])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("%w: %s", ErrInvalidParameter, err) //nolint:errorlint // errorlint: non-wrapping format verb for fmt.Errorf. Use `%w` to format errors
|
return fmt.Errorf("%w: %w", ErrInvalidParameter, err)
|
||||||
}
|
}
|
||||||
var signers []transaction.Signer
|
var signers []transaction.Signer
|
||||||
if len(args) > 1 {
|
if len(args) > 1 {
|
||||||
|
@ -779,7 +779,7 @@ func handleLoadBase64(c *cli.Context) error {
|
||||||
}
|
}
|
||||||
signers, err = cmdargs.ParseSigners(args[2:])
|
signers, err = cmdargs.ParseSigners(args[2:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("%w: %v", ErrInvalidParameter, err) //nolint:errorlint // errorlint: non-wrapping format verb for fmt.Errorf. Use `%w` to format errors
|
return fmt.Errorf("%w: %w", ErrInvalidParameter, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
err = prepareVM(c, createFakeTransaction(b, signers))
|
err = prepareVM(c, createFakeTransaction(b, signers))
|
||||||
|
@ -807,7 +807,7 @@ func handleLoadHex(c *cli.Context) error {
|
||||||
}
|
}
|
||||||
b, err := hex.DecodeString(args[0])
|
b, err := hex.DecodeString(args[0])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("%w: %s", ErrInvalidParameter, err) //nolint:errorlint // errorlint: non-wrapping format verb for fmt.Errorf. Use `%w` to format errors
|
return fmt.Errorf("%w: %w", ErrInvalidParameter, err)
|
||||||
}
|
}
|
||||||
var signers []transaction.Signer
|
var signers []transaction.Signer
|
||||||
if len(args) > 1 {
|
if len(args) > 1 {
|
||||||
|
@ -819,7 +819,7 @@ func handleLoadHex(c *cli.Context) error {
|
||||||
}
|
}
|
||||||
signers, err = cmdargs.ParseSigners(args[2:])
|
signers, err = cmdargs.ParseSigners(args[2:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("%w: %v", ErrInvalidParameter, err) //nolint:errorlint // errorlint: non-wrapping format verb for fmt.Errorf. Use `%w` to format errors
|
return fmt.Errorf("%w: %w", ErrInvalidParameter, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
err = prepareVM(c, createFakeTransaction(b, signers))
|
err = prepareVM(c, createFakeTransaction(b, signers))
|
||||||
|
@ -859,7 +859,7 @@ func handleLoadGo(c *cli.Context) error {
|
||||||
}
|
}
|
||||||
signers, err = cmdargs.ParseSigners(args[2:])
|
signers, err = cmdargs.ParseSigners(args[2:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("%w: %v", ErrInvalidParameter, err) //nolint:errorlint // errorlint: non-wrapping format verb for fmt.Errorf. Use `%w` to format errors
|
return fmt.Errorf("%w: %w", ErrInvalidParameter, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -962,7 +962,7 @@ func handleLoadDeployed(c *cli.Context) error {
|
||||||
}
|
}
|
||||||
signers, err = cmdargs.ParseSigners(args[2:])
|
signers, err = cmdargs.ParseSigners(args[2:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("%w: %v", ErrInvalidParameter, err) //nolint:errorlint // errorlint: non-wrapping format verb for fmt.Errorf. Use `%w` to format errors
|
return fmt.Errorf("%w: %w", ErrInvalidParameter, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
err = prepareVM(c, createFakeTransaction(cs.NEF.Script, signers)) // prepare VM one more time for proper IC initialization.
|
err = prepareVM(c, createFakeTransaction(cs.NEF.Script, signers)) // prepare VM one more time for proper IC initialization.
|
||||||
|
@ -1074,7 +1074,7 @@ func handleRun(c *cli.Context) error {
|
||||||
|
|
||||||
_, scParams, err := cmdargs.ParseParams(args[1:], true)
|
_, scParams, err := cmdargs.ParseParams(args[1:], true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("%w: %v", ErrInvalidParameter, err) //nolint:errorlint // errorlint: non-wrapping format verb for fmt.Errorf. Use `%w` to format errors
|
return fmt.Errorf("%w: %w", ErrInvalidParameter, err)
|
||||||
}
|
}
|
||||||
params = make([]stackitem.Item, len(scParams))
|
params = make([]stackitem.Item, len(scParams))
|
||||||
for i := range scParams {
|
for i := range scParams {
|
||||||
|
@ -1105,7 +1105,7 @@ func handleRun(c *cli.Context) error {
|
||||||
breaks := v.Context().BreakPoints() // We ensure that there's a context loaded.
|
breaks := v.Context().BreakPoints() // We ensure that there's a context loaded.
|
||||||
ic.ReuseVM(v)
|
ic.ReuseVM(v)
|
||||||
v.GasLimit = gasLimit
|
v.GasLimit = gasLimit
|
||||||
v.LoadNEFMethod(&cs.NEF, util.Uint160{}, cs.Hash, callflag.All, hasRet, offset, initOff, nil)
|
v.LoadNEFMethod(&cs.NEF, &cs.Manifest, util.Uint160{}, cs.Hash, callflag.All, hasRet, offset, initOff, nil)
|
||||||
for _, bp := range breaks {
|
for _, bp := range breaks {
|
||||||
v.AddBreakPoint(bp)
|
v.AddBreakPoint(bp)
|
||||||
}
|
}
|
||||||
|
@ -1185,7 +1185,7 @@ func handleStep(c *cli.Context) error {
|
||||||
if len(args) > 0 {
|
if len(args) > 0 {
|
||||||
n, err = strconv.Atoi(args[0])
|
n, err = strconv.Atoi(args[0])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("%w: %s", ErrInvalidParameter, err) //nolint:errorlint // errorlint: non-wrapping format verb for fmt.Errorf. Use `%w` to format errors
|
return fmt.Errorf("%w: %w", ErrInvalidParameter, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
v.AddBreakPointRel(n)
|
v.AddBreakPointRel(n)
|
||||||
|
@ -1436,58 +1436,57 @@ func Parse(args []string) (string, error) {
|
||||||
return "", ErrMissingParameter
|
return "", ErrMissingParameter
|
||||||
}
|
}
|
||||||
arg := args[0]
|
arg := args[0]
|
||||||
buf := bytes.NewBuffer(nil)
|
var buf []byte
|
||||||
if val, err := strconv.ParseInt(arg, 10, 64); err == nil {
|
if val, err := strconv.ParseInt(arg, 10, 64); err == nil {
|
||||||
bs := bigint.ToBytes(big.NewInt(val))
|
bs := bigint.ToBytes(big.NewInt(val))
|
||||||
buf.WriteString(fmt.Sprintf("Integer to Hex\t%s\n", hex.EncodeToString(bs)))
|
buf = fmt.Appendf(buf, "Integer to Hex\t%s\n", hex.EncodeToString(bs))
|
||||||
buf.WriteString(fmt.Sprintf("Integer to Base64\t%s\n", base64.StdEncoding.EncodeToString(bs)))
|
buf = fmt.Appendf(buf, "Integer to Base64\t%s\n", base64.StdEncoding.EncodeToString(bs))
|
||||||
}
|
}
|
||||||
noX := strings.TrimPrefix(arg, "0x")
|
noX := strings.TrimPrefix(arg, "0x")
|
||||||
if rawStr, err := hex.DecodeString(noX); err == nil {
|
if rawStr, err := hex.DecodeString(noX); err == nil {
|
||||||
if val, err := util.Uint160DecodeBytesBE(rawStr); err == nil {
|
if val, err := util.Uint160DecodeBytesBE(rawStr); err == nil {
|
||||||
buf.WriteString(fmt.Sprintf("BE ScriptHash to Address\t%s\n", address.Uint160ToString(val)))
|
buf = fmt.Appendf(buf, "BE ScriptHash to Address\t%s\n", address.Uint160ToString(val))
|
||||||
buf.WriteString(fmt.Sprintf("LE ScriptHash to Address\t%s\n", address.Uint160ToString(val.Reverse())))
|
buf = fmt.Appendf(buf, "LE ScriptHash to Address\t%s\n", address.Uint160ToString(val.Reverse()))
|
||||||
}
|
}
|
||||||
if pub, err := keys.NewPublicKeyFromBytes(rawStr, elliptic.P256()); err == nil {
|
if pub, err := keys.NewPublicKeyFromBytes(rawStr, elliptic.P256()); err == nil {
|
||||||
sh := pub.GetScriptHash()
|
sh := pub.GetScriptHash()
|
||||||
buf.WriteString(fmt.Sprintf("Public key to BE ScriptHash\t%s\n", sh))
|
buf = fmt.Appendf(buf, "Public key to BE ScriptHash\t%s\n", sh)
|
||||||
buf.WriteString(fmt.Sprintf("Public key to LE ScriptHash\t%s\n", sh.Reverse()))
|
buf = fmt.Appendf(buf, "Public key to LE ScriptHash\t%s\n", sh.Reverse())
|
||||||
buf.WriteString(fmt.Sprintf("Public key to Address\t%s\n", address.Uint160ToString(sh)))
|
buf = fmt.Appendf(buf, "Public key to Address\t%s\n", address.Uint160ToString(sh))
|
||||||
}
|
}
|
||||||
buf.WriteString(fmt.Sprintf("Hex to String\t%s\n", fmt.Sprintf("%q", string(rawStr))))
|
buf = fmt.Appendf(buf, "Hex to String\t%s\n", fmt.Sprintf("%q", string(rawStr)))
|
||||||
buf.WriteString(fmt.Sprintf("Hex to Integer\t%s\n", bigint.FromBytes(rawStr)))
|
buf = fmt.Appendf(buf, "Hex to Integer\t%s\n", bigint.FromBytes(rawStr))
|
||||||
buf.WriteString(fmt.Sprintf("Swap Endianness\t%s\n", hex.EncodeToString(slice.CopyReverse(rawStr))))
|
buf = fmt.Appendf(buf, "Swap Endianness\t%s\n", hex.EncodeToString(slice.CopyReverse(rawStr)))
|
||||||
}
|
}
|
||||||
if addr, err := address.StringToUint160(arg); err == nil {
|
if addr, err := address.StringToUint160(arg); err == nil {
|
||||||
buf.WriteString(fmt.Sprintf("Address to BE ScriptHash\t%s\n", addr))
|
buf = fmt.Appendf(buf, "Address to BE ScriptHash\t%s\n", addr)
|
||||||
buf.WriteString(fmt.Sprintf("Address to LE ScriptHash\t%s\n", addr.Reverse()))
|
buf = fmt.Appendf(buf, "Address to LE ScriptHash\t%s\n", addr.Reverse())
|
||||||
buf.WriteString(fmt.Sprintf("Address to Base64 (BE)\t%s\n", base64.StdEncoding.EncodeToString(addr.BytesBE())))
|
buf = fmt.Appendf(buf, "Address to Base64 (BE)\t%s\n", base64.StdEncoding.EncodeToString(addr.BytesBE()))
|
||||||
buf.WriteString(fmt.Sprintf("Address to Base64 (LE)\t%s\n", base64.StdEncoding.EncodeToString(addr.BytesLE())))
|
buf = fmt.Appendf(buf, "Address to Base64 (LE)\t%s\n", base64.StdEncoding.EncodeToString(addr.BytesLE()))
|
||||||
}
|
}
|
||||||
if rawStr, err := base64.StdEncoding.DecodeString(arg); err == nil {
|
if rawStr, err := base64.StdEncoding.DecodeString(arg); err == nil {
|
||||||
buf.WriteString(fmt.Sprintf("Base64 to String\t%s\n", fmt.Sprintf("%q", string(rawStr))))
|
buf = fmt.Appendf(buf, "Base64 to String\t%s\n", fmt.Sprintf("%q", string(rawStr)))
|
||||||
buf.WriteString(fmt.Sprintf("Base64 to BigInteger\t%s\n", bigint.FromBytes(rawStr)))
|
buf = fmt.Appendf(buf, "Base64 to BigInteger\t%s\n", bigint.FromBytes(rawStr))
|
||||||
if u, err := util.Uint160DecodeBytesBE(rawStr); err == nil {
|
if u, err := util.Uint160DecodeBytesBE(rawStr); err == nil {
|
||||||
buf.WriteString(fmt.Sprintf("Base64 to BE ScriptHash\t%s\n", u.StringBE()))
|
buf = fmt.Appendf(buf, "Base64 to BE ScriptHash\t%s\n", u.StringBE())
|
||||||
buf.WriteString(fmt.Sprintf("Base64 to LE ScriptHash\t%s\n", u.StringLE()))
|
buf = fmt.Appendf(buf, "Base64 to LE ScriptHash\t%s\n", u.StringLE())
|
||||||
buf.WriteString(fmt.Sprintf("Base64 to Address (BE)\t%s\n", address.Uint160ToString(u)))
|
buf = fmt.Appendf(buf, "Base64 to Address (BE)\t%s\n", address.Uint160ToString(u))
|
||||||
buf.WriteString(fmt.Sprintf("Base64 to Address (LE)\t%s\n", address.Uint160ToString(u.Reverse())))
|
buf = fmt.Appendf(buf, "Base64 to Address (LE)\t%s\n", address.Uint160ToString(u.Reverse()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
buf.WriteString(fmt.Sprintf("String to Hex\t%s\n", hex.EncodeToString([]byte(arg))))
|
buf = fmt.Appendf(buf, "String to Hex\t%s\n", hex.EncodeToString([]byte(arg)))
|
||||||
buf.WriteString(fmt.Sprintf("String to Base64\t%s\n", base64.StdEncoding.EncodeToString([]byte(arg))))
|
buf = fmt.Appendf(buf, "String to Base64\t%s\n", base64.StdEncoding.EncodeToString([]byte(arg)))
|
||||||
|
|
||||||
out := buf.Bytes()
|
res := bytes.NewBuffer(nil)
|
||||||
buf = bytes.NewBuffer(nil)
|
w := tabwriter.NewWriter(res, 0, 4, 4, '\t', 0)
|
||||||
w := tabwriter.NewWriter(buf, 0, 4, 4, '\t', 0)
|
if _, err := w.Write(buf); err != nil {
|
||||||
if _, err := w.Write(out); err != nil {
|
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
if err := w.Flush(); err != nil {
|
if err := w.Flush(); err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
return buf.String(), nil
|
return res.String(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
const logo = `
|
const logo = `
|
||||||
|
|
|
@ -14,6 +14,7 @@ import (
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
"sync/atomic"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -22,6 +23,7 @@ import (
|
||||||
"github.com/nspcc-dev/neo-go/cli/paramcontext"
|
"github.com/nspcc-dev/neo-go/cli/paramcontext"
|
||||||
"github.com/nspcc-dev/neo-go/internal/basicchain"
|
"github.com/nspcc-dev/neo-go/internal/basicchain"
|
||||||
"github.com/nspcc-dev/neo-go/internal/random"
|
"github.com/nspcc-dev/neo-go/internal/random"
|
||||||
|
"github.com/nspcc-dev/neo-go/internal/versionutil"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/compiler"
|
"github.com/nspcc-dev/neo-go/pkg/compiler"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/config"
|
"github.com/nspcc-dev/neo-go/pkg/config"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/config/netmode"
|
"github.com/nspcc-dev/neo-go/pkg/config/netmode"
|
||||||
|
@ -41,9 +43,11 @@ import (
|
||||||
"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
|
"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"go.uber.org/atomic"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Keep contract NEFs consistent between runs.
|
||||||
|
const _ = versionutil.TestVersion
|
||||||
|
|
||||||
type readCloser struct {
|
type readCloser struct {
|
||||||
sync.Mutex
|
sync.Mutex
|
||||||
bytes.Buffer
|
bytes.Buffer
|
||||||
|
@ -89,10 +93,11 @@ func newTestVMCLIWithLogoAndCustomConfig(t *testing.T, printLogo bool, cfg *conf
|
||||||
}
|
}
|
||||||
var c config.Config
|
var c config.Config
|
||||||
if cfg == nil {
|
if cfg == nil {
|
||||||
configPath := "../../config/protocol.unit_testnet.single.yml"
|
configPath := filepath.Join("..", "..", "config", "protocol.unit_testnet.single.yml")
|
||||||
var err error
|
var err error
|
||||||
c, err = config.LoadFile(configPath)
|
c, err = config.LoadFile(configPath, filepath.Join("..", "..", "config"))
|
||||||
require.NoError(t, err, "could not load chain config")
|
require.NoError(t, err, "could not load chain config")
|
||||||
|
require.Equal(t, filepath.Join("..", "..", "testdata", "wallet1_solo.json"), c.ApplicationConfiguration.Consensus.UnlockWallet.Path)
|
||||||
c.ApplicationConfiguration.DBConfiguration.Type = dbconfig.InMemoryDB
|
c.ApplicationConfiguration.DBConfiguration.Type = dbconfig.InMemoryDB
|
||||||
} else {
|
} else {
|
||||||
c = *cfg
|
c = *cfg
|
||||||
|
@ -129,6 +134,10 @@ func newTestVMClIWithState(t *testing.T) *executor {
|
||||||
}
|
}
|
||||||
bc, validators, committee, err := chain.NewMultiWithCustomConfigAndStoreNoCheck(t, customConfig, store)
|
bc, validators, committee, err := chain.NewMultiWithCustomConfigAndStoreNoCheck(t, customConfig, store)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// Save config for future usage.
|
||||||
|
protoCfg := bc.GetConfig()
|
||||||
|
|
||||||
go bc.Run()
|
go bc.Run()
|
||||||
e := neotest.NewExecutor(t, bc, validators, committee)
|
e := neotest.NewExecutor(t, bc, validators, committee)
|
||||||
basicchain.InitSimple(t, "../../", e)
|
basicchain.InitSimple(t, "../../", e)
|
||||||
|
@ -140,7 +149,9 @@ func newTestVMClIWithState(t *testing.T) *executor {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
cfg.ApplicationConfiguration.DBConfiguration.Type = dbconfig.LevelDB
|
cfg.ApplicationConfiguration.DBConfiguration.Type = dbconfig.LevelDB
|
||||||
cfg.ApplicationConfiguration.DBConfiguration.LevelDBOptions = opts
|
cfg.ApplicationConfiguration.DBConfiguration.LevelDBOptions = opts
|
||||||
cfg.ProtocolConfiguration.StateRootInHeader = true
|
cfg.ProtocolConfiguration.StateRootInHeader = protoCfg.StateRootInHeader
|
||||||
|
cfg.ProtocolConfiguration.P2PStateExchangeExtensions = protoCfg.P2PStateExchangeExtensions
|
||||||
|
cfg.ProtocolConfiguration.Hardforks = protoCfg.Hardforks
|
||||||
return newTestVMCLIWithLogoAndCustomConfig(t, false, &cfg)
|
return newTestVMCLIWithLogoAndCustomConfig(t, false, &cfg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -342,7 +353,7 @@ require (
|
||||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0
|
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0
|
||||||
)
|
)
|
||||||
replace github.com/nspcc-dev/neo-go/pkg/interop => ` + filepath.Join(wd, "../../pkg/interop") + `
|
replace github.com/nspcc-dev/neo-go/pkg/interop => ` + filepath.Join(wd, "../../pkg/interop") + `
|
||||||
go 1.18`)
|
go 1.20`)
|
||||||
require.NoError(t, os.WriteFile(filepath.Join(tmpDir, "go.mod"), goMod, os.ModePerm))
|
require.NoError(t, os.WriteFile(filepath.Join(tmpDir, "go.mod"), goMod, os.ModePerm))
|
||||||
return filename
|
return filename
|
||||||
}
|
}
|
||||||
|
@ -351,8 +362,6 @@ go 1.18`)
|
||||||
// via `loadnef` command. It returns the name of manifest and NEF files ready to be used in CLI
|
// via `loadnef` command. It returns the name of manifest and NEF files ready to be used in CLI
|
||||||
// commands.
|
// commands.
|
||||||
func prepareLoadnefSrc(t *testing.T, tmpDir, src string) (string, string) {
|
func prepareLoadnefSrc(t *testing.T, tmpDir, src string) (string, string) {
|
||||||
config.Version = "0.92.0-test"
|
|
||||||
|
|
||||||
nefFile, di, err := compiler.CompileWithOptions("test.go", strings.NewReader(src), nil)
|
nefFile, di, err := compiler.CompileWithOptions("test.go", strings.NewReader(src), nil)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
filename := filepath.Join(tmpDir, "vmtestcontract.nef")
|
filename := filepath.Join(tmpDir, "vmtestcontract.nef")
|
||||||
|
@ -678,6 +687,7 @@ func TestLoad_RunWithCALLT(t *testing.T) {
|
||||||
e.runProg(t,
|
e.runProg(t,
|
||||||
"loaddeployed "+cH.StringLE()+" -- NbrUYaZgyhSkNoRo9ugRyEMdUZxrhkNaWB:Global", // the contract's owner got from the contract's code.
|
"loaddeployed "+cH.StringLE()+" -- NbrUYaZgyhSkNoRo9ugRyEMdUZxrhkNaWB:Global", // the contract's owner got from the contract's code.
|
||||||
"run destroy",
|
"run destroy",
|
||||||
|
"exit",
|
||||||
)
|
)
|
||||||
e.checkNextLine(t, "READY: loaded \\d* instructions")
|
e.checkNextLine(t, "READY: loaded \\d* instructions")
|
||||||
e.checkStack(t) // Nothing on stack, successful execution.
|
e.checkStack(t) // Nothing on stack, successful execution.
|
||||||
|
@ -1094,7 +1104,7 @@ func TestRunWithHistoricState(t *testing.T) {
|
||||||
e.checkNextLine(t, "READY: loaded 36 instructions")
|
e.checkNextLine(t, "READY: loaded 36 instructions")
|
||||||
e.checkStack(t, []byte{1})
|
e.checkStack(t, []byte{1})
|
||||||
e.checkNextLine(t, "READY: loaded 36 instructions")
|
e.checkNextLine(t, "READY: loaded 36 instructions")
|
||||||
e.checkNextLineExact(t, "Error: at instruction 31 (SYSCALL): System.Contract.Call failed: called contract 73a23e915b66ae406866787f4a6c1c517dc981e2 not found: key not found\n")
|
e.checkNextLineExact(t, "Error: at instruction 31 (SYSCALL): System.Contract.Call failed: called contract 0f825b050eb8ce9eaa82993e90615025ab798016 not found: key not found\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestEvents(t *testing.T) {
|
func TestEvents(t *testing.T) {
|
||||||
|
|
|
@ -13,7 +13,7 @@ import (
|
||||||
|
|
||||||
// NewCommands returns 'vm' command.
|
// NewCommands returns 'vm' command.
|
||||||
func NewCommands() []cli.Command {
|
func NewCommands() []cli.Command {
|
||||||
cfgFlags := []cli.Flag{options.Config, options.ConfigFile}
|
cfgFlags := []cli.Flag{options.Config, options.ConfigFile, options.RelativePath}
|
||||||
cfgFlags = append(cfgFlags, options.Network...)
|
cfgFlags = append(cfgFlags, options.Network...)
|
||||||
return []cli.Command{{
|
return []cli.Command{{
|
||||||
Name: "vm",
|
Name: "vm",
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package wallet_test
|
package wallet_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/hex"
|
|
||||||
"math/big"
|
"math/big"
|
||||||
"strconv"
|
"strconv"
|
||||||
"testing"
|
"testing"
|
||||||
|
@ -18,7 +17,7 @@ func TestRegisterCandidate(t *testing.T) {
|
||||||
|
|
||||||
validatorAddress := testcli.ValidatorPriv.Address()
|
validatorAddress := testcli.ValidatorPriv.Address()
|
||||||
validatorPublic := testcli.ValidatorPriv.PublicKey()
|
validatorPublic := testcli.ValidatorPriv.PublicKey()
|
||||||
validatorHex := hex.EncodeToString(validatorPublic.Bytes())
|
validatorHex := validatorPublic.StringCompressed()
|
||||||
|
|
||||||
e.In.WriteString("one\r")
|
e.In.WriteString("one\r")
|
||||||
e.Run(t, "neo-go", "wallet", "nep17", "multitransfer",
|
e.Run(t, "neo-go", "wallet", "nep17", "multitransfer",
|
||||||
|
@ -159,4 +158,61 @@ func TestRegisterCandidate(t *testing.T) {
|
||||||
e.RunWithError(t, "neo-go", "query", "voter", "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], validatorAddress, validatorAddress)
|
e.RunWithError(t, "neo-go", "query", "voter", "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], validatorAddress, validatorAddress)
|
||||||
e.RunWithError(t, "neo-go", "query", "committee", "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], "something")
|
e.RunWithError(t, "neo-go", "query", "committee", "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], "something")
|
||||||
e.RunWithError(t, "neo-go", "query", "candidates", "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], "something")
|
e.RunWithError(t, "neo-go", "query", "candidates", "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], "something")
|
||||||
|
|
||||||
|
t.Run("VoteUnvote await", func(t *testing.T) {
|
||||||
|
e.In.WriteString("one\r")
|
||||||
|
e.Run(t, "neo-go", "wallet", "candidate", "register",
|
||||||
|
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
|
||||||
|
"--wallet", testcli.ValidatorWallet,
|
||||||
|
"--address", validatorAddress,
|
||||||
|
"--force", "--await")
|
||||||
|
e.CheckAwaitableTxPersisted(t)
|
||||||
|
|
||||||
|
e.In.WriteString("one\r")
|
||||||
|
e.Run(t, "neo-go", "wallet", "candidate", "vote",
|
||||||
|
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
|
||||||
|
"--wallet", testcli.ValidatorWallet,
|
||||||
|
"--address", validatorAddress,
|
||||||
|
"--candidate", validatorHex,
|
||||||
|
"--force",
|
||||||
|
"--await")
|
||||||
|
|
||||||
|
e.CheckAwaitableTxPersisted(t)
|
||||||
|
b, _ := e.Chain.GetGoverningTokenBalance(testcli.ValidatorPriv.GetScriptHash())
|
||||||
|
|
||||||
|
// unvote
|
||||||
|
e.In.WriteString("one\r")
|
||||||
|
e.Run(t, "neo-go", "wallet", "candidate", "vote",
|
||||||
|
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
|
||||||
|
"--wallet", testcli.ValidatorWallet,
|
||||||
|
"--address", validatorAddress,
|
||||||
|
"--force", "--await")
|
||||||
|
_, index := e.CheckAwaitableTxPersisted(t)
|
||||||
|
|
||||||
|
vs, err = e.Chain.GetEnrollments()
|
||||||
|
require.Equal(t, 1, len(vs))
|
||||||
|
require.Equal(t, validatorPublic, vs[0].Key)
|
||||||
|
require.Equal(t, big.NewInt(0), vs[0].Votes)
|
||||||
|
|
||||||
|
// check state
|
||||||
|
e.Run(t, "neo-go", "query", "voter",
|
||||||
|
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
|
||||||
|
validatorAddress)
|
||||||
|
e.CheckNextLine(t, "^\\s*Voted:\\s+"+"null") // no vote.
|
||||||
|
e.CheckNextLine(t, "^\\s*Amount\\s*:\\s*"+b.String()+"$")
|
||||||
|
e.CheckNextLine(t, "^\\s*Block\\s*:\\s*"+strconv.FormatUint(uint64(index), 10))
|
||||||
|
e.CheckEOF(t)
|
||||||
|
})
|
||||||
|
|
||||||
|
e.In.WriteString("one\r")
|
||||||
|
e.Run(t, "neo-go", "wallet", "candidate", "unregister",
|
||||||
|
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
|
||||||
|
"--wallet", testcli.ValidatorWallet,
|
||||||
|
"--address", validatorAddress,
|
||||||
|
"--force",
|
||||||
|
"--await")
|
||||||
|
e.CheckAwaitableTxPersisted(t)
|
||||||
|
|
||||||
|
vs, err = e.Chain.GetEnrollments()
|
||||||
|
require.Equal(t, 0, len(vs))
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
"github.com/nspcc-dev/neo-go/cli/options"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
|
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
||||||
|
@ -46,7 +47,7 @@ func newWalletV2FromFile(path string, configPath string) (*walletV2, *string, er
|
||||||
}
|
}
|
||||||
var pass *string
|
var pass *string
|
||||||
if len(configPath) != 0 {
|
if len(configPath) != 0 {
|
||||||
cfg, err := ReadWalletConfig(configPath)
|
cfg, err := options.ReadWalletConfig(configPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
package wallet
|
package wallet
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"crypto/elliptic"
|
"crypto/elliptic"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/util/slice"
|
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -36,27 +36,27 @@ func TestParseMultisigContract(t *testing.T) {
|
||||||
testParseMultisigContract(t, s, 1, pub)
|
testParseMultisigContract(t, s, 1, pub)
|
||||||
})
|
})
|
||||||
t.Run("bad, no check multisig", func(t *testing.T) {
|
t.Run("bad, no check multisig", func(t *testing.T) {
|
||||||
sBad := slice.Copy(s)
|
sBad := bytes.Clone(s)
|
||||||
sBad[len(sBad)-1] ^= 0xFF
|
sBad[len(sBad)-1] ^= 0xFF
|
||||||
testParseMultisigContract(t, sBad, 0)
|
testParseMultisigContract(t, sBad, 0)
|
||||||
})
|
})
|
||||||
t.Run("bad, invalid number of keys", func(t *testing.T) {
|
t.Run("bad, invalid number of keys", func(t *testing.T) {
|
||||||
sBad := slice.Copy(s)
|
sBad := bytes.Clone(s)
|
||||||
sBad[len(sBad)-2] = opPush1 + 1
|
sBad[len(sBad)-2] = opPush1 + 1
|
||||||
testParseMultisigContract(t, sBad, 0)
|
testParseMultisigContract(t, sBad, 0)
|
||||||
})
|
})
|
||||||
t.Run("bad, invalid first instruction", func(t *testing.T) {
|
t.Run("bad, invalid first instruction", func(t *testing.T) {
|
||||||
sBad := slice.Copy(s)
|
sBad := bytes.Clone(s)
|
||||||
sBad[0] = 0xFF
|
sBad[0] = 0xFF
|
||||||
testParseMultisigContract(t, sBad, 0)
|
testParseMultisigContract(t, sBad, 0)
|
||||||
})
|
})
|
||||||
t.Run("bad, invalid public key", func(t *testing.T) {
|
t.Run("bad, invalid public key", func(t *testing.T) {
|
||||||
sBad := slice.Copy(s)
|
sBad := bytes.Clone(s)
|
||||||
sBad[2] = 0xFF
|
sBad[2] = 0xFF
|
||||||
testParseMultisigContract(t, sBad, 0)
|
testParseMultisigContract(t, sBad, 0)
|
||||||
})
|
})
|
||||||
t.Run("bad, many sigs", func(t *testing.T) {
|
t.Run("bad, many sigs", func(t *testing.T) {
|
||||||
sBad := slice.Copy(s)
|
sBad := bytes.Clone(s)
|
||||||
sBad[0] = opPush1 + 1
|
sBad[0] = opPush1 + 1
|
||||||
testParseMultisigContract(t, sBad, 0)
|
testParseMultisigContract(t, sBad, 0)
|
||||||
})
|
})
|
||||||
|
|
|
@ -8,7 +8,10 @@ import (
|
||||||
"github.com/nspcc-dev/neo-go/cli/flags"
|
"github.com/nspcc-dev/neo-go/cli/flags"
|
||||||
"github.com/nspcc-dev/neo-go/cli/options"
|
"github.com/nspcc-dev/neo-go/cli/options"
|
||||||
"github.com/nspcc-dev/neo-go/cli/paramcontext"
|
"github.com/nspcc-dev/neo-go/cli/paramcontext"
|
||||||
|
"github.com/nspcc-dev/neo-go/cli/txctx"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/core/state"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/rpcclient/waiter"
|
||||||
"github.com/urfave/cli"
|
"github.com/urfave/cli"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -17,15 +20,11 @@ func signStoredTransaction(ctx *cli.Context) error {
|
||||||
out = ctx.String("out")
|
out = ctx.String("out")
|
||||||
rpcNode = ctx.String(options.RPCEndpointFlag)
|
rpcNode = ctx.String(options.RPCEndpointFlag)
|
||||||
addrFlag = ctx.Generic("address").(*flags.Address)
|
addrFlag = ctx.Generic("address").(*flags.Address)
|
||||||
|
aer *state.AppExecResult
|
||||||
)
|
)
|
||||||
if err := cmdargs.EnsureNone(ctx); err != nil {
|
if err := cmdargs.EnsureNone(ctx); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
wall, pass, err := readWallet(ctx)
|
|
||||||
if err != nil {
|
|
||||||
return cli.NewExitError(err, 1)
|
|
||||||
}
|
|
||||||
defer wall.Close()
|
|
||||||
|
|
||||||
pc, err := paramcontext.Read(ctx.String("in"))
|
pc, err := paramcontext.Read(ctx.String("in"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -35,9 +34,7 @@ func signStoredTransaction(ctx *cli.Context) error {
|
||||||
if !addrFlag.IsSet {
|
if !addrFlag.IsSet {
|
||||||
return cli.NewExitError("address was not provided", 1)
|
return cli.NewExitError("address was not provided", 1)
|
||||||
}
|
}
|
||||||
|
acc, _, err := options.GetAccFromContext(ctx)
|
||||||
var ch = addrFlag.Uint160()
|
|
||||||
acc, err := getDecryptedAccount(wall, ch, pass)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.NewExitError(err, 1)
|
||||||
}
|
}
|
||||||
|
@ -47,20 +44,13 @@ func signStoredTransaction(ctx *cli.Context) error {
|
||||||
return cli.NewExitError("verifiable item is not a transaction", 1)
|
return cli.NewExitError("verifiable item is not a transaction", 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
signerFound := false
|
if !tx.HasSigner(acc.ScriptHash()) {
|
||||||
for i := range tx.Signers {
|
|
||||||
if tx.Signers[i].Account == ch {
|
|
||||||
signerFound = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !signerFound {
|
|
||||||
return cli.NewExitError("tx signers don't contain provided account", 1)
|
return cli.NewExitError("tx signers don't contain provided account", 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
if acc.CanSign() {
|
if acc.CanSign() {
|
||||||
sign := acc.SignHashable(pc.Network, pc.Verifiable)
|
sign := acc.SignHashable(pc.Network, pc.Verifiable)
|
||||||
if err := pc.AddSignature(ch, acc.Contract, acc.PublicKey(), sign); err != nil {
|
if err := pc.AddSignature(acc.ScriptHash(), acc.Contract, acc.PublicKey(), sign); err != nil {
|
||||||
return cli.NewExitError(fmt.Errorf("can't add signature: %w", err), 1)
|
return cli.NewExitError(fmt.Errorf("can't add signature: %w", err), 1)
|
||||||
}
|
}
|
||||||
} else if rpcNode == "" {
|
} else if rpcNode == "" {
|
||||||
|
@ -98,10 +88,15 @@ func signStoredTransaction(ctx *cli.Context) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(fmt.Errorf("failed to submit transaction to RPC node: %w", err), 1)
|
return cli.NewExitError(fmt.Errorf("failed to submit transaction to RPC node: %w", err), 1)
|
||||||
}
|
}
|
||||||
fmt.Fprintln(ctx.App.Writer, res.StringLE())
|
if ctx.Bool("await") {
|
||||||
return nil
|
version, err := c.GetVersion()
|
||||||
|
aer, err = waiter.New(c, version).Wait(res, tx.ValidUntilBlock, err)
|
||||||
|
if err != nil {
|
||||||
|
return cli.NewExitError(fmt.Errorf("failed to await transaction %s: %w", res.StringLE(), err), 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Fprintln(ctx.App.Writer, tx.Hash().StringLE())
|
txctx.DumpTransactionInfo(ctx.App.Writer, tx.Hash(), aer)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package wallet_test
|
package wallet_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/hex"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
@ -45,9 +44,9 @@ func TestSignMultisigTx(t *testing.T) {
|
||||||
"--wallet", w,
|
"--wallet", w,
|
||||||
"--wif", wif,
|
"--wif", wif,
|
||||||
"--min", "2",
|
"--min", "2",
|
||||||
hex.EncodeToString(pubs[0].Bytes()),
|
pubs[0].StringCompressed(),
|
||||||
hex.EncodeToString(pubs[1].Bytes()),
|
pubs[1].StringCompressed(),
|
||||||
hex.EncodeToString(pubs[2].Bytes()))
|
pubs[2].StringCompressed())
|
||||||
}
|
}
|
||||||
addAccount(wallet1Path, privs[0].WIF())
|
addAccount(wallet1Path, privs[0].WIF())
|
||||||
addAccount(wallet2Path, privs[1].WIF())
|
addAccount(wallet2Path, privs[1].WIF())
|
||||||
|
|
|
@ -101,7 +101,7 @@ func newNEP11Commands() []cli.Command {
|
||||||
{
|
{
|
||||||
Name: "transfer",
|
Name: "transfer",
|
||||||
Usage: "transfer NEP-11 tokens",
|
Usage: "transfer NEP-11 tokens",
|
||||||
UsageText: "transfer -w wallet [--wallet-config path] --rpc-endpoint <node> --timeout <time> --from <addr> --to <addr> --token <hash-or-name> --id <token-id> [--amount string] [data] [-- <cosigner1:Scope> [<cosigner2> [...]]]",
|
UsageText: "transfer -w wallet [--wallet-config path] --rpc-endpoint <node> --timeout <time> --from <addr> --to <addr> --token <hash-or-name> --id <token-id> [--amount string] [--await] [data] [-- <cosigner1:Scope> [<cosigner2> [...]]]",
|
||||||
Action: transferNEP11,
|
Action: transferNEP11,
|
||||||
Flags: transferFlags,
|
Flags: transferFlags,
|
||||||
Description: `Transfers specified NEP-11 token with optional cosigners list attached to
|
Description: `Transfers specified NEP-11 token with optional cosigners list attached to
|
||||||
|
@ -110,7 +110,8 @@ func newNEP11Commands() []cli.Command {
|
||||||
'contract testinvokefunction' documentation for the details
|
'contract testinvokefunction' documentation for the details
|
||||||
about cosigners syntax. If no cosigners are given then the
|
about cosigners syntax. If no cosigners are given then the
|
||||||
sender with CalledByEntry scope will be used as the only
|
sender with CalledByEntry scope will be used as the only
|
||||||
signer.
|
signer. If --await flag is set then the command will wait
|
||||||
|
for the transaction to be included in a block.
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -30,6 +30,14 @@ import (
|
||||||
"github.com/urfave/cli"
|
"github.com/urfave/cli"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// transferTarget represents target address, token amount and data for transfer.
|
||||||
|
type transferTarget struct {
|
||||||
|
Token util.Uint160
|
||||||
|
Address util.Uint160
|
||||||
|
Amount int64
|
||||||
|
Data any
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
tokenFlag = cli.StringFlag{
|
tokenFlag = cli.StringFlag{
|
||||||
Name: "token",
|
Name: "token",
|
||||||
|
@ -62,6 +70,7 @@ var (
|
||||||
txctx.GasFlag,
|
txctx.GasFlag,
|
||||||
txctx.SysGasFlag,
|
txctx.SysGasFlag,
|
||||||
txctx.ForceFlag,
|
txctx.ForceFlag,
|
||||||
|
txctx.AwaitFlag,
|
||||||
cli.StringFlag{
|
cli.StringFlag{
|
||||||
Name: "amount",
|
Name: "amount",
|
||||||
Usage: "Amount of asset to send",
|
Usage: "Amount of asset to send",
|
||||||
|
@ -75,6 +84,7 @@ var (
|
||||||
txctx.GasFlag,
|
txctx.GasFlag,
|
||||||
txctx.SysGasFlag,
|
txctx.SysGasFlag,
|
||||||
txctx.ForceFlag,
|
txctx.ForceFlag,
|
||||||
|
txctx.AwaitFlag,
|
||||||
}, options.RPC...)
|
}, options.RPC...)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -139,20 +149,22 @@ func newNEP17Commands() []cli.Command {
|
||||||
{
|
{
|
||||||
Name: "transfer",
|
Name: "transfer",
|
||||||
Usage: "transfer NEP-17 tokens",
|
Usage: "transfer NEP-17 tokens",
|
||||||
UsageText: "transfer -w wallet [--wallet-config path] --rpc-endpoint <node> --timeout <time> --from <addr> --to <addr> --token <hash-or-name> --amount string [data] [-- <cosigner1:Scope> [<cosigner2> [...]]]",
|
UsageText: "transfer -w wallet [--wallet-config path] [--await] --rpc-endpoint <node> --timeout <time> --from <addr> --to <addr> --token <hash-or-name> --amount string [data] [-- <cosigner1:Scope> [<cosigner2> [...]]]",
|
||||||
Action: transferNEP17,
|
Action: transferNEP17,
|
||||||
Flags: transferFlags,
|
Flags: transferFlags,
|
||||||
Description: `Transfers specified NEP-17 token amount with optional 'data' parameter and cosigners
|
Description: `Transfers specified NEP-17 token amount with optional 'data' parameter and cosigners
|
||||||
list attached to the transfer. See 'contract testinvokefunction' documentation
|
list attached to the transfer. See 'contract testinvokefunction' documentation
|
||||||
for the details about 'data' parameter and cosigners syntax. If no 'data' is
|
for the details about 'data' parameter and cosigners syntax. If no 'data' is
|
||||||
given then default nil value will be used. If no cosigners are given then the
|
given then default nil value will be used. If no cosigners are given then the
|
||||||
sender with CalledByEntry scope will be used as the only signer.
|
sender with CalledByEntry scope will be used as the only signer. When --await
|
||||||
|
flag is used, the command waits for the transaction to be included in a block
|
||||||
|
before exiting.
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "multitransfer",
|
Name: "multitransfer",
|
||||||
Usage: "transfer NEP-17 tokens to multiple recipients",
|
Usage: "transfer NEP-17 tokens to multiple recipients",
|
||||||
UsageText: `multitransfer -w wallet [--wallet-config path] --rpc-endpoint <node> --timeout <time> --from <addr>` +
|
UsageText: `multitransfer -w wallet [--wallet-config path] [--await] --rpc-endpoint <node> --timeout <time> --from <addr>` +
|
||||||
` <token1>:<addr1>:<amount1> [<token2>:<addr2>:<amount2> [...]] [-- <cosigner1:Scope> [<cosigner2> [...]]]`,
|
` <token1>:<addr1>:<amount1> [<token2>:<addr2>:<amount2> [...]] [-- <cosigner1:Scope> [<cosigner2> [...]]]`,
|
||||||
Action: multiTransferNEP17,
|
Action: multiTransferNEP17,
|
||||||
Flags: multiTransferFlags,
|
Flags: multiTransferFlags,
|
||||||
|
@ -514,7 +526,7 @@ func multiTransferNEP17(ctx *cli.Context) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.NewExitError(err, 1)
|
||||||
}
|
}
|
||||||
acc, err := getDecryptedAccount(wall, from, pass)
|
acc, err := options.GetUnlockedAccount(wall, from, pass)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.NewExitError(err, 1)
|
||||||
}
|
}
|
||||||
|
@ -522,25 +534,36 @@ func multiTransferNEP17(ctx *cli.Context) error {
|
||||||
gctx, cancel := options.GetTimeoutContext(ctx)
|
gctx, cancel := options.GetTimeoutContext(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
c, err := options.GetRPCClient(gctx, ctx)
|
|
||||||
if err != nil {
|
|
||||||
return cli.NewExitError(err, 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
if ctx.NArg() == 0 {
|
if ctx.NArg() == 0 {
|
||||||
return cli.NewExitError("empty recipients list", 1)
|
return cli.NewExitError("empty recipients list", 1)
|
||||||
}
|
}
|
||||||
var (
|
var (
|
||||||
recipients []rpcclient.TransferTarget
|
recipients []transferTarget
|
||||||
cosignersOffset = ctx.NArg()
|
cosignersSepPos = ctx.NArg() // `--` position.
|
||||||
)
|
)
|
||||||
cache := make(map[string]*wallet.Token)
|
|
||||||
for i := 0; i < ctx.NArg(); i++ {
|
for i := 0; i < ctx.NArg(); i++ {
|
||||||
arg := ctx.Args().Get(i)
|
arg := ctx.Args().Get(i)
|
||||||
if arg == cmdargs.CosignersSeparator {
|
if arg == cmdargs.CosignersSeparator {
|
||||||
cosignersOffset = i + 1
|
cosignersSepPos = i
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
cosigners, extErr := cmdargs.GetSignersFromContext(ctx, cosignersSepPos+1)
|
||||||
|
if extErr != nil {
|
||||||
|
return extErr
|
||||||
|
}
|
||||||
|
signersAccounts, err := cmdargs.GetSignersAccounts(acc, wall, cosigners, transaction.CalledByEntry)
|
||||||
|
if err != nil {
|
||||||
|
return cli.NewExitError(fmt.Errorf("invalid signers: %w", err), 1)
|
||||||
|
}
|
||||||
|
c, act, exitErr := options.GetRPCWithActor(gctx, ctx, signersAccounts)
|
||||||
|
if exitErr != nil {
|
||||||
|
return exitErr
|
||||||
|
}
|
||||||
|
|
||||||
|
cache := make(map[string]*wallet.Token)
|
||||||
|
for i := 0; i < cosignersSepPos; i++ {
|
||||||
|
arg := ctx.Args().Get(i)
|
||||||
ss := strings.SplitN(arg, ":", 3)
|
ss := strings.SplitN(arg, ":", 3)
|
||||||
if len(ss) != 3 {
|
if len(ss) != 3 {
|
||||||
return cli.NewExitError("send format must be '<token>:<addr>:<amount>", 1)
|
return cli.NewExitError("send format must be '<token>:<addr>:<amount>", 1)
|
||||||
|
@ -564,7 +587,7 @@ func multiTransferNEP17(ctx *cli.Context) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(fmt.Errorf("invalid amount: %w", err), 1)
|
return cli.NewExitError(fmt.Errorf("invalid amount: %w", err), 1)
|
||||||
}
|
}
|
||||||
recipients = append(recipients, rpcclient.TransferTarget{
|
recipients = append(recipients, transferTarget{
|
||||||
Token: token.Hash,
|
Token: token.Hash,
|
||||||
Address: addr,
|
Address: addr,
|
||||||
Amount: amount.Int64(),
|
Amount: amount.Int64(),
|
||||||
|
@ -572,19 +595,6 @@ func multiTransferNEP17(ctx *cli.Context) error {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
cosigners, extErr := cmdargs.GetSignersFromContext(ctx, cosignersOffset)
|
|
||||||
if extErr != nil {
|
|
||||||
return extErr
|
|
||||||
}
|
|
||||||
signersAccounts, err := cmdargs.GetSignersAccounts(acc, wall, cosigners, transaction.CalledByEntry)
|
|
||||||
if err != nil {
|
|
||||||
return cli.NewExitError(fmt.Errorf("invalid signers: %w", err), 1)
|
|
||||||
}
|
|
||||||
act, err := actor.New(c, signersAccounts)
|
|
||||||
if err != nil {
|
|
||||||
return cli.NewExitError(fmt.Errorf("failed to create RPC actor: %w", err), 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
tx, err := makeMultiTransferNEP17(act, recipients)
|
tx, err := makeMultiTransferNEP17(act, recipients)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(fmt.Errorf("can't make transaction: %w", err), 1)
|
return cli.NewExitError(fmt.Errorf("can't make transaction: %w", err), 1)
|
||||||
|
@ -610,7 +620,7 @@ func transferNEP(ctx *cli.Context, standard string) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.NewExitError(err, 1)
|
||||||
}
|
}
|
||||||
acc, err := getDecryptedAccount(wall, from, pass)
|
acc, err := options.GetUnlockedAccount(wall, from, pass)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.NewExitError(err, 1)
|
||||||
}
|
}
|
||||||
|
@ -618,9 +628,22 @@ func transferNEP(ctx *cli.Context, standard string) error {
|
||||||
gctx, cancel := options.GetTimeoutContext(ctx)
|
gctx, cancel := options.GetTimeoutContext(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
c, err := options.GetRPCClient(gctx, ctx)
|
cosignersOffset, data, extErr := cmdargs.GetDataFromContext(ctx)
|
||||||
|
if extErr != nil {
|
||||||
|
return extErr
|
||||||
|
}
|
||||||
|
cosigners, extErr := cmdargs.GetSignersFromContext(ctx, cosignersOffset)
|
||||||
|
if extErr != nil {
|
||||||
|
return extErr
|
||||||
|
}
|
||||||
|
signersAccounts, err := cmdargs.GetSignersAccounts(acc, wall, cosigners, transaction.CalledByEntry)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.NewExitError(fmt.Errorf("invalid signers: %w", err), 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
c, act, exitErr := options.GetRPCWithActor(gctx, ctx, signersAccounts)
|
||||||
|
if exitErr != nil {
|
||||||
|
return exitErr
|
||||||
}
|
}
|
||||||
|
|
||||||
toFlag := ctx.Generic("to").(*flags.Address)
|
toFlag := ctx.Generic("to").(*flags.Address)
|
||||||
|
@ -636,24 +659,6 @@ func transferNEP(ctx *cli.Context, standard string) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cosignersOffset, data, extErr := cmdargs.GetDataFromContext(ctx)
|
|
||||||
if extErr != nil {
|
|
||||||
return extErr
|
|
||||||
}
|
|
||||||
|
|
||||||
cosigners, extErr := cmdargs.GetSignersFromContext(ctx, cosignersOffset)
|
|
||||||
if extErr != nil {
|
|
||||||
return extErr
|
|
||||||
}
|
|
||||||
signersAccounts, err := cmdargs.GetSignersAccounts(acc, wall, cosigners, transaction.CalledByEntry)
|
|
||||||
if err != nil {
|
|
||||||
return cli.NewExitError(fmt.Errorf("invalid signers: %w", err), 1)
|
|
||||||
}
|
|
||||||
act, err := actor.New(c, signersAccounts)
|
|
||||||
if err != nil {
|
|
||||||
return cli.NewExitError(fmt.Errorf("failed to create RPC actor: %w", err), 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
amountArg := ctx.String("amount")
|
amountArg := ctx.String("amount")
|
||||||
amount, err := fixedn.FromString(amountArg, int(token.Decimals))
|
amount, err := fixedn.FromString(amountArg, int(token.Decimals))
|
||||||
// It's OK for NEP-11 transfer to not have amount set.
|
// It's OK for NEP-11 transfer to not have amount set.
|
||||||
|
@ -690,7 +695,7 @@ func transferNEP(ctx *cli.Context, standard string) error {
|
||||||
return txctx.SignAndSend(ctx, act, acc, tx)
|
return txctx.SignAndSend(ctx, act, acc, tx)
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeMultiTransferNEP17(act *actor.Actor, recipients []rpcclient.TransferTarget) (*transaction.Transaction, error) {
|
func makeMultiTransferNEP17(act *actor.Actor, recipients []transferTarget) (*transaction.Transaction, error) {
|
||||||
scr := smartcontract.NewBuilder()
|
scr := smartcontract.NewBuilder()
|
||||||
for i := range recipients {
|
for i := range recipients {
|
||||||
scr.InvokeWithAssert(recipients[i].Token, "transfer", act.Sender(),
|
scr.InvokeWithAssert(recipients[i].Token, "transfer", act.Sender(),
|
||||||
|
|
|
@ -5,13 +5,10 @@ import (
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/cli/cmdargs"
|
"github.com/nspcc-dev/neo-go/cli/cmdargs"
|
||||||
"github.com/nspcc-dev/neo-go/cli/flags"
|
"github.com/nspcc-dev/neo-go/cli/flags"
|
||||||
"github.com/nspcc-dev/neo-go/cli/input"
|
|
||||||
"github.com/nspcc-dev/neo-go/cli/options"
|
"github.com/nspcc-dev/neo-go/cli/options"
|
||||||
"github.com/nspcc-dev/neo-go/cli/txctx"
|
"github.com/nspcc-dev/neo-go/cli/txctx"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/rpcclient/actor"
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/rpcclient/neo"
|
"github.com/nspcc-dev/neo-go/pkg/rpcclient/neo"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
||||||
|
@ -23,7 +20,7 @@ func newValidatorCommands() []cli.Command {
|
||||||
{
|
{
|
||||||
Name: "register",
|
Name: "register",
|
||||||
Usage: "register as a new candidate",
|
Usage: "register as a new candidate",
|
||||||
UsageText: "register -w <path> -r <rpc> -a <addr> [-g gas] [-e sysgas] [--out file] [--force]",
|
UsageText: "register -w <path> -r <rpc> -a <addr> [-g gas] [-e sysgas] [--out file] [--force] [--await]",
|
||||||
Action: handleRegister,
|
Action: handleRegister,
|
||||||
Flags: append([]cli.Flag{
|
Flags: append([]cli.Flag{
|
||||||
walletPathFlag,
|
walletPathFlag,
|
||||||
|
@ -32,6 +29,7 @@ func newValidatorCommands() []cli.Command {
|
||||||
txctx.SysGasFlag,
|
txctx.SysGasFlag,
|
||||||
txctx.OutFlag,
|
txctx.OutFlag,
|
||||||
txctx.ForceFlag,
|
txctx.ForceFlag,
|
||||||
|
txctx.AwaitFlag,
|
||||||
flags.AddressFlag{
|
flags.AddressFlag{
|
||||||
Name: "address, a",
|
Name: "address, a",
|
||||||
Usage: "Address to register",
|
Usage: "Address to register",
|
||||||
|
@ -41,7 +39,7 @@ func newValidatorCommands() []cli.Command {
|
||||||
{
|
{
|
||||||
Name: "unregister",
|
Name: "unregister",
|
||||||
Usage: "unregister self as a candidate",
|
Usage: "unregister self as a candidate",
|
||||||
UsageText: "unregister -w <path> -r <rpc> -a <addr> [-g gas] [-e sysgas] [--out file] [--force]",
|
UsageText: "unregister -w <path> -r <rpc> -a <addr> [-g gas] [-e sysgas] [--out file] [--force] [--await]",
|
||||||
Action: handleUnregister,
|
Action: handleUnregister,
|
||||||
Flags: append([]cli.Flag{
|
Flags: append([]cli.Flag{
|
||||||
walletPathFlag,
|
walletPathFlag,
|
||||||
|
@ -50,6 +48,7 @@ func newValidatorCommands() []cli.Command {
|
||||||
txctx.SysGasFlag,
|
txctx.SysGasFlag,
|
||||||
txctx.OutFlag,
|
txctx.OutFlag,
|
||||||
txctx.ForceFlag,
|
txctx.ForceFlag,
|
||||||
|
txctx.AwaitFlag,
|
||||||
flags.AddressFlag{
|
flags.AddressFlag{
|
||||||
Name: "address, a",
|
Name: "address, a",
|
||||||
Usage: "Address to unregister",
|
Usage: "Address to unregister",
|
||||||
|
@ -59,9 +58,10 @@ func newValidatorCommands() []cli.Command {
|
||||||
{
|
{
|
||||||
Name: "vote",
|
Name: "vote",
|
||||||
Usage: "vote for a validator",
|
Usage: "vote for a validator",
|
||||||
UsageText: "vote -w <path> -r <rpc> [-s <timeout>] [-g gas] [-e sysgas] -a <addr> [-c <public key>] [--out file] [--force]",
|
UsageText: "vote -w <path> -r <rpc> [-s <timeout>] [-g gas] [-e sysgas] -a <addr> [-c <public key>] [--out file] [--force] [--await]",
|
||||||
Description: `Votes for a validator by calling "vote" method of a NEO native
|
Description: `Votes for a validator by calling "vote" method of a NEO native
|
||||||
contract. Do not provide candidate argument to perform unvoting.
|
contract. Do not provide candidate argument to perform unvoting. If --await flag is
|
||||||
|
included, the command waits for the transaction to be included in a block before exiting.
|
||||||
`,
|
`,
|
||||||
Action: handleVote,
|
Action: handleVote,
|
||||||
Flags: append([]cli.Flag{
|
Flags: append([]cli.Flag{
|
||||||
|
@ -71,6 +71,7 @@ func newValidatorCommands() []cli.Command {
|
||||||
txctx.SysGasFlag,
|
txctx.SysGasFlag,
|
||||||
txctx.OutFlag,
|
txctx.OutFlag,
|
||||||
txctx.ForceFlag,
|
txctx.ForceFlag,
|
||||||
|
txctx.AwaitFlag,
|
||||||
flags.AddressFlag{
|
flags.AddressFlag{
|
||||||
Name: "address, a",
|
Name: "address, a",
|
||||||
Usage: "Address to vote from",
|
Usage: "Address to vote from",
|
||||||
|
@ -111,7 +112,7 @@ func handleNeoAction(ctx *cli.Context, mkTx func(*neo.Contract, util.Uint160, *w
|
||||||
return cli.NewExitError("address was not provided", 1)
|
return cli.NewExitError("address was not provided", 1)
|
||||||
}
|
}
|
||||||
addr := addrFlag.Uint160()
|
addr := addrFlag.Uint160()
|
||||||
acc, err := getDecryptedAccount(wall, addr, pass)
|
acc, err := options.GetUnlockedAccount(wall, addr, pass)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.NewExitError(err, 1)
|
||||||
}
|
}
|
||||||
|
@ -119,13 +120,13 @@ func handleNeoAction(ctx *cli.Context, mkTx func(*neo.Contract, util.Uint160, *w
|
||||||
gctx, cancel := options.GetTimeoutContext(ctx)
|
gctx, cancel := options.GetTimeoutContext(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
c, err := options.GetRPCClient(gctx, ctx)
|
signers, err := cmdargs.GetSignersAccounts(acc, wall, nil, transaction.CalledByEntry)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.NewExitError(fmt.Errorf("invalid signers: %w", err), 1)
|
||||||
}
|
}
|
||||||
act, err := actor.NewSimple(c, acc)
|
_, act, exitErr := options.GetRPCWithActor(gctx, ctx, signers)
|
||||||
if err != nil {
|
if exitErr != nil {
|
||||||
return cli.NewExitError(fmt.Errorf("RPC actor issue: %w", err), 1)
|
return exitErr
|
||||||
}
|
}
|
||||||
|
|
||||||
contract := neo.New(act)
|
contract := neo.New(act)
|
||||||
|
@ -153,32 +154,3 @@ func handleVote(ctx *cli.Context) error {
|
||||||
return contract.VoteUnsigned(addr, pub)
|
return contract.VoteUnsigned(addr, pub)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// getDecryptedAccount tries to get and unlock the specified account if it has a
|
|
||||||
// key inside (otherwise it's returned as is, without an ability to sign). If
|
|
||||||
// password is nil, it will be requested via terminal.
|
|
||||||
func getDecryptedAccount(wall *wallet.Wallet, addr util.Uint160, password *string) (*wallet.Account, error) {
|
|
||||||
acc := wall.GetAccount(addr)
|
|
||||||
if acc == nil {
|
|
||||||
return nil, fmt.Errorf("can't find account for the address: %s", address.Uint160ToString(addr))
|
|
||||||
}
|
|
||||||
|
|
||||||
// No private key available, nothing to decrypt, but it's still a useful account for many purposes.
|
|
||||||
if acc.EncryptedWIF == "" {
|
|
||||||
return acc, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if password == nil {
|
|
||||||
pass, err := input.ReadPassword(EnterPasswordPrompt)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println("Error reading password", err)
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
password = &pass
|
|
||||||
}
|
|
||||||
err := acc.Decrypt(*password, wall.Scrypt)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return acc, nil
|
|
||||||
}
|
|
||||||
|
|
|
@ -15,7 +15,6 @@ import (
|
||||||
"github.com/nspcc-dev/neo-go/cli/input"
|
"github.com/nspcc-dev/neo-go/cli/input"
|
||||||
"github.com/nspcc-dev/neo-go/cli/options"
|
"github.com/nspcc-dev/neo-go/cli/options"
|
||||||
"github.com/nspcc-dev/neo-go/cli/txctx"
|
"github.com/nspcc-dev/neo-go/cli/txctx"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/config"
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
|
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
|
||||||
|
@ -26,7 +25,6 @@ import (
|
||||||
"github.com/nspcc-dev/neo-go/pkg/vm"
|
"github.com/nspcc-dev/neo-go/pkg/vm"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
||||||
"github.com/urfave/cli"
|
"github.com/urfave/cli"
|
||||||
"gopkg.in/yaml.v3"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -88,6 +86,7 @@ func NewCommands() []cli.Command {
|
||||||
txctx.SysGasFlag,
|
txctx.SysGasFlag,
|
||||||
txctx.OutFlag,
|
txctx.OutFlag,
|
||||||
txctx.ForceFlag,
|
txctx.ForceFlag,
|
||||||
|
txctx.AwaitFlag,
|
||||||
flags.AddressFlag{
|
flags.AddressFlag{
|
||||||
Name: "address, a",
|
Name: "address, a",
|
||||||
Usage: "Address to claim GAS for",
|
Usage: "Address to claim GAS for",
|
||||||
|
@ -98,6 +97,7 @@ func NewCommands() []cli.Command {
|
||||||
walletPathFlag,
|
walletPathFlag,
|
||||||
walletConfigFlag,
|
walletConfigFlag,
|
||||||
txctx.OutFlag,
|
txctx.OutFlag,
|
||||||
|
txctx.AwaitFlag,
|
||||||
inFlag,
|
inFlag,
|
||||||
flags.AddressFlag{
|
flags.AddressFlag{
|
||||||
Name: "address, a",
|
Name: "address, a",
|
||||||
|
@ -112,7 +112,7 @@ func NewCommands() []cli.Command {
|
||||||
{
|
{
|
||||||
Name: "claim",
|
Name: "claim",
|
||||||
Usage: "claim GAS",
|
Usage: "claim GAS",
|
||||||
UsageText: "neo-go wallet claim -w wallet [--wallet-config path] [-g gas] [-e sysgas] -a address -r endpoint [-s timeout] [--out file] [--force]",
|
UsageText: "neo-go wallet claim -w wallet [--wallet-config path] [-g gas] [-e sysgas] -a address -r endpoint [-s timeout] [--out file] [--force] [--await]",
|
||||||
Action: claimGas,
|
Action: claimGas,
|
||||||
Flags: claimFlags,
|
Flags: claimFlags,
|
||||||
},
|
},
|
||||||
|
@ -236,8 +236,15 @@ func NewCommands() []cli.Command {
|
||||||
{
|
{
|
||||||
Name: "import-multisig",
|
Name: "import-multisig",
|
||||||
Usage: "import multisig contract",
|
Usage: "import multisig contract",
|
||||||
UsageText: "import-multisig -w wallet [--wallet-config path] --wif <wif> [--name <account_name>] --min <n>" +
|
UsageText: "import-multisig -w wallet [--wallet-config path] [--wif <wif>] [--name <account_name>] --min <m>" +
|
||||||
" [<pubkey1> [<pubkey2> [...]]]",
|
" [<pubkey1> [<pubkey2> [...]]]",
|
||||||
|
Description: `Imports a standard multisignature contract with "m out of n" signatures required where "m" is
|
||||||
|
specified by --min flag and "n" is the length of provided set of public keys. If
|
||||||
|
--wif flag is provided, it's used to create an account with the given name (or
|
||||||
|
without a name if --name flag is not provided). Otherwise, the command tries to
|
||||||
|
find an account with one of the given public keys and convert it to multisig. If
|
||||||
|
no suitable account is found and no --wif flag is specified, an error is returned.
|
||||||
|
`,
|
||||||
Action: importMultisig,
|
Action: importMultisig,
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
walletPathFlag,
|
walletPathFlag,
|
||||||
|
@ -290,13 +297,15 @@ func NewCommands() []cli.Command {
|
||||||
{
|
{
|
||||||
Name: "sign",
|
Name: "sign",
|
||||||
Usage: "cosign transaction with multisig/contract/additional account",
|
Usage: "cosign transaction with multisig/contract/additional account",
|
||||||
UsageText: "sign -w wallet [--wallet-config path] --address <address> --in <file.in> [--out <file.out>] [-r <endpoint>]",
|
UsageText: "sign -w wallet [--wallet-config path] --address <address> --in <file.in> [--out <file.out>] [-r <endpoint>] [--await]",
|
||||||
Description: `Signs the given (in file.in) context (which must be a transaction
|
Description: `Signs the given (in file.in) context (which must be a transaction
|
||||||
signing context) for the given address using the given wallet. This command can
|
signing context) for the given address using the given wallet. This command can
|
||||||
output the resulting JSON (with additional signature added) right to the console
|
output the resulting JSON (with additional signature added) right to the console
|
||||||
(if no file.out and no RPC endpoint specified) or into a file (which can be the
|
(if no file.out and no RPC endpoint specified) or into a file (which can be the
|
||||||
same as input one). If an RPC endpoint is given it'll also try to construct a
|
same as input one). If an RPC endpoint is given it'll also try to construct a
|
||||||
complete transaction and send it via RPC (printing its hash if everything is OK).
|
complete transaction and send it via RPC (printing its hash if everything is OK).
|
||||||
|
If the --await (with a given RPC endpoint) flag is included, the command waits
|
||||||
|
for the transaction to be included in a block before exiting.
|
||||||
`,
|
`,
|
||||||
Action: signStoredTransaction,
|
Action: signStoredTransaction,
|
||||||
Flags: signFlags,
|
Flags: signFlags,
|
||||||
|
@ -519,6 +528,12 @@ loop:
|
||||||
}
|
}
|
||||||
|
|
||||||
func importMultisig(ctx *cli.Context) error {
|
func importMultisig(ctx *cli.Context) error {
|
||||||
|
var (
|
||||||
|
label *string
|
||||||
|
acc *wallet.Account
|
||||||
|
accPub *keys.PublicKey
|
||||||
|
)
|
||||||
|
|
||||||
wall, pass, err := openWallet(ctx, true)
|
wall, pass, err := openWallet(ctx, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.NewExitError(err, 1)
|
||||||
|
@ -540,12 +555,45 @@ func importMultisig(ctx *cli.Context) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var label *string
|
|
||||||
if ctx.IsSet("name") {
|
if ctx.IsSet("name") {
|
||||||
l := ctx.String("name")
|
l := ctx.String("name")
|
||||||
label = &l
|
label = &l
|
||||||
}
|
}
|
||||||
acc, err := newAccountFromWIF(ctx.App.Writer, ctx.String("wif"), wall.Scrypt, label, pass)
|
|
||||||
|
loop:
|
||||||
|
for _, pub := range pubs {
|
||||||
|
for _, wallAcc := range wall.Accounts {
|
||||||
|
if wallAcc.ScriptHash().Equals(pub.GetScriptHash()) {
|
||||||
|
if acc != nil {
|
||||||
|
// Multiple matching accounts found, fallback to WIF-based conversion.
|
||||||
|
acc = nil
|
||||||
|
break loop
|
||||||
|
}
|
||||||
|
acc = new(wallet.Account)
|
||||||
|
*acc = *wallAcc
|
||||||
|
accPub = pub
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if acc != nil {
|
||||||
|
err = acc.ConvertMultisigEncrypted(accPub, m, pubs)
|
||||||
|
if err != nil {
|
||||||
|
return cli.NewExitError(err, 1)
|
||||||
|
}
|
||||||
|
if label != nil {
|
||||||
|
acc.Label = *label
|
||||||
|
}
|
||||||
|
if err := addAccountAndSave(wall, acc); err != nil {
|
||||||
|
return cli.NewExitError(err, 1)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if !ctx.IsSet("wif") {
|
||||||
|
return cli.NewExitError(errors.New("none of the provided public keys correspond to an existing key in the wallet or multiple matching accounts found in the wallet, and no WIF is provided"), 1)
|
||||||
|
}
|
||||||
|
acc, err = newAccountFromWIF(ctx.App.Writer, ctx.String("wif"), wall.Scrypt, label, pass)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.NewExitError(err, 1)
|
||||||
}
|
}
|
||||||
|
@ -603,7 +651,8 @@ func importDeployed(ctx *cli.Context) error {
|
||||||
return cli.NewExitError("contract has no `verify` method with boolean return", 1)
|
return cli.NewExitError("contract has no `verify` method with boolean return", 1)
|
||||||
}
|
}
|
||||||
acc.Address = address.Uint160ToString(cs.Hash)
|
acc.Address = address.Uint160ToString(cs.Hash)
|
||||||
acc.Contract.Script = cs.NEF.Script
|
// Explicitly overwrite single signature script of the provided WIF since the contract is known to be deployed.
|
||||||
|
acc.Contract.Script = nil
|
||||||
acc.Contract.Parameters = acc.Contract.Parameters[:0]
|
acc.Contract.Parameters = acc.Contract.Parameters[:0]
|
||||||
for _, p := range md.Parameters {
|
for _, p := range md.Parameters {
|
||||||
acc.Contract.Parameters = append(acc.Contract.Parameters, wallet.ContractParam{
|
acc.Contract.Parameters = append(acc.Contract.Parameters, wallet.ContractParam{
|
||||||
|
@ -822,7 +871,7 @@ func createWallet(ctx *cli.Context) error {
|
||||||
}
|
}
|
||||||
var pass *string
|
var pass *string
|
||||||
if len(configPath) != 0 {
|
if len(configPath) != 0 {
|
||||||
cfg, err := ReadWalletConfig(configPath)
|
cfg, err := options.ReadWalletConfig(configPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.NewExitError(err, 1)
|
||||||
}
|
}
|
||||||
|
@ -900,14 +949,14 @@ func createAccount(wall *wallet.Wallet, pass *string) error {
|
||||||
func openWallet(ctx *cli.Context, canUseWalletConfig bool) (*wallet.Wallet, *string, error) {
|
func openWallet(ctx *cli.Context, canUseWalletConfig bool) (*wallet.Wallet, *string, error) {
|
||||||
path, pass, err := getWalletPathAndPass(ctx, canUseWalletConfig)
|
path, pass, err := getWalletPathAndPass(ctx, canUseWalletConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, cli.NewExitError(fmt.Errorf("failed to get wallet path or password: %w", err), 1)
|
||||||
}
|
}
|
||||||
if path == "-" {
|
if path == "-" {
|
||||||
return nil, nil, errNoStdin
|
return nil, nil, errNoStdin
|
||||||
}
|
}
|
||||||
w, err := wallet.NewWalletFromFile(path)
|
w, err := wallet.NewWalletFromFile(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, cli.NewExitError(fmt.Errorf("failed to read wallet: %w", err), 1)
|
||||||
}
|
}
|
||||||
return w, pass, nil
|
return w, pass, nil
|
||||||
}
|
}
|
||||||
|
@ -946,7 +995,7 @@ func getWalletPathAndPass(ctx *cli.Context, canUseWalletConfig bool) (string, *s
|
||||||
}
|
}
|
||||||
var pass *string
|
var pass *string
|
||||||
if len(configPath) != 0 {
|
if len(configPath) != 0 {
|
||||||
cfg, err := ReadWalletConfig(configPath)
|
cfg, err := options.ReadWalletConfig(configPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", nil, err
|
return "", nil, err
|
||||||
}
|
}
|
||||||
|
@ -956,27 +1005,6 @@ func getWalletPathAndPass(ctx *cli.Context, canUseWalletConfig bool) (string, *s
|
||||||
return path, pass, nil
|
return path, pass, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func ReadWalletConfig(configPath string) (*config.Wallet, error) {
|
|
||||||
file, err := os.Open(configPath)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
defer file.Close()
|
|
||||||
|
|
||||||
configData, err := os.ReadFile(configPath)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("unable to read wallet config: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
cfg := &config.Wallet{}
|
|
||||||
|
|
||||||
err = yaml.Unmarshal(configData, &cfg)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to unmarshal wallet config YAML: %w", err)
|
|
||||||
}
|
|
||||||
return cfg, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func newAccountFromWIF(w io.Writer, wif string, scrypt keys.ScryptParams, label *string, pass *string) (*wallet.Account, error) {
|
func newAccountFromWIF(w io.Writer, wif string, scrypt keys.ScryptParams, label *string, pass *string) (*wallet.Account, error) {
|
||||||
var (
|
var (
|
||||||
phrase, name string
|
phrase, name string
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package wallet_test
|
package wallet_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/hex"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"math/big"
|
"math/big"
|
||||||
"os"
|
"os"
|
||||||
|
@ -437,16 +436,16 @@ func TestWalletInit(t *testing.T) {
|
||||||
"--wallet", walletPath,
|
"--wallet", walletPath,
|
||||||
"--min", "2"}
|
"--min", "2"}
|
||||||
t.Run("invalid pub encoding", func(t *testing.T) {
|
t.Run("invalid pub encoding", func(t *testing.T) {
|
||||||
e.RunWithError(t, append(cmd, hex.EncodeToString(pubs[1].Bytes()),
|
e.RunWithError(t, append(cmd, pubs[1].StringCompressed(),
|
||||||
hex.EncodeToString(pubs[1].Bytes()),
|
pubs[1].StringCompressed(),
|
||||||
hex.EncodeToString(pubs[2].Bytes()),
|
pubs[2].StringCompressed(),
|
||||||
"not-a-pub")...)
|
"not-a-pub")...)
|
||||||
})
|
})
|
||||||
t.Run("missing WIF", func(t *testing.T) {
|
t.Run("missing WIF", func(t *testing.T) {
|
||||||
e.RunWithError(t, append(cmd, hex.EncodeToString(pubs[0].Bytes()),
|
e.RunWithError(t, append(cmd, pubs[0].StringCompressed(),
|
||||||
hex.EncodeToString(pubs[1].Bytes()),
|
pubs[1].StringCompressed(),
|
||||||
hex.EncodeToString(pubs[2].Bytes()),
|
pubs[2].StringCompressed(),
|
||||||
hex.EncodeToString(pubs[3].Bytes()))...)
|
pubs[3].StringCompressed())...)
|
||||||
})
|
})
|
||||||
cmd = append(cmd, "--wif", privs[0].WIF())
|
cmd = append(cmd, "--wif", privs[0].WIF())
|
||||||
t.Run("InvalidPublicKeys", func(t *testing.T) {
|
t.Run("InvalidPublicKeys", func(t *testing.T) {
|
||||||
|
@ -455,18 +454,18 @@ func TestWalletInit(t *testing.T) {
|
||||||
e.In.WriteString("multipass\r")
|
e.In.WriteString("multipass\r")
|
||||||
defer e.In.Reset()
|
defer e.In.Reset()
|
||||||
|
|
||||||
e.RunWithError(t, append(cmd, hex.EncodeToString(pubs[1].Bytes()),
|
e.RunWithError(t, append(cmd, pubs[1].StringCompressed(),
|
||||||
hex.EncodeToString(pubs[1].Bytes()),
|
pubs[1].StringCompressed(),
|
||||||
hex.EncodeToString(pubs[2].Bytes()),
|
pubs[2].StringCompressed(),
|
||||||
hex.EncodeToString(pubs[3].Bytes()))...)
|
pubs[3].StringCompressed())...)
|
||||||
})
|
})
|
||||||
e.In.WriteString("multiacc\r")
|
e.In.WriteString("multiacc\r")
|
||||||
e.In.WriteString("multipass\r")
|
e.In.WriteString("multipass\r")
|
||||||
e.In.WriteString("multipass\r")
|
e.In.WriteString("multipass\r")
|
||||||
e.Run(t, append(cmd, hex.EncodeToString(pubs[0].Bytes()),
|
e.Run(t, append(cmd, pubs[0].StringCompressed(),
|
||||||
hex.EncodeToString(pubs[1].Bytes()),
|
pubs[1].StringCompressed(),
|
||||||
hex.EncodeToString(pubs[2].Bytes()),
|
pubs[2].StringCompressed(),
|
||||||
hex.EncodeToString(pubs[3].Bytes()))...)
|
pubs[3].StringCompressed())...)
|
||||||
|
|
||||||
script, err := smartcontract.CreateMultiSigRedeemScript(2, pubs)
|
script, err := smartcontract.CreateMultiSigRedeemScript(2, pubs)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
@ -482,10 +481,62 @@ func TestWalletInit(t *testing.T) {
|
||||||
e.In.WriteString("multiacc\r")
|
e.In.WriteString("multiacc\r")
|
||||||
e.In.WriteString("multipass\r")
|
e.In.WriteString("multipass\r")
|
||||||
e.In.WriteString("multipass\r")
|
e.In.WriteString("multipass\r")
|
||||||
e.RunWithError(t, append(cmd, hex.EncodeToString(pubs[0].Bytes()),
|
e.RunWithError(t, append(cmd, pubs[0].StringCompressed(),
|
||||||
hex.EncodeToString(pubs[1].Bytes()),
|
pubs[1].StringCompressed(),
|
||||||
hex.EncodeToString(pubs[2].Bytes()),
|
pubs[2].StringCompressed(),
|
||||||
hex.EncodeToString(pubs[3].Bytes()))...)
|
pubs[3].StringCompressed())...)
|
||||||
|
})
|
||||||
|
|
||||||
|
privs, pubs = testcli.GenerateKeys(t, 3)
|
||||||
|
script, err = smartcontract.CreateMultiSigRedeemScript(2, pubs)
|
||||||
|
require.NoError(t, err)
|
||||||
|
// Create a wallet and import a standard account
|
||||||
|
e.Run(t, "neo-go", "wallet", "init", "--wallet", walletPath)
|
||||||
|
e.In.WriteString("standardacc\rstdpass\rstdpass\r")
|
||||||
|
e.Run(t, "neo-go", "wallet", "import",
|
||||||
|
"--wallet", walletPath,
|
||||||
|
"--wif", privs[0].WIF())
|
||||||
|
w, err = wallet.NewWalletFromFile(walletPath)
|
||||||
|
require.NoError(t, err)
|
||||||
|
actual = w.GetAccount(privs[0].GetScriptHash())
|
||||||
|
require.NotNil(t, actual)
|
||||||
|
require.NotEqual(t, actual.Contract.Script, script)
|
||||||
|
|
||||||
|
// Test when a public key of an already imported account is present
|
||||||
|
t.Run("existing account public key, no WIF", func(t *testing.T) {
|
||||||
|
e.Run(t, "neo-go", "wallet", "import-multisig",
|
||||||
|
"--wallet", walletPath,
|
||||||
|
"--min", "2",
|
||||||
|
pubs[0].StringCompressed(), // Public key of the already imported account
|
||||||
|
pubs[1].StringCompressed(),
|
||||||
|
pubs[2].StringCompressed())
|
||||||
|
|
||||||
|
w, err := wallet.NewWalletFromFile(walletPath)
|
||||||
|
require.NoError(t, err)
|
||||||
|
actual := w.GetAccount(hash.Hash160(script))
|
||||||
|
require.NotNil(t, actual)
|
||||||
|
require.Equal(t, actual.Contract.Script, script)
|
||||||
|
require.NoError(t, actual.Decrypt("stdpass", w.Scrypt))
|
||||||
|
require.NotEqual(t, actual.Address, w.GetAccount(privs[0].GetScriptHash()).Address)
|
||||||
|
})
|
||||||
|
|
||||||
|
// Test when no public key of an already imported account is present, and no WIF is provided
|
||||||
|
t.Run("no existing account public key, no WIF", func(t *testing.T) {
|
||||||
|
_, pubsNew := testcli.GenerateKeys(t, 3)
|
||||||
|
scriptNew, err := smartcontract.CreateMultiSigRedeemScript(2, pubsNew)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
e.RunWithError(t, "neo-go", "wallet", "import-multisig",
|
||||||
|
"--wallet", walletPath,
|
||||||
|
"--min", "2",
|
||||||
|
pubsNew[0].StringCompressed(),
|
||||||
|
pubsNew[1].StringCompressed(),
|
||||||
|
pubsNew[2].StringCompressed())
|
||||||
|
|
||||||
|
w, err := wallet.NewWalletFromFile(walletPath)
|
||||||
|
require.NoError(t, err)
|
||||||
|
actual := w.GetAccount(hash.Hash160(scriptNew))
|
||||||
|
require.Nil(t, actual)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -605,6 +656,47 @@ func TestWalletClaimGas(t *testing.T) {
|
||||||
} else {
|
} else {
|
||||||
require.Equal(t, 1, balanceAfter.Cmp(balanceBefore))
|
require.Equal(t, 1, balanceAfter.Cmp(balanceBefore))
|
||||||
}
|
}
|
||||||
|
t.Run("await", func(t *testing.T) {
|
||||||
|
args := []string{
|
||||||
|
"neo-go", "wallet", "nep17", "multitransfer",
|
||||||
|
"--rpc-endpoint", "http://" + e.RPC.Addresses()[0],
|
||||||
|
"--wallet", testcli.ValidatorWallet,
|
||||||
|
"--from", testcli.ValidatorAddr, "--await",
|
||||||
|
"--force",
|
||||||
|
"NEO:" + testcli.TestWalletAccount + ":1000",
|
||||||
|
"GAS:" + testcli.TestWalletAccount + ":1000", // for tx send
|
||||||
|
}
|
||||||
|
e.In.WriteString("one\r")
|
||||||
|
e.Run(t, args...)
|
||||||
|
e.CheckAwaitableTxPersisted(t)
|
||||||
|
|
||||||
|
h, err := address.StringToUint160(testcli.TestWalletAccount)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
balanceBefore := e.Chain.GetUtilityTokenBalance(h)
|
||||||
|
claimHeight := e.Chain.BlockHeight() + 1
|
||||||
|
cl, err := e.Chain.CalculateClaimable(h, claimHeight)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.True(t, cl.Sign() > 0)
|
||||||
|
|
||||||
|
e.In.WriteString("testpass\r")
|
||||||
|
e.Run(t, "neo-go", "wallet", "claim",
|
||||||
|
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
|
||||||
|
"--wallet", testcli.TestWalletPath,
|
||||||
|
"--address", testcli.TestWalletAccount,
|
||||||
|
"--force", "--await")
|
||||||
|
tx, height = e.CheckAwaitableTxPersisted(t)
|
||||||
|
balanceBefore.Sub(balanceBefore, big.NewInt(tx.NetworkFee+tx.SystemFee))
|
||||||
|
balanceBefore.Add(balanceBefore, cl)
|
||||||
|
|
||||||
|
balanceAfter = e.Chain.GetUtilityTokenBalance(h)
|
||||||
|
// height can be bigger than claimHeight especially when tests are executed with -race.
|
||||||
|
if height == claimHeight {
|
||||||
|
require.Equal(t, 0, balanceAfter.Cmp(balanceBefore))
|
||||||
|
} else {
|
||||||
|
require.Equal(t, 1, balanceAfter.Cmp(balanceBefore))
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestWalletImportDeployed(t *testing.T) {
|
func TestWalletImportDeployed(t *testing.T) {
|
||||||
|
@ -822,6 +914,31 @@ func TestOfflineSigning(t *testing.T) {
|
||||||
"--in", txPath)
|
"--in", txPath)
|
||||||
})
|
})
|
||||||
e.CheckTxPersisted(t)
|
e.CheckTxPersisted(t)
|
||||||
|
|
||||||
|
t.Run("await 1/1 multisig", func(t *testing.T) {
|
||||||
|
args := []string{"neo-go", "wallet", "nep17", "transfer",
|
||||||
|
"--rpc-endpoint", "http://" + e.RPC.Addresses()[0],
|
||||||
|
"--wallet", walletPath,
|
||||||
|
"--from", testcli.ValidatorAddr,
|
||||||
|
"--to", w.Accounts[0].Address,
|
||||||
|
"--token", "NEO",
|
||||||
|
"--amount", "1",
|
||||||
|
"--force",
|
||||||
|
}
|
||||||
|
e.Run(t, append(args, "--out", txPath)...)
|
||||||
|
|
||||||
|
e.In.WriteString("one\r")
|
||||||
|
e.Run(t, "neo-go", "wallet", "sign",
|
||||||
|
"--wallet", testcli.ValidatorWallet, "--address", testcli.ValidatorAddr,
|
||||||
|
"--in", txPath, "--out", txPath)
|
||||||
|
|
||||||
|
e.Run(t, "neo-go", "wallet", "sign",
|
||||||
|
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
|
||||||
|
"--wallet", walletPath, "--address", testcli.ValidatorAddr,
|
||||||
|
"--in", txPath, "--await")
|
||||||
|
e.CheckAwaitableTxPersisted(t)
|
||||||
|
})
|
||||||
|
|
||||||
t.Run("simple signature", func(t *testing.T) {
|
t.Run("simple signature", func(t *testing.T) {
|
||||||
simpleAddr := w.Accounts[0].Address
|
simpleAddr := w.Accounts[0].Address
|
||||||
args := []string{"neo-go", "wallet", "nep17", "transfer",
|
args := []string{"neo-go", "wallet", "nep17", "transfer",
|
||||||
|
@ -853,6 +970,31 @@ func TestOfflineSigning(t *testing.T) {
|
||||||
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
|
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
|
||||||
txPath)
|
txPath)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("await simple signature", func(t *testing.T) {
|
||||||
|
simpleAddr := w.Accounts[0].Address
|
||||||
|
args := []string{"neo-go", "wallet", "nep17", "transfer",
|
||||||
|
"--rpc-endpoint", "http://" + e.RPC.Addresses()[0],
|
||||||
|
"--wallet", walletPath,
|
||||||
|
"--from", simpleAddr,
|
||||||
|
"--to", testcli.ValidatorAddr,
|
||||||
|
"--token", "NEO",
|
||||||
|
"--amount", "1",
|
||||||
|
"--force",
|
||||||
|
}
|
||||||
|
|
||||||
|
e.Run(t, append(args, "--out", txPath)...)
|
||||||
|
|
||||||
|
e.In.WriteString("one\r")
|
||||||
|
e.Run(t, "neo-go", "wallet", "sign",
|
||||||
|
"--wallet", testcli.ValidatorWallet, "--address", simpleAddr,
|
||||||
|
"--in", txPath, "--out", txPath)
|
||||||
|
|
||||||
|
e.Run(t, "neo-go", "util", "sendtx",
|
||||||
|
"--rpc-endpoint", "http://"+e.RPC.Addresses()[0],
|
||||||
|
txPath, "--await")
|
||||||
|
e.CheckAwaitableTxPersisted(t)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestWalletDump(t *testing.T) {
|
func TestWalletDump(t *testing.T) {
|
||||||
|
|
|
@ -22,19 +22,11 @@ ProtocolConfiguration:
|
||||||
- morph6.fs.neo.org:40333
|
- morph6.fs.neo.org:40333
|
||||||
- morph7.fs.neo.org:40333
|
- morph7.fs.neo.org:40333
|
||||||
VerifyTransactions: true
|
VerifyTransactions: true
|
||||||
P2PSigExtensions: false
|
P2PSigExtensions: true
|
||||||
Hardforks:
|
Hardforks:
|
||||||
Aspidochelone: 3000000
|
Aspidochelone: 3000000
|
||||||
NativeActivations:
|
Basilisk: 4500000
|
||||||
ContractManagement: [0]
|
Cockatrice: 5800000
|
||||||
StdLib: [0]
|
|
||||||
CryptoLib: [0]
|
|
||||||
LedgerContract: [0]
|
|
||||||
NeoToken: [0]
|
|
||||||
GasToken: [0]
|
|
||||||
PolicyContract: [0]
|
|
||||||
RoleManagement: [0]
|
|
||||||
OracleContract: [0]
|
|
||||||
|
|
||||||
ApplicationConfiguration:
|
ApplicationConfiguration:
|
||||||
SkipBlockVerification: false
|
SkipBlockVerification: false
|
||||||
|
|
|
@ -37,16 +37,8 @@ ProtocolConfiguration:
|
||||||
P2PSigExtensions: false
|
P2PSigExtensions: false
|
||||||
Hardforks:
|
Hardforks:
|
||||||
Aspidochelone: 1730000
|
Aspidochelone: 1730000
|
||||||
NativeActivations:
|
Basilisk: 4120000
|
||||||
ContractManagement: [0]
|
Cockatrice: 5450000
|
||||||
StdLib: [0]
|
|
||||||
CryptoLib: [0]
|
|
||||||
LedgerContract: [0]
|
|
||||||
NeoToken: [0]
|
|
||||||
GasToken: [0]
|
|
||||||
PolicyContract: [0]
|
|
||||||
RoleManagement: [0]
|
|
||||||
OracleContract: [0]
|
|
||||||
|
|
||||||
ApplicationConfiguration:
|
ApplicationConfiguration:
|
||||||
SkipBlockVerification: false
|
SkipBlockVerification: false
|
||||||
|
|
|
@ -16,16 +16,6 @@ ProtocolConfiguration:
|
||||||
- node_four:20336
|
- node_four:20336
|
||||||
VerifyTransactions: true
|
VerifyTransactions: true
|
||||||
P2PSigExtensions: false
|
P2PSigExtensions: false
|
||||||
NativeActivations:
|
|
||||||
ContractManagement: [0]
|
|
||||||
StdLib: [0]
|
|
||||||
CryptoLib: [0]
|
|
||||||
LedgerContract: [0]
|
|
||||||
NeoToken: [0]
|
|
||||||
GasToken: [0]
|
|
||||||
PolicyContract: [0]
|
|
||||||
RoleManagement: [0]
|
|
||||||
OracleContract: [0]
|
|
||||||
|
|
||||||
ApplicationConfiguration:
|
ApplicationConfiguration:
|
||||||
SkipBlockVerification: false
|
SkipBlockVerification: false
|
||||||
|
@ -73,6 +63,7 @@ ApplicationConfiguration:
|
||||||
- ":30336"
|
- ":30336"
|
||||||
MaxGasInvoke: 15
|
MaxGasInvoke: 15
|
||||||
EnableCORSWorkaround: false
|
EnableCORSWorkaround: false
|
||||||
|
SessionEnabled: true
|
||||||
Prometheus:
|
Prometheus:
|
||||||
Enabled: true
|
Enabled: true
|
||||||
Addresses:
|
Addresses:
|
||||||
|
|
|
@ -16,16 +16,6 @@ ProtocolConfiguration:
|
||||||
- node_four:20336
|
- node_four:20336
|
||||||
VerifyTransactions: true
|
VerifyTransactions: true
|
||||||
P2PSigExtensions: false
|
P2PSigExtensions: false
|
||||||
NativeActivations:
|
|
||||||
ContractManagement: [0]
|
|
||||||
StdLib: [0]
|
|
||||||
CryptoLib: [0]
|
|
||||||
LedgerContract: [0]
|
|
||||||
NeoToken: [0]
|
|
||||||
GasToken: [0]
|
|
||||||
PolicyContract: [0]
|
|
||||||
RoleManagement: [0]
|
|
||||||
OracleContract: [0]
|
|
||||||
|
|
||||||
ApplicationConfiguration:
|
ApplicationConfiguration:
|
||||||
SkipBlockVerification: false
|
SkipBlockVerification: false
|
||||||
|
@ -73,13 +63,15 @@ ApplicationConfiguration:
|
||||||
- ":30333"
|
- ":30333"
|
||||||
MaxGasInvoke: 15
|
MaxGasInvoke: 15
|
||||||
EnableCORSWorkaround: false
|
EnableCORSWorkaround: false
|
||||||
|
SessionEnabled: true
|
||||||
Prometheus:
|
Prometheus:
|
||||||
Enabled: true
|
Enabled: true
|
||||||
Addresses:
|
Addresses:
|
||||||
- ":20001"
|
- ":20001"
|
||||||
Pprof:
|
Pprof:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
Port: 20011
|
Addresses:
|
||||||
|
- ":20011"
|
||||||
Consensus:
|
Consensus:
|
||||||
Enabled: true
|
Enabled: true
|
||||||
UnlockWallet:
|
UnlockWallet:
|
||||||
|
|
|
@ -10,16 +10,6 @@ ProtocolConfiguration:
|
||||||
- node_single:20333
|
- node_single:20333
|
||||||
VerifyTransactions: true
|
VerifyTransactions: true
|
||||||
P2PSigExtensions: false
|
P2PSigExtensions: false
|
||||||
NativeActivations:
|
|
||||||
ContractManagement: [0]
|
|
||||||
StdLib: [0]
|
|
||||||
CryptoLib: [0]
|
|
||||||
LedgerContract: [0]
|
|
||||||
NeoToken: [0]
|
|
||||||
GasToken: [0]
|
|
||||||
PolicyContract: [0]
|
|
||||||
RoleManagement: [0]
|
|
||||||
OracleContract: [0]
|
|
||||||
|
|
||||||
ApplicationConfiguration:
|
ApplicationConfiguration:
|
||||||
SkipBlockVerification: false
|
SkipBlockVerification: false
|
||||||
|
@ -64,6 +54,7 @@ ApplicationConfiguration:
|
||||||
- ":30333"
|
- ":30333"
|
||||||
EnableCORSWorkaround: false
|
EnableCORSWorkaround: false
|
||||||
MaxGasInvoke: 15
|
MaxGasInvoke: 15
|
||||||
|
SessionEnabled: true
|
||||||
Prometheus:
|
Prometheus:
|
||||||
Enabled: true
|
Enabled: true
|
||||||
Addresses:
|
Addresses:
|
||||||
|
|
|
@ -16,16 +16,6 @@ ProtocolConfiguration:
|
||||||
- node_four:20336
|
- node_four:20336
|
||||||
VerifyTransactions: true
|
VerifyTransactions: true
|
||||||
P2PSigExtensions: false
|
P2PSigExtensions: false
|
||||||
NativeActivations:
|
|
||||||
ContractManagement: [0]
|
|
||||||
StdLib: [0]
|
|
||||||
CryptoLib: [0]
|
|
||||||
LedgerContract: [0]
|
|
||||||
NeoToken: [0]
|
|
||||||
GasToken: [0]
|
|
||||||
PolicyContract: [0]
|
|
||||||
RoleManagement: [0]
|
|
||||||
OracleContract: [0]
|
|
||||||
|
|
||||||
ApplicationConfiguration:
|
ApplicationConfiguration:
|
||||||
SkipBlockVerification: false
|
SkipBlockVerification: false
|
||||||
|
@ -73,6 +63,7 @@ ApplicationConfiguration:
|
||||||
- ":30335"
|
- ":30335"
|
||||||
MaxGasInvoke: 15
|
MaxGasInvoke: 15
|
||||||
EnableCORSWorkaround: false
|
EnableCORSWorkaround: false
|
||||||
|
SessionEnabled: true
|
||||||
Prometheus:
|
Prometheus:
|
||||||
Enabled: true
|
Enabled: true
|
||||||
Addresses:
|
Addresses:
|
||||||
|
|
|
@ -16,16 +16,6 @@ ProtocolConfiguration:
|
||||||
- node_four:20336
|
- node_four:20336
|
||||||
VerifyTransactions: true
|
VerifyTransactions: true
|
||||||
P2PSigExtensions: false
|
P2PSigExtensions: false
|
||||||
NativeActivations:
|
|
||||||
ContractManagement: [0]
|
|
||||||
StdLib: [0]
|
|
||||||
CryptoLib: [0]
|
|
||||||
LedgerContract: [0]
|
|
||||||
NeoToken: [0]
|
|
||||||
GasToken: [0]
|
|
||||||
PolicyContract: [0]
|
|
||||||
RoleManagement: [0]
|
|
||||||
OracleContract: [0]
|
|
||||||
|
|
||||||
ApplicationConfiguration:
|
ApplicationConfiguration:
|
||||||
SkipBlockVerification: false
|
SkipBlockVerification: false
|
||||||
|
@ -73,6 +63,7 @@ ApplicationConfiguration:
|
||||||
EnableCORSWorkaround: false
|
EnableCORSWorkaround: false
|
||||||
Addresses:
|
Addresses:
|
||||||
- ":30334"
|
- ":30334"
|
||||||
|
SessionEnabled: true
|
||||||
Prometheus:
|
Prometheus:
|
||||||
Enabled: true
|
Enabled: true
|
||||||
Addresses:
|
Addresses:
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue