Compare commits
980 Commits
v0.7.10-br
...
v0.8.4
Author | SHA1 | Date | |
---|---|---|---|
bba7ccb07f | |||
cb7cd03919 | |||
bc541b918c | |||
3c14902649 | |||
92337baa5a | |||
f9663b8f4f | |||
113cf4208b | |||
703dc8299c | |||
bd7ebbcd5b | |||
d586a633ff | |||
9feb657763 | |||
cc43ab9a81 | |||
66d5559866 | |||
82cae27737 | |||
75625801f5 | |||
ea9a549bbd | |||
5c975dd4ed | |||
d8ac267f41 | |||
63031f571a | |||
982f73fa6d | |||
3b12a9293c | |||
654f7f707c | |||
66abe2e3d4 | |||
b3b6210886 | |||
01ce066d43 | |||
4ab7a290cd | |||
81dea2d8e7 | |||
0006585391 | |||
639ac5c3da | |||
765740b829 | |||
07c34751da | |||
fa4cbad315 | |||
a59cd94625 | |||
605dd3a982 | |||
3719db352a | |||
fa15854a54 | |||
dd871e791c | |||
3dbd32093c | |||
1ec6190e86 | |||
73f94f3755 | |||
c14071df9d | |||
dba4f3122e | |||
4322632c59 | |||
0057bb4ef6 | |||
03b8c6841b | |||
fdecc11128 | |||
5aff8bfb59 | |||
487c5cc294 | |||
ee9df32dba | |||
655e942597 | |||
be90ad89a8 | |||
05b1ec008b | |||
07bdba687f | |||
f499f343ba | |||
acd93c2971 | |||
60318c96d0 | |||
c1d0693cb1 | |||
5ec8c5f71b | |||
c1474e1877 | |||
26d58e0446 | |||
7fc9b5b3f9 | |||
0e2f6691bf | |||
11e12680eb | |||
13c00afc68 | |||
5022b618aa | |||
5238b9439e | |||
9a2be227a6 | |||
fe94622ea3 | |||
567428fb34 | |||
815ead7107 | |||
7ea131d4ff | |||
547788b1b0 | |||
417f018498 | |||
2c454863f2 | |||
f965f41b6e | |||
119bea22aa | |||
bb346a3ae1 | |||
abb9b7f46f | |||
c934222a80 | |||
8135752a32 | |||
34d0e1b2c3 | |||
fbd5e4d5af | |||
0de1d1dd58 | |||
a22711a7b5 | |||
c4b8c11529 | |||
666ef48239 | |||
643eda5c2d | |||
cb34502728 | |||
9796feccb7 | |||
c0ce323092 | |||
3068e2688d | |||
68f6ddc5aa | |||
1878630b59 | |||
702218008e | |||
202362d925 | |||
393267489c | |||
a92bcbb795 | |||
164de5e22b | |||
8f69b5c7a2 | |||
d68e607aa5 | |||
d2a4bc4d73 | |||
f63c4a9bcb | |||
05f2808849 | |||
2c3a014f03 | |||
c924a841c7 | |||
7299eb72e0 | |||
238f39a42e | |||
09e53367a2 | |||
b143dad596 | |||
16ae675107 | |||
12fc590b34 | |||
c29b01ce75 | |||
befb4bc1c1 | |||
32c7ebc51d | |||
65159d65c8 | |||
3ff6c9bb79 | |||
84f7c966f7 | |||
8464e43eaf | |||
4bef3ce284 | |||
396f1a0a33 | |||
7c0f4a9b18 | |||
49a739c8d6 | |||
12b2d57629 | |||
95cfaa1b37 | |||
acc7c0f706 | |||
1c1a3033be | |||
384305f4aa | |||
7aef0fed29 | |||
4d49d7b5a6 | |||
f35d62b759 | |||
6a7b0ef904 | |||
ce239333d5 | |||
0f3c25b265 | |||
790de35e7f | |||
218f437b0c | |||
7336dfad02 | |||
00fca40939 | |||
8a0f23915e | |||
8305d409d2 | |||
5c251b6928 | |||
bde3ff16ad | |||
39434e383b | |||
76fa75b394 | |||
32a9c0ca80 | |||
fd3e1061e0 | |||
cf754b9483 | |||
5cc1256fd6 | |||
7101f44998 | |||
22ee366ed6 | |||
75d164037f | |||
a5ea21cd85 | |||
5110f80bba | |||
170eb3ac68 | |||
82f0bd9009 | |||
d0a2e655c9 | |||
1543833ca0 | |||
38faf2c51a | |||
31fdc645ed | |||
5136fc9ab7 | |||
04c1a81509 | |||
b64ad7a2a6 | |||
3f6baa45a7 | |||
52a46e61f9 | |||
558c67d392 | |||
d73dff4d5b | |||
b94f85de22 | |||
1fc3524e40 | |||
ebc506dae8 | |||
6221b282d4 | |||
db24fb792c | |||
d311b1b9b7 | |||
3c40eb9e5a | |||
df49c609a0 | |||
3d6fd601c5 | |||
ef6c7bd726 | |||
d613bf69bf | |||
cfddb7f3cd | |||
c6af5f0a27 | |||
e433525f51 | |||
ab66a3d0d3 | |||
8c056aebe1 | |||
d53e5646ec | |||
5fe2916ee1 | |||
acc667fbef | |||
80890cd9dd | |||
6b5f4ed244 | |||
4242b05462 | |||
a21b30c901 | |||
ddccea75e8 | |||
da2fae0e43 | |||
a3cd218719 | |||
0c7df37351 | |||
70e2df3904 | |||
f1ebad2508 | |||
9915d3c3be | |||
58ba290a9f | |||
b22f0f2ef5 | |||
16a04e64f2 | |||
c8147fb7b9 | |||
0fa6927171 | |||
99ebb869bf | |||
44eafb15e0 | |||
792cd0aa10 | |||
028775a086 | |||
2cf4fed11b | |||
e34d134102 | |||
8564eb9f7e | |||
e4bb419707 | |||
5e0b2b260c | |||
b58b6b9bac | |||
f3ac378ca4 | |||
56f777b2fc | |||
e40c1c62ce | |||
8e8ec8f5f8 | |||
5bdc115943 | |||
739066ec56 | |||
12224c7f59 | |||
8c3095faf0 | |||
410b35e913 | |||
2e48d39fc7 | |||
488a042736 | |||
71765957e4 | |||
68205dec9f | |||
4499743522 | |||
54252ede31 | |||
faa069a126 | |||
20aade56c3 | |||
1f2adb05b5 | |||
4afde4e738 | |||
364b783281 | |||
58fc2c679b | |||
923504ce3d | |||
2e868566d7 | |||
e252c634cb | |||
1803c65e40 | |||
489d956283 | |||
076c382a74 | |||
3b6385b146 | |||
714b955d6e | |||
b855f671a5 | |||
4e52adb84a | |||
d227f6184e | |||
88167f39a6 | |||
c8a8aa0d43 | |||
6b5f25802e | |||
f8c1eb157d | |||
59665ade85 | |||
c1f6e259a9 | |||
03b89ab712 | |||
ae3e9d4881 | |||
cad53fa191 | |||
0e682d936d | |||
cec30e23b2 | |||
47129428fe | |||
2f30a27b2b | |||
8be1d134aa | |||
7e0799ff21 | |||
9d84609b3f | |||
c64852dbcc | |||
bcacaaa4f4 | |||
d00e2731e5 | |||
99a1551b20 | |||
ac69538707 | |||
82cc5f63ae | |||
9d2166a964 | |||
db7c34a9df | |||
a1b4547a53 | |||
57f95c1dc7 | |||
1d519854e2 | |||
292f7ada8e | |||
65158d39b0 | |||
7c278d6ac2 | |||
429077a5a0 | |||
2656a2d038 | |||
3f03197dae | |||
b1870631a4 | |||
859a1999cb | |||
f3e1797153 | |||
55ed0ff07c | |||
07590196a5 | |||
697c2b5dc1 | |||
a0cfa3ca21 | |||
e58e2f5ee4 | |||
45134de740 | |||
f3ce1f07c4 | |||
ddc17196da | |||
fdcc1af4e2 | |||
4a54b8c451 | |||
4dc283c0fb | |||
f1a5cf9128 | |||
a5909d82eb | |||
59b7386abb | |||
7bd2fbe2b1 | |||
623469cb6c | |||
663d725026 | |||
1860b3dff9 | |||
03faec9d41 | |||
30fa30bd4a | |||
faa54e59c1 | |||
93ae7bb0d2 | |||
3c7181d28f | |||
6fecb150d6 | |||
1f4ed49b4c | |||
57c6caf146 | |||
4bb5ba78b0 | |||
9d9c23e315 | |||
1a6b7de0af | |||
b2b42f759c | |||
7139c1aff7 | |||
1e60919d47 | |||
011fdd91df | |||
0994efa66f | |||
8ccde784f9 | |||
d52878c744 | |||
d5166918e9 | |||
0d97c3ce13 | |||
19cff8ecca | |||
bb2e847363 | |||
a008c21cf0 | |||
9016ce8dd8 | |||
79cd58bdf3 | |||
d1e5d92191 | |||
cb382fa76b | |||
e6c0ec7278 | |||
3cdf108057 | |||
688030ecb6 | |||
589c4fb30f | |||
b20e972bec | |||
a8a2e3231c | |||
4bdf52fc1e | |||
0b82a05a75 | |||
80c97ca21b | |||
2491c99b37 | |||
cf534d4726 | |||
5689086202 | |||
bd64ed1e93 | |||
995861de4d | |||
56a0131778 | |||
0bb3943698 | |||
2d9b3aa537 | |||
8e14545282 | |||
2eedc330bf | |||
0ed3edc99e | |||
0c0708076e | |||
3847e248df | |||
af927ffdaf | |||
c03d403437 | |||
c48644490f | |||
54927dc0e0 | |||
705cf6113d | |||
9022f5034f | |||
bd992e7baf | |||
0031f388ac | |||
447bad9dbd | |||
89a48e365c | |||
1cfea1113a | |||
6488a392a3 | |||
600c9dd27d | |||
e380462532 | |||
94e0e5ab7d | |||
8613382869 | |||
df17c33898 | |||
ddf17d93ac | |||
c8ee08c24b | |||
84adf77bf3 | |||
f75dcc7f4c | |||
842b8cf323 | |||
b5918a1faa | |||
d0c6559204 | |||
6d012f628b | |||
726852e3d3 | |||
83b385a290 | |||
ec85458612 | |||
73dcbf7ba2 | |||
f80fe97763 | |||
cbf1d07073 | |||
8284bef072 | |||
fd5d061d49 | |||
32fbc0d334 | |||
1337a8dfb1 | |||
3440a8a0bf | |||
5e891ea981 | |||
adda54ac55 | |||
cebb149f5c | |||
e1c0862658 | |||
21fd31dad8 | |||
957f80c623 | |||
1c51e12c18 | |||
872b249711 | |||
1146f25015 | |||
45e15f62f5 | |||
7f638f0b2d | |||
5a52e86546 | |||
a88f609b8a | |||
61e8ae2f7b | |||
b46e1ca97e | |||
fb7c03ff4d | |||
2544d2c952 | |||
ea7c2fc673 | |||
9a11a94894 | |||
cbf162ca64 | |||
85d20cd61b | |||
94976d63ca | |||
cb47a9e97f | |||
ad5894e486 | |||
63d9c070ef | |||
f15d23b496 | |||
4c5968097d | |||
159c4d56cd | |||
f3e78c8f3c | |||
8d9752a557 | |||
1345a8c67c | |||
83fad0fb59 | |||
e9d017ba08 | |||
d8c6168d11 | |||
dd3f38fe5b | |||
a38bca3438 | |||
5f50fe7a4a | |||
b8e7b8e2e1 | |||
2f0166b945 | |||
d790229a33 | |||
8c99a87aa8 | |||
fe14b0b82e | |||
aa5b29e2f2 | |||
382726fde4 | |||
c2cb2bef96 | |||
09f633596d | |||
42a25f2f26 | |||
6d59047c5f | |||
ad7c05778f | |||
f02368141f | |||
649b9cc195 | |||
1f5a6f1341 | |||
da4c2d530d | |||
079c59b929 | |||
5b701962dc | |||
c595632b92 | |||
c5610398d5 | |||
a7f4448f34 | |||
7807a4f738 | |||
e5d294df32 | |||
d0b6f3663b | |||
c71aff99db | |||
5d33d5a7d9 | |||
512ffa2bf4 | |||
d223ac0379 | |||
113a3809ab | |||
fb34c6c7b9 | |||
7869294a26 | |||
61a0158877 | |||
fa93480d9a | |||
063f69d51d | |||
c54a85ee64 | |||
48083608b5 | |||
393a6c5edf | |||
0d96528d2f | |||
2ba54a69be | |||
94106cc41f | |||
3aa0410f6e | |||
7a894e3738 | |||
d792e95c21 | |||
a125b0fbc3 | |||
a216225827 | |||
0dfe511370 | |||
d4cc2d3503 | |||
d5f38f5690 | |||
c01f0ae825 | |||
81bbe8c93b | |||
29fa57e9b3 | |||
13f39afbdd | |||
3073511e30 | |||
6c4432d417 | |||
e45db42e94 | |||
375ca542ab | |||
0202b05a5d | |||
d6a92b18d4 | |||
5e623f14f3 | |||
22c77c607e | |||
b777d6aa3f | |||
4df2e1ef5c | |||
67f9783e6a | |||
6eaa404187 | |||
0045ce4cde | |||
465b0a79d8 | |||
ad8e92e9c6 | |||
edfb874527 | |||
c2d9c1a6f1 | |||
81a5813270 | |||
08e2696627 | |||
c9693b4746 | |||
ceb4357a8d | |||
fc986a3fbe | |||
0d2cccc2ce | |||
8af42d42da | |||
81ff253e68 | |||
e68f8e79ea | |||
e1fcffcc81 | |||
f3e78e50ff | |||
c14900dbb0 | |||
0aa76d3e5b | |||
622bfd4f08 | |||
1077109e11 | |||
ed7d7b405e | |||
41d80ba17b | |||
bdf99e0981 | |||
acdc19d1b7 | |||
7f9c335487 | |||
1f8290ca44 | |||
215780ab56 | |||
a6d4ce2630 | |||
0c77a96249 | |||
d92fde6980 | |||
87f50659db | |||
689630d261 | |||
848c54dc47 | |||
9845029a75 | |||
375cc67ba6 | |||
380c1522ac | |||
4dd7be7ed0 | |||
12fad65991 | |||
5c79ee4446 | |||
d48140cab3 | |||
3cf038f300 | |||
83505e61f3 | |||
6a58db66f7 | |||
af54832d24 | |||
86b417e83f | |||
f34838688e | |||
bcb1166e52 | |||
8d1637f567 | |||
b03614527b | |||
9b509f6478 | |||
89c69a1d25 | |||
06bfe19f05 | |||
7394ee7c72 | |||
b2d23b91e7 | |||
2ce109eb53 | |||
823fb2995b | |||
1e2c1ae98a | |||
b457e88cd0 | |||
e97478cc1e | |||
2d8383d3c8 | |||
1c4d8f36e4 | |||
e94da808cb | |||
a1c0bb68dd | |||
774e9d24a1 | |||
9a264a4284 | |||
0172939490 | |||
24613a60dc | |||
acc8f7fadc | |||
de4ea8e6f4 | |||
2c36d5ff45 | |||
f1295b506d | |||
fbcc6d0d25 | |||
fc92abec2c | |||
52bb149541 | |||
9caf32befe | |||
47d3b3dd58 | |||
a1c2749380 | |||
945798f913 | |||
6d02c0d392 | |||
ec74fc05d4 | |||
46b932ccc0 | |||
f85f77f6cc | |||
6a4b4f3449 | |||
d0473d6d83 | |||
70bf1a5711 | |||
bacc5aa6d3 | |||
29c46cdf34 | |||
552f5b2693 | |||
d5d9746ca3 | |||
508f116738 | |||
472ad43211 | |||
603c790213 | |||
62e0e18030 | |||
b0a9bbf33a | |||
6b2ec23132 | |||
ed1cb9edca | |||
17f2f12ce6 | |||
12bdb5f550 | |||
8d1f96cc0a | |||
a4049fb85c | |||
bb55307a9d | |||
422dc05bb0 | |||
9a8f45ee30 | |||
dac93ed616 | |||
8b7d4b0c9e | |||
499bc404e8 | |||
a81d835e4d | |||
961e4da7d8 | |||
b178414a47 | |||
f54c90a0ba | |||
ee167e53d1 | |||
8f733461b3 | |||
82beaabf6a | |||
4056c046a7 | |||
e3cad04dec | |||
1428dcee21 | |||
f3b71a73e3 | |||
380d9862c3 | |||
b6c0e53d69 | |||
e95bb34ea0 | |||
9e0de57a82 | |||
f6ff1f18b8 | |||
7595a5dfcb | |||
1e5353824a | |||
4704a0a288 | |||
b2112729fa | |||
32bed50ba1 | |||
5b561f434d | |||
750d70c202 | |||
34689cb3f3 | |||
ba225017c4 | |||
507241f73c | |||
8a1b51c716 | |||
75cd9cd2de | |||
00348756bc | |||
35fe4313d5 | |||
9a9987aeed | |||
5582901ca5 | |||
ded221fba2 | |||
ab745d3b0e | |||
b915c7a870 | |||
6c26255979 | |||
e2c4525da7 | |||
e778e127d6 | |||
a4e6f0b3c6 | |||
048e7771fb | |||
15c229300c | |||
24814a4f0f | |||
6188e64473 | |||
c34b0c67a1 | |||
7e6b72cb5c | |||
e3da85faed | |||
491c23a728 | |||
351516c57c | |||
8c7b764d47 | |||
905b8cc82f | |||
47687cf085 | |||
29c60c000a | |||
35f4bb96f3 | |||
92f171ec99 | |||
0933a79ab8 | |||
b136b387a7 | |||
6eb455032c | |||
5c8c0ae04e | |||
a35be3a12a | |||
f9b0d1a8e7 | |||
543a87c63f | |||
c9f566269b | |||
bfa12d75f8 | |||
b3eda29f41 | |||
18d8bf4b9c | |||
aee82d3196 | |||
a5907a8239 | |||
2a6c84984a | |||
0538c11576 | |||
012a1c2533 | |||
c9015e2e04 | |||
07fba274b1 | |||
585f259b63 | |||
b3161f5803 | |||
5a9952c7b4 | |||
8ecc9509b3 | |||
f72cb28b0f | |||
43ed0ed1ae | |||
69dfca2feb | |||
3bdf28c1fe | |||
c8a4c04b36 | |||
26f066f0c7 | |||
4a0ade4788 | |||
c397e350f4 | |||
b6058a837f | |||
5518022a5d | |||
5f958a582d | |||
e27237a03a | |||
ee84b20247 | |||
b25126a277 | |||
807ec60e63 | |||
f9cc090473 | |||
2f3384947b | |||
a8dde17146 | |||
db4aaedcbd | |||
5208bb32f1 | |||
982c812e81 | |||
c1908c7d91 | |||
59c5a2f519 | |||
1d05027ba2 | |||
fed3e6a808 | |||
ec7cb9981c | |||
df4d7846e5 | |||
6c160adab3 | |||
032ab66529 | |||
60d9611c23 | |||
210682b734 | |||
f0ec751237 | |||
1d139f7a0b | |||
25e6c4eff8 | |||
a76b7dadae | |||
b6232cfdd1 | |||
a2a77172a6 | |||
1b903767e0 | |||
4e7f53adf0 | |||
8c1b26889a | |||
af9242f4cc | |||
564f02aa2b | |||
3b8725e0f5 | |||
3caa4ad1ba | |||
b0ff946b55 | |||
eb0e7b1b81 | |||
36e1e5f151 | |||
4c8c115a76 | |||
545e14691b | |||
be97785856 | |||
fde0ddb324 | |||
117f66e823 | |||
a26aecdfdb | |||
47e6b2cef8 | |||
cc7f8f58e8 | |||
c9985bf563 | |||
22c0c5465a | |||
2cfbf76db8 | |||
ec4dee0fcd | |||
952287db29 | |||
b99b2c446c | |||
04c0f7e15c | |||
d001479a47 | |||
f16810c48e | |||
66b05433b6 | |||
6abf8ef78f | |||
b907a5d765 | |||
b0854fbff5 | |||
c1dee15144 | |||
987119cd4a | |||
08b03afa4b | |||
09841b1c9b | |||
bd0c267cbe | |||
ca1b2a1a91 | |||
1b90567546 | |||
16f417f5af | |||
5c82fdc243 | |||
55e55826ee | |||
530953050a | |||
24f89f8bd9 | |||
4dc7ee9087 | |||
e2d1d832ef | |||
d336e24dce | |||
ae2c90cc28 | |||
6cf61039cf | |||
48d2a8b8ee | |||
477a6d426c | |||
0972bdeda2 | |||
1cc86c07a0 | |||
1c7e8e9093 | |||
b619b244c7 | |||
0fb1bcd321 | |||
a4dc12f12c | |||
4547a05a68 | |||
4b4e082102 | |||
1954b87819 | |||
77924757a8 | |||
16460b0048 | |||
a9068aa8ff | |||
89244981a8 | |||
138ab26b8c | |||
51a97c031f | |||
cc5e621fc4 | |||
2ebf33ac1c | |||
788d812a72 | |||
29c887ef2c | |||
1085960ed8 | |||
8df689bd44 | |||
2f8a45cd8b | |||
ce68ac6959 | |||
dc7c584a4d | |||
58d477f7a6 | |||
804af9658a | |||
9d429180f9 | |||
771bfe9e78 | |||
c9f963a77e | |||
7ba9fe4d5d | |||
fb1edd05f4 | |||
780abaec98 | |||
f468a9a0e2 | |||
1054c155db | |||
7d2353f24d | |||
34f72ddb3d | |||
1382e8d84b | |||
e2e3fa3d11 | |||
9e5257b83b | |||
4cd79d8ddd | |||
4b52cd512d | |||
e32f7baa0d | |||
60b1f9629c | |||
4051c0333f | |||
e42517754a | |||
a153b47c2b | |||
e531c6fc6c | |||
ed7e05fb2a | |||
8130df63ca | |||
123098ce79 | |||
4fd4facf35 | |||
43bf3b4a78 | |||
05da381c15 | |||
26bf95731b | |||
03dc6ec0d4 | |||
f7ec759ef0 | |||
7ddebd7a75 | |||
bab78bbeb6 | |||
7a79428278 | |||
1360f027d9 | |||
b3629c6f62 | |||
176c98eb66 | |||
25d16f358a | |||
795b14330a | |||
0e5aed63dd | |||
125bdc3253 | |||
6cff6dd8b8 | |||
75f0412f9d | |||
207b6c50fb | |||
6e24b1587d | |||
22d29a6d52 | |||
0dc566124a | |||
721e8ae93f | |||
e6fdf0c9f7 | |||
8da07e91e4 | |||
52b54631a4 | |||
e9db2d1b18 | |||
93edae280d | |||
bb17591959 | |||
aa3b91b802 | |||
b55fabc7be | |||
54605d8c8e | |||
52ca80bdd2 | |||
0291eff99a | |||
c96e504adb | |||
01a6db9324 | |||
993280ec03 | |||
6ff9d5770b | |||
455241debb | |||
db89c3e1a3 | |||
56dac74f71 | |||
c7bc684909 | |||
96272e19a6 | |||
bd9088792b | |||
cdb2ebbdfa | |||
4b5ad31b3a | |||
6c168c8f22 | |||
afc8b887ab | |||
f111fc0608 | |||
1d959cb0ca | |||
72290f67fe | |||
4c89d5331f | |||
61940b2275 | |||
e77b720ead | |||
7b39cc83cc | |||
01dc1c1394 | |||
4dfce4624d | |||
5e4d77b2b8 | |||
2dd8f41147 | |||
0add0c400f | |||
e847aaca3e | |||
7d02c4fdb7 | |||
d9b16c1197 | |||
ae7c1e3e55 | |||
50e1dcc43a | |||
d84810d89d | |||
39d86a28e7 | |||
5022a31889 | |||
c2af10d256 | |||
b89ed8eb7b | |||
118862f1ba | |||
148de1c875 | |||
76070b4674 | |||
3308d82b23 | |||
c44e025898 | |||
02017ed0e0 | |||
4366fdfc13 | |||
d957dd2c9f | |||
eb5cb04aa9 | |||
e5aa38cb0f | |||
d899334bba | |||
ce796dcdbf | |||
3e38f8af23 | |||
e74f9f27db | |||
31a9fdced8 | |||
47793b606c | |||
6cf6981ed0 | |||
7c24cd790d | |||
b402484e41 | |||
04845d42c0 | |||
0d526d66b7 | |||
8fe16df6c9 | |||
1a9624af51 | |||
8b7e59729f | |||
27a8799e48 | |||
f6ee8e52dd | |||
08f2dde45a | |||
42713c6e99 | |||
7ffba22f2d | |||
60198a05b9 | |||
6b8b1259e2 | |||
c966a5c17e | |||
ea8db7a4ae | |||
8aaec1d98f | |||
b1428555d1 | |||
0e67fcd361 | |||
d99fea2db6 | |||
7ce63d32b2 | |||
3451f26086 | |||
05290d5547 | |||
dc100f85b3 | |||
0316490c54 | |||
d85cef557b | |||
838ca2fd93 | |||
84b36a7193 | |||
dea68f073e | |||
7af9cc70d0 | |||
4b876168f4 | |||
d92a7527db | |||
720365859c | |||
d95e2b7999 | |||
6fc5d8e81e | |||
67e3eff806 | |||
f5024b4926 | |||
c1b2595deb | |||
512d4ca6a4 | |||
c91e4afe6c | |||
a2d8b89289 | |||
8ca991ecd2 | |||
e3ad9be4c8 | |||
0d6479e1d6 | |||
3270b432bc | |||
bd14b4d23e | |||
4402a7d817 | |||
5871d1e359 | |||
2f33a8c657 | |||
6dc7be6cd1 | |||
7d6164b351 | |||
44ab30f628 | |||
dcae30c1e4 | |||
f281a362f0 | |||
c402dad6fa | |||
45d0d72138 | |||
15088d7ebe | |||
4be4db5e6c | |||
3e174a0879 | |||
0cdef3376d | |||
b0e11826e5 | |||
e3998e30ba | |||
51d79f3e3b | |||
b773e57490 | |||
c8307a9e44 | |||
e84fa8d4e6 | |||
f11b5f3e40 | |||
5538ff7252 | |||
aca9a41fcf | |||
cb607b4911 | |||
31c6159019 | |||
9adb625846 | |||
0b10cbd713 | |||
3119be908c | |||
28d4250866 | |||
66e439b6f4 | |||
f9ca054314 | |||
f7c9c8928e | |||
ea3048421f | |||
5cd93a0618 | |||
eef4cd1b64 | |||
ac7994d8c7 | |||
8a7d1a69b3 | |||
76b20be2ea | |||
74cab14b8d | |||
c8aa5feb14 | |||
590c393680 | |||
c95dfec5e4 | |||
3bc238b1ce | |||
a3c66b2740 | |||
0cae9c3c1b | |||
68ccbefc94 |
.gitignore.mailmap.travis.ymlDockerfile
Godeps
Godeps.jsonReadme
README.md_workspace
.gitignore
src
bitbucket.org
kardianos
code.google.com
p
github.com
ethereum
serpent-go
.gitignore.gitmodulesREADME.mdall.cpp
cpp
serpent.goserpent
.gitignoreMANIFEST.inMakefileREADME.mdbignum.cppbignum.hcmdline.cppcompiler.cppcompiler.hexample.cpp
examples
collatz.se
funcs.cppfuncs.hfunctions.cppfunctions.hlllparser.cpplllparser.hopcodes.cppopcodes.hoptimize.cppoptimize.hparser.cppparser.hpreprocess.cpppreprocess.hpyserpent.cpppyserpent.pyrewriter.cpprewriter.hrewriteutils.cpprewriteutils.hserpent.pysetup.pytokenize.cpptokenize.hutil.cpputil.hcounterparty
crowdfund.secyberdyne
datafeed.seecc
ecrecover.seecrecover_compiled.evmjacobian_add.sejacobian_double.sejacobian_mul.semodexp.sesubstitutes.pytest.py
eth15
fixedpoint.selong_integer_macros.semul2.semutuala.senamecoin.sepeano.sereturnten.seschellingcoin
schellinghelper.seshort_namecoin.sesubcurrency.setests
howeyc
fsnotify
huin
goupnp
jackpal
obscuren
otto
.gitignoreDESIGN.markdownLICENSEMakefileREADME.markdownarray_test.go
ast
bug_test.gobuiltin.gobuiltin_array.gobuiltin_boolean.gobuiltin_date.gobuiltin_error.gobuiltin_function.gobuiltin_json.gobuiltin_math.gobuiltin_number.gobuiltin_object.gobuiltin_regexp.gobuiltin_string.gobuiltin_test.goclone.gocmpl_evaluate.gocmpl_evaluate_expression.gocmpl_evaluate_statement.gocmpl_function.gocmpl_parse.gocmpl_test.goconsole.godate_test.godbg.godbg
documentation_test.goenvironment.goerror.goerror_test.goevaluate.goexecution_context.gofile
function_test.goglobal.goglobal_test.goinlineinline.gojson_test.gomath_test.gonumber_test.goobject.goobject_class.goobject_test.gootto.gootto
otto_.gootto_error_test.gootto_test.gopanic_test.goparser
MakefileREADME.markdowndbg.goerror.goexpression.golexer.golexer_test.gomarshal_test.goparser.goparser_test.goregexp.goregexp_test.goscope.gostatement.go
parser_test.goproperty.goreflect_test.goregexp_test.goregistry
result.goruntime.goruntime_test.goscript.goscript_test.gostring_test.goterst
test
testing_test.gotoken
type_arguments.gotype_array.gotype_boolean.gotype_date.gotype_error.gotype_function.gotype_go_array.gotype_go_map.gotype_go_slice.gotype_go_struct.gotype_number.gotype_reference.gotype_regexp.gotype_string.gounderscore
underscore_arrays_test.gounderscore_chaining_test.gounderscore_collections_test.gounderscore_functions_test.gounderscore_objects_test.gounderscore_test.gounderscore_utility_test.govalue.govalue_boolean.govalue_number.govalue_primitive.govalue_string.govalue_test.goqml
.gitignoreLICENSEREADME.mdall.cppbridge.golog.goqml.goqml_test.goresources.gostats.gotesting.go
cdata
cmd
cpp
capi.cppcapi.hconnector.cppconnector.hgovalue.cppgovalue.hgovaluetype.cppgovaluetype.hidletimer.cppmmemwin.cppmoc_all.cppmoc_connector.cppmoc_govalue.cppmoc_idletimer.cpp
private
update-moc.shcpptest
datatype.godoc.goexamples
controls
.gitignoreREADME.md
basiclayouts
gallery
content
gallery.goimages
bubble.pngbutton-pressed.pngbutton.pngdocument-open.pngdocument-open@2x.pngdocument-save-as.pngdocument-save-as@2x.pngfolder_new.pnggo-next.pnggo-previous.pngpreferences-system.pngprocess-stop.pngprogress-background.pngprogress-fill.pngslider-handle.pngtab.pngtab_selected.pngtextfield.pngtoplevel_window.pngview-refresh.pngwindow-new.pngwindow-new@2x.png
main.qmlsplitview
tableview
touch
customtype
gopher
imgprovider
modelview
delegate
painting-es2
painting
particle
qmlscene
qrcpacking
reparent
snapweb
gl
1.0
1.1
1.2
1.3
1.4
1.5
2.0
2.1
3.0
3.1
3.2compat
3.2core
3.3compat
3.3core
4.0compat
4.0core
4.1compat
4.1core
4.2compat
4.2core
4.3compat
4.3core
es2
gengl
glbase
rakyll
globalconf
goini
robertkrimen
otto
syndtr
goleveldb
leveldb
batch.gobatch_test.gobench_test.go
cache
comparer.gocomparer
config.gocorrupt_test.godb.godb_compaction.godb_iter.godb_snapshot.godb_state.godb_test.godb_util.godb_write.godoc.goerror.goexternal_test.gofilter.gofilter
iterator
array_iter.goarray_iter_test.goindexed_iter.goindexed_iter_test.goiter.goiter_suite_test.gomerged_iter.gomerged_iter_test.go
journal
key.gokey_test.goleveldb_suite_test.gomemdb
opt
options.gosession.gosession_record.gosession_record_test.gosession_util.gostorage
file_storage.gofile_storage_plan9.gofile_storage_test.gofile_storage_unix.gofile_storage_windows.gomem_storage.gomem_storage_test.gostorage.go
storage_test.gotable.gotable
testutil
testutil_test.goutil.goutil
version.gogolang.org
x
gopkg.in
_data
accounts
block_pool.gocmd
bootnode
disasm
ethereum
ethtest
evm
mist
assets
backButton.pngbackButton@2x.pngbackButtonDisabled.pngbackButtonDisabled@2x.pngbackButtonHover.pngbackButtonHover@2x.pngbrowser.pngbrowser@2x.png
bindings.godebugger.goerrors.goext_app.goflags.gogui.gohtml_container.gomain.goqml_container.goui_lib.godebugger
examples
ext
.bowerrc.editorconfig.gitignore.jshintrc.npmignore.travis.ymlbig.jsbignumber.min.js
eth.js
ethereum.jsethereum.js
.bowerrc.editorconfig.gitignore.jshintrc.npmignore.travis.ymlLICENSEREADME.mdbower.json
home.htmlhtml_messaging.jsmist.jsq.jsqml_messaging.jsqt_messaging_adapter.jssetup.jsstring.jstest.htmldist
example
balance.htmlcontract.htmlcontract_with_array.htmlevent.htmlevent_inc.htmlnatspec_contract.htmlnode-app.js
gulpfile.jsindex.jslib
abi.jsconst.jscontract.jsevent.jsfilter.jsformatters.jshttpsync.jsjsonrpc.jslocal.jsprovidermanager.jsqtsync.jstypes.jsutils.jsweb3.js
package.jsontest
html
miner.pngmining-icon.pngmining-icon@2x.pngqml
depricated_browser.qml
fonts
Simple-Line-Icons.ttfSourceSansPro-Black.ttfSourceSansPro-BlackIt.ttfSourceSansPro-Bold.ttfSourceSansPro-BoldIt.ttfSourceSansPro-ExtraLight.ttfSourceSansPro-ExtraLightIt.ttfSourceSansPro-It.ttfSourceSansPro-Light.ttfSourceSansPro-LightIt.ttfSourceSansPro-Regular.ttfSourceSansPro-Semibold.ttfSourceSansPro-SemiboldIt.ttfSourceSerifPro-Bold.ttfSourceSerifPro-Regular.ttfSourceSerifPro-Semibold.ttf
main.qmlviews
webapp.qmlpeerserver
rlpdump
utils
core
block_manager.goblock_processor.goblock_processor_test.gochain_manager.gochain_manager_test.goerror.goevents.goexecution.gofilter.gogenesis.gohelper_test.gomanager.gosimple_pow.gostate_transition.gotransaction_pool.gotransaction_pool_test.go
types
vm_env.gocrypto
crypto.gocrypto_test.go
ecies
key.gokey_store_passphrase.gokey_store_plain.gokey_store_test.gokeypair.gorandentropy
secp256k1
.gitignoreREADME.mdnotes.gosecp256.gosecp256_test.go
secp256k1
COPYINGMakefileTODOconfig.mkconfigure
include
src
bench.cecdsa.hecmult.hfield.hfield_10x26.hfield_5x52.hfield_5x52_asm.asmfield_5x64.hfield_5x64_asm.asmfield_gmp.hgroup.h
impl
ecdsa.hecmult.hfield.hfield_10x26.hfield_5x52.hfield_5x52_asm.hfield_5x52_int128.hfield_5x64.hfield_5x64_asm.hfield_gmp.hgroup.hnum.hnum_gmp.hnum_openssl.hutil.h
java
num.hnum_gmp.hnum_openssl.hsecp256k1.ctests.cutil.hsha3
eth
backend.goblock_pool.goblock_pool_test.goerror.gopeer_util.goprotocol.goprotocol_test.go
test
wallet.goethdb
ethereum.goethutil
event/filter
events.gogocoverage.shinstall_deps.shjavascript
logger
miner
nat.gonatpmp.gonatupnp.gop2p
client_identity.goclient_identity_test.go
peer.godiscover
handshake.gohandshake_test.gomessage.gomessage_test.gonat
natpmp.gonatupnp.gopeer.gopeer_error.gopeer_test.goprotocol.goprotocol_test.goserver.goserver_test.gotestlog_test.gotestpoc7.gopow
profile.covptrie
rlp
rpc
state
tests
files
.gitignore
BasicTests
BlockchainTests
StateTests
stBlockHashTest.jsonstInitCodeTest.jsonstRecursiveCreate.jsonstRefundTest.jsonstSpecialTest.jsonstSystemOperationsTest.jsonstTransactionTest.json
TransactionTests
TrieTests
VMTests
RandomTests
201412232335.json201501082023.json201501082026.json201501082028.json201501082029.json201501082030.json201501082036.json201501082039.json201501082040.json201501082041.json201501082052.json201501082111.json201501082112.json201501082115.json201501082116.json201501082118.json201501082119.json201501082121.json201501082122.json201501082123.json201501082131.json201501082132.json201501082134.json201501082137.json201501082141.json201501082145.json201501082146.json201501082150.json201501082151.json201501082153.json201501082156.json201501082159.json201501082200.json201501082203.json201501082205.json201501082207.json201501091628.json201501091644.json201501091657.json201501091658.json201501091831.json201501110744GO.json201501120415GO.json201501120933PYTHON.json201501121148GO.json201501121149GO.json201501121151GO.json201501121256GO.json201501121301GO.json201501121303GO.json201501122225CALL_TO_PRECOMPILED_GO.json201501122239BALANCE_OF_ADDRESS_GO.json201501130902PYTHON_BLOCKHASH.json201501130903PYTHON_INVALID_JUMP_DESTINATION.json201501130906PYTHON_INVALID_OPCODE.json201501131326STACKUNDERFLOW_CPPJIT.json201501131330CPPJIT.json201501131331CPPJIT.json201501131414CPPJIT.json201501131452CPPJIT.json201501131453CPPJIT.json201501131627CPPJIT.json201501131628CPPJIT.json201501131655CREATE_RETURNS_DIFFERENT_ADDREESS_GO.json201501131811CPPJIT.json201501131818CPPJIT.json201501131820CPPJIT.json201501131821CPPJIT.json201501131823CPPJIT.json201501131824CPPJIT.json201501131826CPPJIT.json201501132239PYTHON.json201501132242PYTHON.json201501132304PYTHON.json201501132305PYTHON.json201501140910CPPJIT.json201501140911CPPJIT.json201501140912CPPJIT.json201501140914CPPJIT.json201501140918PYTHON.json201501150842LARGE_DATA_IN_CALLCREATE_GOjson201501151106PYTHON.json201501191458PYTHON.json201501191859PYTHON.json201501191953PYTHON.json201501221210PYTHON.json201501221235PYTHON.json201501221531CPPJIT.json201501221647PYTHON.json201501221718CPPJIT.json201501222304PYTHON.json201501222357PYTHON.json201501230844PYTHON.json201501231158PYTHON.json201502031248CPPJIT.json201502032117GO.jsongoFail.jsongoFail2.jsongoFail3.json
vmArithmeticTest.jsonvmBlockInfoTest.jsonvmEnvironmentalInfoTest.jsonvmIOandFlowOperationsTest.jsonvmInputLimitsTest1.jsonvmInputLimitsTest2.jsonvmSha3Test.jsonvmSystemOperationsTest.jsonansible
README.mdVagrantfileec2-setup.ymlec2-terminate.ymlec2.iniec2.pyhost-config.ymlsite.yml
index.jspackage.jsonroles
common
docker
ec2
testrunner
tasks
test-files
testrunner-config.ymlhelper
vm
trie
cache.goencoding.gofullnode.gohashnode.goiterator.goiterator_test.gomain_test.gonode.goshortnode.gotrie.gotrie_test.govaluenode.go
ui
update-license.govm
address.goanalysis.goclosure.gocommon.gocontext.goenvironment.gostack.gotypes.govirtual_machine.govm.govm_debug.govm_jit.govm_jit_fake.go
websocket
whisper
wire
xeth
10
.gitignore
vendored
10
.gitignore
vendored
@ -10,3 +10,13 @@
|
||||
.DS_Store
|
||||
*/**/.DS_Store
|
||||
.ethtest
|
||||
|
||||
#*
|
||||
.#*
|
||||
*#
|
||||
*~
|
||||
.project
|
||||
.settings
|
||||
|
||||
cmd/ethereum/ethereum
|
||||
cmd/mist/mist
|
||||
|
12
.mailmap
Normal file
12
.mailmap
Normal file
@ -0,0 +1,12 @@
|
||||
Jeffrey Wilcke <jeffrey@ethereum.org>
|
||||
Jeffrey Wilcke <jeffrey@ethereum.org> <geffobscura@gmail.com>
|
||||
Jeffrey Wilcke <jeffrey@ethereum.org> <obscuren@obscura.com>
|
||||
Jeffrey Wilcke <jeffrey@ethereum.org> <obscuren@users.noreply.github.com>
|
||||
|
||||
Viktor Trón <viktor.tron@gmail.com>
|
||||
|
||||
Joseph Goulden <joegoulden@gmail.com>
|
||||
|
||||
Nick Savers <nicksavers@gmail.com>
|
||||
|
||||
Maran Hidskes <maran.hidskes@gmail.com>
|
23
.travis.yml
23
.travis.yml
@ -1,25 +1,24 @@
|
||||
language: go
|
||||
go:
|
||||
- 1.3
|
||||
- 1.4.1
|
||||
before_install:
|
||||
- sudo add-apt-repository ppa:ubuntu-sdk-team/ppa -y
|
||||
- sudo add-apt-repository ppa:beineri/opt-qt54 -y
|
||||
- sudo apt-get update -qq
|
||||
- sudo apt-get install -yqq libgmp3-dev qtbase5-private-dev qtdeclarative5-private-dev libqt5opengl5-dev libreadline6-dev
|
||||
- sudo apt-get install -yqq libgmp3-dev libreadline6-dev qt54quickcontrols qt54webengine
|
||||
install:
|
||||
- go get code.google.com/p/go.tools/cmd/goimports
|
||||
- go get github.com/golang/lint/golint
|
||||
# - go get code.google.com/p/go.tools/cmd/vet
|
||||
- go get code.google.com/p/go.tools/cmd/cover
|
||||
# - go get golang.org/x/tools/cmd/vet
|
||||
- if ! go get code.google.com/p/go.tools/cmd/cover; then go get golang.org/x/tools/cmd/cover; fi
|
||||
- go get github.com/mattn/goveralls
|
||||
- ./install_deps.sh
|
||||
before_script:
|
||||
- gofmt -l -w .
|
||||
- goimports -l -w .
|
||||
- golint .
|
||||
# - go vet ./...
|
||||
# - go test -race ./...
|
||||
script:
|
||||
- ./gocoverage.sh && goveralls -coverprofile=profile.cov -service=travis-ci -repotoken $COVERALLS_TOKEN
|
||||
- ./gocoverage.sh
|
||||
after_success:
|
||||
- if [ "$COVERALLS_TOKEN" ]; then goveralls -coverprofile=profile.cov -service=travis-ci -repotoken $COVERALLS_TOKEN; fi
|
||||
env:
|
||||
global:
|
||||
- PKG_CONFIG_PATH=/opt/qt54/lib/pkgconfig
|
||||
- LD_LIBRARY_PATH=/opt/qt54/lib
|
||||
- secure: "U2U1AmkU4NJBgKR/uUAebQY87cNL0+1JHjnLOmmXwxYYyj5ralWb1aSuSH3qSXiT93qLBmtaUkuv9fberHVqrbAeVlztVdUsKAq7JMQH+M99iFkC9UiRMqHmtjWJ0ok4COD1sRYixxi21wb/JrMe3M1iL4QJVS61iltjHhVdM64="
|
||||
|
||||
|
45
Dockerfile
45
Dockerfile
@ -1,41 +1,40 @@
|
||||
FROM ubuntu:14.04
|
||||
FROM ubuntu:14.04.1
|
||||
|
||||
## Environment setup
|
||||
ENV HOME /root
|
||||
ENV GOPATH /root/go
|
||||
ENV PATH /go/bin:/root/go/bin:/usr/local/go/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games
|
||||
ENV PATH /root/go/bin:/usr/local/go/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games
|
||||
|
||||
RUN mkdir -p /root/go
|
||||
ENV DEBIAN_FRONTEND noninteractive
|
||||
|
||||
## Install base dependencies
|
||||
RUN apt-get update && apt-get upgrade -y
|
||||
RUN apt-get install -y git mercurial build-essential software-properties-common pkg-config libgmp3-dev libreadline6-dev libpcre3-dev libpcre++-dev
|
||||
RUN apt-get install -y git mercurial build-essential software-properties-common wget pkg-config libgmp3-dev libreadline6-dev libpcre3-dev libpcre++-dev
|
||||
|
||||
## Build and install Go
|
||||
RUN hg clone -u release https://code.google.com/p/go
|
||||
RUN cd go && hg update go1.4
|
||||
RUN cd go/src && ./all.bash && go version
|
||||
## Install Qt5.4 (not required for CLI)
|
||||
# RUN add-apt-repository ppa:beineri/opt-qt54-trusty -y
|
||||
# RUN apt-get update -y
|
||||
# RUN apt-get install -y qt54quickcontrols qt54webengine mesa-common-dev libglu1-mesa-dev
|
||||
# ENV PKG_CONFIG_PATH /opt/qt54/lib/pkgconfig
|
||||
|
||||
## Install GUI dependencies
|
||||
RUN add-apt-repository ppa:ubuntu-sdk-team/ppa -y
|
||||
RUN apt-get update -y
|
||||
RUN apt-get install -y qtbase5-private-dev qtdeclarative5-private-dev libqt5opengl5-dev
|
||||
# Install Golang
|
||||
RUN wget https://storage.googleapis.com/golang/go1.4.1.linux-amd64.tar.gz
|
||||
RUN tar -C /usr/local -xzf go*.tar.gz && go version
|
||||
|
||||
## Fetch and install serpent-go
|
||||
RUN go get -v -d github.com/ethereum/serpent-go
|
||||
WORKDIR $GOPATH/src/github.com/ethereum/serpent-go
|
||||
RUN git checkout master
|
||||
RUN git submodule update --init
|
||||
RUN go install -v
|
||||
# this is a workaround, to make sure that docker's cache is invalidated whenever the git repo changes
|
||||
ADD https://api.github.com/repos/ethereum/go-ethereum/git/refs/heads/develop file_does_not_exist
|
||||
|
||||
# Fetch and install go-ethereum
|
||||
## Fetch and install go-ethereum
|
||||
RUN go get -v github.com/tools/godep
|
||||
RUN go get -v -d github.com/ethereum/go-ethereum/...
|
||||
WORKDIR $GOPATH/src/github.com/ethereum/go-ethereum
|
||||
RUN git checkout poc8
|
||||
RUN ETH_DEPS=$(go list -f '{{.Imports}} {{.TestImports}} {{.XTestImports}}' github.com/ethereum/go-ethereum/... | sed -e 's/\[//g' | sed -e 's/\]//g' | sed -e 's/C //g'); if [ "$ETH_DEPS" ]; then go get $ETH_DEPS; fi
|
||||
RUN git checkout develop
|
||||
RUN godep restore
|
||||
RUN go install -v ./cmd/ethereum
|
||||
|
||||
# Run JSON RPC
|
||||
ENTRYPOINT ["ethereum", "-rpc=true", "-rpcport=8080"]
|
||||
EXPOSE 8080
|
||||
## Run & expose JSON RPC
|
||||
ENTRYPOINT ["ethereum", "-rpc=true", "-rpcport=8545"]
|
||||
EXPOSE 8545
|
||||
|
||||
|
||||
|
118
Godeps/Godeps.json
generated
Normal file
118
Godeps/Godeps.json
generated
Normal file
@ -0,0 +1,118 @@
|
||||
{
|
||||
"ImportPath": "github.com/ethereum/go-ethereum",
|
||||
"GoVersion": "go1.4.1",
|
||||
"Packages": [
|
||||
"./..."
|
||||
],
|
||||
"Deps": [
|
||||
{
|
||||
"ImportPath": "bitbucket.org/kardianos/osext",
|
||||
"Comment": "null-13",
|
||||
"Rev": "5d3ddcf53a508cc2f7404eaebf546ef2cb5cdb6e"
|
||||
},
|
||||
{
|
||||
"ImportPath": "code.google.com/p/go-uuid/uuid",
|
||||
"Comment": "null-12",
|
||||
"Rev": "7dda39b2e7d5e265014674c5af696ba4186679e9"
|
||||
},
|
||||
{
|
||||
"ImportPath": "code.google.com/p/snappy-go/snappy",
|
||||
"Comment": "null-15",
|
||||
"Rev": "12e4b4183793ac4b061921e7980845e750679fd0"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/ethereum/serpent-go",
|
||||
"Rev": "5767a0dbd759d313df3f404dadb7f98d7ab51443"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/howeyc/fsnotify",
|
||||
"Comment": "v0.9.0-11-g6b1ef89",
|
||||
"Rev": "6b1ef893dc11e0447abda6da20a5203481878dda"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/huin/goupnp",
|
||||
"Rev": "4191d8a85005844ea202fde52799681971b12dfe"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/jackpal/go-nat-pmp",
|
||||
"Rev": "a45aa3d54aef73b504e15eb71bea0e5565b5e6e1"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/obscuren/otto",
|
||||
"Rev": "cf13cc4228c5e5ce0fe27a7aea90bc10091c4f19"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/obscuren/qml",
|
||||
"Rev": "c288002b52e905973b131089a8a7c761d4a2c36a"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/rakyll/globalconf",
|
||||
"Rev": "415abc325023f1a00cd2d9fa512e0e71745791a2"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/rakyll/goini",
|
||||
"Rev": "907cca0f578a5316fb864ec6992dc3d9730ec58c"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/robertkrimen/otto/ast",
|
||||
"Rev": "dea31a3d392779af358ec41f77a07fcc7e9d04ba"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/robertkrimen/otto/dbg",
|
||||
"Rev": "dea31a3d392779af358ec41f77a07fcc7e9d04ba"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/robertkrimen/otto/file",
|
||||
"Rev": "dea31a3d392779af358ec41f77a07fcc7e9d04ba"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/robertkrimen/otto/parser",
|
||||
"Rev": "dea31a3d392779af358ec41f77a07fcc7e9d04ba"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/robertkrimen/otto/registry",
|
||||
"Rev": "dea31a3d392779af358ec41f77a07fcc7e9d04ba"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/robertkrimen/otto/token",
|
||||
"Rev": "dea31a3d392779af358ec41f77a07fcc7e9d04ba"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/syndtr/goleveldb/leveldb",
|
||||
"Rev": "832fa7ed4d28545eab80f19e1831fc004305cade"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/crypto/pbkdf2",
|
||||
"Rev": "4ed45ec682102c643324fae5dff8dab085b6c300"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/crypto/ripemd160",
|
||||
"Rev": "4ed45ec682102c643324fae5dff8dab085b6c300"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/crypto/scrypt",
|
||||
"Rev": "4ed45ec682102c643324fae5dff8dab085b6c300"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/net/websocket",
|
||||
"Rev": "59b0df9b1f7abda5aab0495ee54f408daf182ce7"
|
||||
},
|
||||
{
|
||||
"ImportPath": "gopkg.in/check.v1",
|
||||
"Rev": "64131543e7896d5bcc6bd5a76287eb75ea96c673"
|
||||
},
|
||||
{
|
||||
"ImportPath": "gopkg.in/fatih/set.v0",
|
||||
"Comment": "v0.1.0-3-g27c4092",
|
||||
"Rev": "27c40922c40b43fe04554d8223a402af3ea333f3"
|
||||
},
|
||||
{
|
||||
"ImportPath": "gopkg.in/qml.v1/cdata",
|
||||
"Rev": "1116cb9cd8dee23f8d444ded354eb53122739f99"
|
||||
},
|
||||
{
|
||||
"ImportPath": "gopkg.in/qml.v1/gl/glbase",
|
||||
"Rev": "1116cb9cd8dee23f8d444ded354eb53122739f99"
|
||||
}
|
||||
]
|
||||
}
|
5
Godeps/Readme
generated
Normal file
5
Godeps/Readme
generated
Normal file
@ -0,0 +1,5 @@
|
||||
This directory tree is generated automatically by godep.
|
||||
|
||||
Please do not edit.
|
||||
|
||||
See https://github.com/tools/godep for more information.
|
2
Godeps/_workspace/.gitignore
generated
vendored
Normal file
2
Godeps/_workspace/.gitignore
generated
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
/pkg
|
||||
/bin
|
20
Godeps/_workspace/src/bitbucket.org/kardianos/osext/LICENSE
generated
vendored
Normal file
20
Godeps/_workspace/src/bitbucket.org/kardianos/osext/LICENSE
generated
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
Copyright (c) 2012 Daniel Theophanes
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
32
Godeps/_workspace/src/bitbucket.org/kardianos/osext/osext.go
generated
vendored
Normal file
32
Godeps/_workspace/src/bitbucket.org/kardianos/osext/osext.go
generated
vendored
Normal file
@ -0,0 +1,32 @@
|
||||
// Copyright 2012 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Extensions to the standard "os" package.
|
||||
package osext
|
||||
|
||||
import "path/filepath"
|
||||
|
||||
// Executable returns an absolute path that can be used to
|
||||
// re-invoke the current program.
|
||||
// It may not be valid after the current program exits.
|
||||
func Executable() (string, error) {
|
||||
p, err := executable()
|
||||
return filepath.Clean(p), err
|
||||
}
|
||||
|
||||
// Returns same path as Executable, returns just the folder
|
||||
// path. Excludes the executable name.
|
||||
func ExecutableFolder() (string, error) {
|
||||
p, err := Executable()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
folder, _ := filepath.Split(p)
|
||||
return folder, nil
|
||||
}
|
||||
|
||||
// Depricated. Same as Executable().
|
||||
func GetExePath() (exePath string, err error) {
|
||||
return Executable()
|
||||
}
|
20
Godeps/_workspace/src/bitbucket.org/kardianos/osext/osext_plan9.go
generated
vendored
Normal file
20
Godeps/_workspace/src/bitbucket.org/kardianos/osext/osext_plan9.go
generated
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
// Copyright 2012 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package osext
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"os"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func executable() (string, error) {
|
||||
f, err := os.Open("/proc/" + strconv.Itoa(os.Getpid()) + "/text")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer f.Close()
|
||||
return syscall.Fd2path(int(f.Fd()))
|
||||
}
|
25
Godeps/_workspace/src/bitbucket.org/kardianos/osext/osext_procfs.go
generated
vendored
Normal file
25
Godeps/_workspace/src/bitbucket.org/kardianos/osext/osext_procfs.go
generated
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
// Copyright 2012 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build linux netbsd openbsd
|
||||
|
||||
package osext
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
func executable() (string, error) {
|
||||
switch runtime.GOOS {
|
||||
case "linux":
|
||||
return os.Readlink("/proc/self/exe")
|
||||
case "netbsd":
|
||||
return os.Readlink("/proc/curproc/exe")
|
||||
case "openbsd":
|
||||
return os.Readlink("/proc/curproc/file")
|
||||
}
|
||||
return "", errors.New("ExecPath not implemented for " + runtime.GOOS)
|
||||
}
|
79
Godeps/_workspace/src/bitbucket.org/kardianos/osext/osext_sysctl.go
generated
vendored
Normal file
79
Godeps/_workspace/src/bitbucket.org/kardianos/osext/osext_sysctl.go
generated
vendored
Normal file
@ -0,0 +1,79 @@
|
||||
// Copyright 2012 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build darwin freebsd
|
||||
|
||||
package osext
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
var initCwd, initCwdErr = os.Getwd()
|
||||
|
||||
func executable() (string, error) {
|
||||
var mib [4]int32
|
||||
switch runtime.GOOS {
|
||||
case "freebsd":
|
||||
mib = [4]int32{1 /* CTL_KERN */, 14 /* KERN_PROC */, 12 /* KERN_PROC_PATHNAME */, -1}
|
||||
case "darwin":
|
||||
mib = [4]int32{1 /* CTL_KERN */, 38 /* KERN_PROCARGS */, int32(os.Getpid()), -1}
|
||||
}
|
||||
|
||||
n := uintptr(0)
|
||||
// Get length.
|
||||
_, _, errNum := syscall.Syscall6(syscall.SYS___SYSCTL, uintptr(unsafe.Pointer(&mib[0])), 4, 0, uintptr(unsafe.Pointer(&n)), 0, 0)
|
||||
if errNum != 0 {
|
||||
return "", errNum
|
||||
}
|
||||
if n == 0 { // This shouldn't happen.
|
||||
return "", nil
|
||||
}
|
||||
buf := make([]byte, n)
|
||||
_, _, errNum = syscall.Syscall6(syscall.SYS___SYSCTL, uintptr(unsafe.Pointer(&mib[0])), 4, uintptr(unsafe.Pointer(&buf[0])), uintptr(unsafe.Pointer(&n)), 0, 0)
|
||||
if errNum != 0 {
|
||||
return "", errNum
|
||||
}
|
||||
if n == 0 { // This shouldn't happen.
|
||||
return "", nil
|
||||
}
|
||||
for i, v := range buf {
|
||||
if v == 0 {
|
||||
buf = buf[:i]
|
||||
break
|
||||
}
|
||||
}
|
||||
var err error
|
||||
execPath := string(buf)
|
||||
// execPath will not be empty due to above checks.
|
||||
// Try to get the absolute path if the execPath is not rooted.
|
||||
if execPath[0] != '/' {
|
||||
execPath, err = getAbs(execPath)
|
||||
if err != nil {
|
||||
return execPath, err
|
||||
}
|
||||
}
|
||||
// For darwin KERN_PROCARGS may return the path to a symlink rather than the
|
||||
// actual executable.
|
||||
if runtime.GOOS == "darwin" {
|
||||
if execPath, err = filepath.EvalSymlinks(execPath); err != nil {
|
||||
return execPath, err
|
||||
}
|
||||
}
|
||||
return execPath, nil
|
||||
}
|
||||
|
||||
func getAbs(execPath string) (string, error) {
|
||||
if initCwdErr != nil {
|
||||
return execPath, initCwdErr
|
||||
}
|
||||
// The execPath may begin with a "../" or a "./" so clean it first.
|
||||
// Join the two paths, trailing and starting slashes undetermined, so use
|
||||
// the generic Join function.
|
||||
return filepath.Join(initCwd, filepath.Clean(execPath)), nil
|
||||
}
|
79
Godeps/_workspace/src/bitbucket.org/kardianos/osext/osext_test.go
generated
vendored
Normal file
79
Godeps/_workspace/src/bitbucket.org/kardianos/osext/osext_test.go
generated
vendored
Normal file
@ -0,0 +1,79 @@
|
||||
// Copyright 2012 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build darwin linux freebsd netbsd windows
|
||||
|
||||
package osext
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
oexec "os/exec"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"testing"
|
||||
)
|
||||
|
||||
const execPath_EnvVar = "OSTEST_OUTPUT_EXECPATH"
|
||||
|
||||
func TestExecPath(t *testing.T) {
|
||||
ep, err := Executable()
|
||||
if err != nil {
|
||||
t.Fatalf("ExecPath failed: %v", err)
|
||||
}
|
||||
// we want fn to be of the form "dir/prog"
|
||||
dir := filepath.Dir(filepath.Dir(ep))
|
||||
fn, err := filepath.Rel(dir, ep)
|
||||
if err != nil {
|
||||
t.Fatalf("filepath.Rel: %v", err)
|
||||
}
|
||||
cmd := &oexec.Cmd{}
|
||||
// make child start with a relative program path
|
||||
cmd.Dir = dir
|
||||
cmd.Path = fn
|
||||
// forge argv[0] for child, so that we can verify we could correctly
|
||||
// get real path of the executable without influenced by argv[0].
|
||||
cmd.Args = []string{"-", "-test.run=XXXX"}
|
||||
cmd.Env = []string{fmt.Sprintf("%s=1", execPath_EnvVar)}
|
||||
out, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
t.Fatalf("exec(self) failed: %v", err)
|
||||
}
|
||||
outs := string(out)
|
||||
if !filepath.IsAbs(outs) {
|
||||
t.Fatalf("Child returned %q, want an absolute path", out)
|
||||
}
|
||||
if !sameFile(outs, ep) {
|
||||
t.Fatalf("Child returned %q, not the same file as %q", out, ep)
|
||||
}
|
||||
}
|
||||
|
||||
func sameFile(fn1, fn2 string) bool {
|
||||
fi1, err := os.Stat(fn1)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
fi2, err := os.Stat(fn2)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return os.SameFile(fi1, fi2)
|
||||
}
|
||||
|
||||
func init() {
|
||||
if e := os.Getenv(execPath_EnvVar); e != "" {
|
||||
// first chdir to another path
|
||||
dir := "/"
|
||||
if runtime.GOOS == "windows" {
|
||||
dir = filepath.VolumeName(".")
|
||||
}
|
||||
os.Chdir(dir)
|
||||
if ep, err := Executable(); err != nil {
|
||||
fmt.Fprint(os.Stderr, "ERROR: ", err)
|
||||
} else {
|
||||
fmt.Fprint(os.Stderr, ep)
|
||||
}
|
||||
os.Exit(0)
|
||||
}
|
||||
}
|
34
Godeps/_workspace/src/bitbucket.org/kardianos/osext/osext_windows.go
generated
vendored
Normal file
34
Godeps/_workspace/src/bitbucket.org/kardianos/osext/osext_windows.go
generated
vendored
Normal file
@ -0,0 +1,34 @@
|
||||
// Copyright 2012 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package osext
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"unicode/utf16"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
var (
|
||||
kernel = syscall.MustLoadDLL("kernel32.dll")
|
||||
getModuleFileNameProc = kernel.MustFindProc("GetModuleFileNameW")
|
||||
)
|
||||
|
||||
// GetModuleFileName() with hModule = NULL
|
||||
func executable() (exePath string, err error) {
|
||||
return getModuleFileName()
|
||||
}
|
||||
|
||||
func getModuleFileName() (string, error) {
|
||||
var n uint32
|
||||
b := make([]uint16, syscall.MAX_PATH)
|
||||
size := uint32(len(b))
|
||||
|
||||
r0, _, e1 := getModuleFileNameProc.Call(0, uintptr(unsafe.Pointer(&b[0])), uintptr(size))
|
||||
n = uint32(r0)
|
||||
if n == 0 {
|
||||
return "", e1
|
||||
}
|
||||
return string(utf16.Decode(b[0:n])), nil
|
||||
}
|
27
Godeps/_workspace/src/code.google.com/p/go-uuid/uuid/LICENSE
generated
vendored
Normal file
27
Godeps/_workspace/src/code.google.com/p/go-uuid/uuid/LICENSE
generated
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
Copyright (c) 2009 Google Inc. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
84
Godeps/_workspace/src/code.google.com/p/go-uuid/uuid/dce.go
generated
vendored
Normal file
84
Godeps/_workspace/src/code.google.com/p/go-uuid/uuid/dce.go
generated
vendored
Normal file
@ -0,0 +1,84 @@
|
||||
// Copyright 2011 Google Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package uuid
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
// A Domain represents a Version 2 domain
|
||||
type Domain byte
|
||||
|
||||
// Domain constants for DCE Security (Version 2) UUIDs.
|
||||
const (
|
||||
Person = Domain(0)
|
||||
Group = Domain(1)
|
||||
Org = Domain(2)
|
||||
)
|
||||
|
||||
// NewDCESecurity returns a DCE Security (Version 2) UUID.
|
||||
//
|
||||
// The domain should be one of Person, Group or Org.
|
||||
// On a POSIX system the id should be the users UID for the Person
|
||||
// domain and the users GID for the Group. The meaning of id for
|
||||
// the domain Org or on non-POSIX systems is site defined.
|
||||
//
|
||||
// For a given domain/id pair the same token may be returned for up to
|
||||
// 7 minutes and 10 seconds.
|
||||
func NewDCESecurity(domain Domain, id uint32) UUID {
|
||||
uuid := NewUUID()
|
||||
if uuid != nil {
|
||||
uuid[6] = (uuid[6] & 0x0f) | 0x20 // Version 2
|
||||
uuid[9] = byte(domain)
|
||||
binary.BigEndian.PutUint32(uuid[0:], id)
|
||||
}
|
||||
return uuid
|
||||
}
|
||||
|
||||
// NewDCEPerson returns a DCE Security (Version 2) UUID in the person
|
||||
// domain with the id returned by os.Getuid.
|
||||
//
|
||||
// NewDCEPerson(Person, uint32(os.Getuid()))
|
||||
func NewDCEPerson() UUID {
|
||||
return NewDCESecurity(Person, uint32(os.Getuid()))
|
||||
}
|
||||
|
||||
// NewDCEGroup returns a DCE Security (Version 2) UUID in the group
|
||||
// domain with the id returned by os.Getgid.
|
||||
//
|
||||
// NewDCEGroup(Group, uint32(os.Getgid()))
|
||||
func NewDCEGroup() UUID {
|
||||
return NewDCESecurity(Group, uint32(os.Getgid()))
|
||||
}
|
||||
|
||||
// Domain returns the domain for a Version 2 UUID or false.
|
||||
func (uuid UUID) Domain() (Domain, bool) {
|
||||
if v, _ := uuid.Version(); v != 2 {
|
||||
return 0, false
|
||||
}
|
||||
return Domain(uuid[9]), true
|
||||
}
|
||||
|
||||
// Id returns the id for a Version 2 UUID or false.
|
||||
func (uuid UUID) Id() (uint32, bool) {
|
||||
if v, _ := uuid.Version(); v != 2 {
|
||||
return 0, false
|
||||
}
|
||||
return binary.BigEndian.Uint32(uuid[0:4]), true
|
||||
}
|
||||
|
||||
func (d Domain) String() string {
|
||||
switch d {
|
||||
case Person:
|
||||
return "Person"
|
||||
case Group:
|
||||
return "Group"
|
||||
case Org:
|
||||
return "Org"
|
||||
}
|
||||
return fmt.Sprintf("Domain%d", int(d))
|
||||
}
|
8
Godeps/_workspace/src/code.google.com/p/go-uuid/uuid/doc.go
generated
vendored
Normal file
8
Godeps/_workspace/src/code.google.com/p/go-uuid/uuid/doc.go
generated
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
// Copyright 2011 Google Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// The uuid package generates and inspects UUIDs.
|
||||
//
|
||||
// UUIDs are based on RFC 4122 and DCE 1.1: Authentication and Security Services.
|
||||
package uuid
|
53
Godeps/_workspace/src/code.google.com/p/go-uuid/uuid/hash.go
generated
vendored
Normal file
53
Godeps/_workspace/src/code.google.com/p/go-uuid/uuid/hash.go
generated
vendored
Normal file
@ -0,0 +1,53 @@
|
||||
// Copyright 2011 Google Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package uuid
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"crypto/sha1"
|
||||
"hash"
|
||||
)
|
||||
|
||||
// Well known Name Space IDs and UUIDs
|
||||
var (
|
||||
NameSpace_DNS = Parse("6ba7b810-9dad-11d1-80b4-00c04fd430c8")
|
||||
NameSpace_URL = Parse("6ba7b811-9dad-11d1-80b4-00c04fd430c8")
|
||||
NameSpace_OID = Parse("6ba7b812-9dad-11d1-80b4-00c04fd430c8")
|
||||
NameSpace_X500 = Parse("6ba7b814-9dad-11d1-80b4-00c04fd430c8")
|
||||
NIL = Parse("00000000-0000-0000-0000-000000000000")
|
||||
)
|
||||
|
||||
// NewHash returns a new UUID dervied from the hash of space concatenated with
|
||||
// data generated by h. The hash should be at least 16 byte in length. The
|
||||
// first 16 bytes of the hash are used to form the UUID. The version of the
|
||||
// UUID will be the lower 4 bits of version. NewHash is used to implement
|
||||
// NewMD5 and NewSHA1.
|
||||
func NewHash(h hash.Hash, space UUID, data []byte, version int) UUID {
|
||||
h.Reset()
|
||||
h.Write(space)
|
||||
h.Write([]byte(data))
|
||||
s := h.Sum(nil)
|
||||
uuid := make([]byte, 16)
|
||||
copy(uuid, s)
|
||||
uuid[6] = (uuid[6] & 0x0f) | uint8((version&0xf)<<4)
|
||||
uuid[8] = (uuid[8] & 0x3f) | 0x80 // RFC 4122 variant
|
||||
return uuid
|
||||
}
|
||||
|
||||
// NewMD5 returns a new MD5 (Version 3) UUID based on the
|
||||
// supplied name space and data.
|
||||
//
|
||||
// NewHash(md5.New(), space, data, 3)
|
||||
func NewMD5(space UUID, data []byte) UUID {
|
||||
return NewHash(md5.New(), space, data, 3)
|
||||
}
|
||||
|
||||
// NewSHA1 returns a new SHA1 (Version 5) UUID based on the
|
||||
// supplied name space and data.
|
||||
//
|
||||
// NewHash(sha1.New(), space, data, 5)
|
||||
func NewSHA1(space UUID, data []byte) UUID {
|
||||
return NewHash(sha1.New(), space, data, 5)
|
||||
}
|
101
Godeps/_workspace/src/code.google.com/p/go-uuid/uuid/node.go
generated
vendored
Normal file
101
Godeps/_workspace/src/code.google.com/p/go-uuid/uuid/node.go
generated
vendored
Normal file
@ -0,0 +1,101 @@
|
||||
// Copyright 2011 Google Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package uuid
|
||||
|
||||
import "net"
|
||||
|
||||
var (
|
||||
interfaces []net.Interface // cached list of interfaces
|
||||
ifname string // name of interface being used
|
||||
nodeID []byte // hardware for version 1 UUIDs
|
||||
)
|
||||
|
||||
// NodeInterface returns the name of the interface from which the NodeID was
|
||||
// derived. The interface "user" is returned if the NodeID was set by
|
||||
// SetNodeID.
|
||||
func NodeInterface() string {
|
||||
return ifname
|
||||
}
|
||||
|
||||
// SetNodeInterface selects the hardware address to be used for Version 1 UUIDs.
|
||||
// If name is "" then the first usable interface found will be used or a random
|
||||
// Node ID will be generated. If a named interface cannot be found then false
|
||||
// is returned.
|
||||
//
|
||||
// SetNodeInterface never fails when name is "".
|
||||
func SetNodeInterface(name string) bool {
|
||||
if interfaces == nil {
|
||||
var err error
|
||||
interfaces, err = net.Interfaces()
|
||||
if err != nil && name != "" {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
for _, ifs := range interfaces {
|
||||
if len(ifs.HardwareAddr) >= 6 && (name == "" || name == ifs.Name) {
|
||||
if setNodeID(ifs.HardwareAddr) {
|
||||
ifname = ifs.Name
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We found no interfaces with a valid hardware address. If name
|
||||
// does not specify a specific interface generate a random Node ID
|
||||
// (section 4.1.6)
|
||||
if name == "" {
|
||||
if nodeID == nil {
|
||||
nodeID = make([]byte, 6)
|
||||
}
|
||||
randomBits(nodeID)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// NodeID returns a slice of a copy of the current Node ID, setting the Node ID
|
||||
// if not already set.
|
||||
func NodeID() []byte {
|
||||
if nodeID == nil {
|
||||
SetNodeInterface("")
|
||||
}
|
||||
nid := make([]byte, 6)
|
||||
copy(nid, nodeID)
|
||||
return nid
|
||||
}
|
||||
|
||||
// SetNodeID sets the Node ID to be used for Version 1 UUIDs. The first 6 bytes
|
||||
// of id are used. If id is less than 6 bytes then false is returned and the
|
||||
// Node ID is not set.
|
||||
func SetNodeID(id []byte) bool {
|
||||
if setNodeID(id) {
|
||||
ifname = "user"
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func setNodeID(id []byte) bool {
|
||||
if len(id) < 6 {
|
||||
return false
|
||||
}
|
||||
if nodeID == nil {
|
||||
nodeID = make([]byte, 6)
|
||||
}
|
||||
copy(nodeID, id)
|
||||
return true
|
||||
}
|
||||
|
||||
// NodeID returns the 6 byte node id encoded in uuid. It returns nil if uuid is
|
||||
// not valid. The NodeID is only well defined for version 1 and 2 UUIDs.
|
||||
func (uuid UUID) NodeID() []byte {
|
||||
if len(uuid) != 16 {
|
||||
return nil
|
||||
}
|
||||
node := make([]byte, 6)
|
||||
copy(node, uuid[10:])
|
||||
return node
|
||||
}
|
132
Godeps/_workspace/src/code.google.com/p/go-uuid/uuid/time.go
generated
vendored
Normal file
132
Godeps/_workspace/src/code.google.com/p/go-uuid/uuid/time.go
generated
vendored
Normal file
@ -0,0 +1,132 @@
|
||||
// Copyright 2014 Google Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package uuid
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// A Time represents a time as the number of 100's of nanoseconds since 15 Oct
|
||||
// 1582.
|
||||
type Time int64
|
||||
|
||||
const (
|
||||
lillian = 2299160 // Julian day of 15 Oct 1582
|
||||
unix = 2440587 // Julian day of 1 Jan 1970
|
||||
epoch = unix - lillian // Days between epochs
|
||||
g1582 = epoch * 86400 // seconds between epochs
|
||||
g1582ns100 = g1582 * 10000000 // 100s of a nanoseconds between epochs
|
||||
)
|
||||
|
||||
var (
|
||||
mu sync.Mutex
|
||||
lasttime uint64 // last time we returned
|
||||
clock_seq uint16 // clock sequence for this run
|
||||
|
||||
timeNow = time.Now // for testing
|
||||
)
|
||||
|
||||
// UnixTime converts t the number of seconds and nanoseconds using the Unix
|
||||
// epoch of 1 Jan 1970.
|
||||
func (t Time) UnixTime() (sec, nsec int64) {
|
||||
sec = int64(t - g1582ns100)
|
||||
nsec = (sec % 10000000) * 100
|
||||
sec /= 10000000
|
||||
return sec, nsec
|
||||
}
|
||||
|
||||
// GetTime returns the current Time (100s of nanoseconds since 15 Oct 1582) and
|
||||
// adjusts the clock sequence as needed. An error is returned if the current
|
||||
// time cannot be determined.
|
||||
func GetTime() (Time, error) {
|
||||
defer mu.Unlock()
|
||||
mu.Lock()
|
||||
return getTime()
|
||||
}
|
||||
|
||||
func getTime() (Time, error) {
|
||||
t := timeNow()
|
||||
|
||||
// If we don't have a clock sequence already, set one.
|
||||
if clock_seq == 0 {
|
||||
setClockSequence(-1)
|
||||
}
|
||||
now := uint64(t.UnixNano()/100) + g1582ns100
|
||||
|
||||
// If time has gone backwards with this clock sequence then we
|
||||
// increment the clock sequence
|
||||
if now <= lasttime {
|
||||
clock_seq = ((clock_seq + 1) & 0x3fff) | 0x8000
|
||||
}
|
||||
lasttime = now
|
||||
return Time(now), nil
|
||||
}
|
||||
|
||||
// ClockSequence returns the current clock sequence, generating one if not
|
||||
// already set. The clock sequence is only used for Version 1 UUIDs.
|
||||
//
|
||||
// The uuid package does not use global static storage for the clock sequence or
|
||||
// the last time a UUID was generated. Unless SetClockSequence a new random
|
||||
// clock sequence is generated the first time a clock sequence is requested by
|
||||
// ClockSequence, GetTime, or NewUUID. (section 4.2.1.1) sequence is generated
|
||||
// for
|
||||
func ClockSequence() int {
|
||||
defer mu.Unlock()
|
||||
mu.Lock()
|
||||
return clockSequence()
|
||||
}
|
||||
|
||||
func clockSequence() int {
|
||||
if clock_seq == 0 {
|
||||
setClockSequence(-1)
|
||||
}
|
||||
return int(clock_seq & 0x3fff)
|
||||
}
|
||||
|
||||
// SetClockSeq sets the clock sequence to the lower 14 bits of seq. Setting to
|
||||
// -1 causes a new sequence to be generated.
|
||||
func SetClockSequence(seq int) {
|
||||
defer mu.Unlock()
|
||||
mu.Lock()
|
||||
setClockSequence(seq)
|
||||
}
|
||||
|
||||
func setClockSequence(seq int) {
|
||||
if seq == -1 {
|
||||
var b [2]byte
|
||||
randomBits(b[:]) // clock sequence
|
||||
seq = int(b[0])<<8 | int(b[1])
|
||||
}
|
||||
old_seq := clock_seq
|
||||
clock_seq = uint16(seq&0x3fff) | 0x8000 // Set our variant
|
||||
if old_seq != clock_seq {
|
||||
lasttime = 0
|
||||
}
|
||||
}
|
||||
|
||||
// Time returns the time in 100s of nanoseconds since 15 Oct 1582 encoded in
|
||||
// uuid. It returns false if uuid is not valid. The time is only well defined
|
||||
// for version 1 and 2 UUIDs.
|
||||
func (uuid UUID) Time() (Time, bool) {
|
||||
if len(uuid) != 16 {
|
||||
return 0, false
|
||||
}
|
||||
time := int64(binary.BigEndian.Uint32(uuid[0:4]))
|
||||
time |= int64(binary.BigEndian.Uint16(uuid[4:6])) << 32
|
||||
time |= int64(binary.BigEndian.Uint16(uuid[6:8])&0xfff) << 48
|
||||
return Time(time), true
|
||||
}
|
||||
|
||||
// ClockSequence returns the clock sequence encoded in uuid. It returns false
|
||||
// if uuid is not valid. The clock sequence is only well defined for version 1
|
||||
// and 2 UUIDs.
|
||||
func (uuid UUID) ClockSequence() (int, bool) {
|
||||
if len(uuid) != 16 {
|
||||
return 0, false
|
||||
}
|
||||
return int(binary.BigEndian.Uint16(uuid[8:10])) & 0x3fff, true
|
||||
}
|
43
Godeps/_workspace/src/code.google.com/p/go-uuid/uuid/util.go
generated
vendored
Normal file
43
Godeps/_workspace/src/code.google.com/p/go-uuid/uuid/util.go
generated
vendored
Normal file
@ -0,0 +1,43 @@
|
||||
// Copyright 2011 Google Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package uuid
|
||||
|
||||
import (
|
||||
"io"
|
||||
)
|
||||
|
||||
// randomBits completely fills slice b with random data.
|
||||
func randomBits(b []byte) {
|
||||
if _, err := io.ReadFull(rander, b); err != nil {
|
||||
panic(err.Error()) // rand should never fail
|
||||
}
|
||||
}
|
||||
|
||||
// xvalues returns the value of a byte as a hexadecimal digit or 255.
|
||||
var xvalues = []byte{
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 255, 255, 255, 255, 255, 255,
|
||||
255, 10, 11, 12, 13, 14, 15, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 10, 11, 12, 13, 14, 15, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
}
|
||||
|
||||
// xtob converts the the first two hex bytes of x into a byte.
|
||||
func xtob(x string) (byte, bool) {
|
||||
b1 := xvalues[x[0]]
|
||||
b2 := xvalues[x[1]]
|
||||
return (b1 << 4) | b2, b1 != 255 && b2 != 255
|
||||
}
|
163
Godeps/_workspace/src/code.google.com/p/go-uuid/uuid/uuid.go
generated
vendored
Normal file
163
Godeps/_workspace/src/code.google.com/p/go-uuid/uuid/uuid.go
generated
vendored
Normal file
@ -0,0 +1,163 @@
|
||||
// Copyright 2011 Google Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package uuid
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/rand"
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// A UUID is a 128 bit (16 byte) Universal Unique IDentifier as defined in RFC
|
||||
// 4122.
|
||||
type UUID []byte
|
||||
|
||||
// A Version represents a UUIDs version.
|
||||
type Version byte
|
||||
|
||||
// A Variant represents a UUIDs variant.
|
||||
type Variant byte
|
||||
|
||||
// Constants returned by Variant.
|
||||
const (
|
||||
Invalid = Variant(iota) // Invalid UUID
|
||||
RFC4122 // The variant specified in RFC4122
|
||||
Reserved // Reserved, NCS backward compatibility.
|
||||
Microsoft // Reserved, Microsoft Corporation backward compatibility.
|
||||
Future // Reserved for future definition.
|
||||
)
|
||||
|
||||
var rander = rand.Reader // random function
|
||||
|
||||
// New returns a new random (version 4) UUID as a string. It is a convenience
|
||||
// function for NewRandom().String().
|
||||
func New() string {
|
||||
return NewRandom().String()
|
||||
}
|
||||
|
||||
// Parse decodes s into a UUID or returns nil. Both the UUID form of
|
||||
// xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx and
|
||||
// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx are decoded.
|
||||
func Parse(s string) UUID {
|
||||
if len(s) == 36+9 {
|
||||
if strings.ToLower(s[:9]) != "urn:uuid:" {
|
||||
return nil
|
||||
}
|
||||
s = s[9:]
|
||||
} else if len(s) != 36 {
|
||||
return nil
|
||||
}
|
||||
if s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-' {
|
||||
return nil
|
||||
}
|
||||
uuid := make([]byte, 16)
|
||||
for i, x := range []int{
|
||||
0, 2, 4, 6,
|
||||
9, 11,
|
||||
14, 16,
|
||||
19, 21,
|
||||
24, 26, 28, 30, 32, 34} {
|
||||
if v, ok := xtob(s[x:]); !ok {
|
||||
return nil
|
||||
} else {
|
||||
uuid[i] = v
|
||||
}
|
||||
}
|
||||
return uuid
|
||||
}
|
||||
|
||||
// Equal returns true if uuid1 and uuid2 are equal.
|
||||
func Equal(uuid1, uuid2 UUID) bool {
|
||||
return bytes.Equal(uuid1, uuid2)
|
||||
}
|
||||
|
||||
// String returns the string form of uuid, xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
||||
// , or "" if uuid is invalid.
|
||||
func (uuid UUID) String() string {
|
||||
if uuid == nil || len(uuid) != 16 {
|
||||
return ""
|
||||
}
|
||||
b := []byte(uuid)
|
||||
return fmt.Sprintf("%08x-%04x-%04x-%04x-%012x",
|
||||
b[:4], b[4:6], b[6:8], b[8:10], b[10:])
|
||||
}
|
||||
|
||||
// URN returns the RFC 2141 URN form of uuid,
|
||||
// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx, or "" if uuid is invalid.
|
||||
func (uuid UUID) URN() string {
|
||||
if uuid == nil || len(uuid) != 16 {
|
||||
return ""
|
||||
}
|
||||
b := []byte(uuid)
|
||||
return fmt.Sprintf("urn:uuid:%08x-%04x-%04x-%04x-%012x",
|
||||
b[:4], b[4:6], b[6:8], b[8:10], b[10:])
|
||||
}
|
||||
|
||||
// Variant returns the variant encoded in uuid. It returns Invalid if
|
||||
// uuid is invalid.
|
||||
func (uuid UUID) Variant() Variant {
|
||||
if len(uuid) != 16 {
|
||||
return Invalid
|
||||
}
|
||||
switch {
|
||||
case (uuid[8] & 0xc0) == 0x80:
|
||||
return RFC4122
|
||||
case (uuid[8] & 0xe0) == 0xc0:
|
||||
return Microsoft
|
||||
case (uuid[8] & 0xe0) == 0xe0:
|
||||
return Future
|
||||
default:
|
||||
return Reserved
|
||||
}
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
// Version returns the verison of uuid. It returns false if uuid is not
|
||||
// valid.
|
||||
func (uuid UUID) Version() (Version, bool) {
|
||||
if len(uuid) != 16 {
|
||||
return 0, false
|
||||
}
|
||||
return Version(uuid[6] >> 4), true
|
||||
}
|
||||
|
||||
func (v Version) String() string {
|
||||
if v > 15 {
|
||||
return fmt.Sprintf("BAD_VERSION_%d", v)
|
||||
}
|
||||
return fmt.Sprintf("VERSION_%d", v)
|
||||
}
|
||||
|
||||
func (v Variant) String() string {
|
||||
switch v {
|
||||
case RFC4122:
|
||||
return "RFC4122"
|
||||
case Reserved:
|
||||
return "Reserved"
|
||||
case Microsoft:
|
||||
return "Microsoft"
|
||||
case Future:
|
||||
return "Future"
|
||||
case Invalid:
|
||||
return "Invalid"
|
||||
}
|
||||
return fmt.Sprintf("BadVariant%d", int(v))
|
||||
}
|
||||
|
||||
// SetRand sets the random number generator to r, which implents io.Reader.
|
||||
// If r.Read returns an error when the package requests random data then
|
||||
// a panic will be issued.
|
||||
//
|
||||
// Calling SetRand with nil sets the random number generator to the default
|
||||
// generator.
|
||||
func SetRand(r io.Reader) {
|
||||
if r == nil {
|
||||
rander = rand.Reader
|
||||
return
|
||||
}
|
||||
rander = r
|
||||
}
|
390
Godeps/_workspace/src/code.google.com/p/go-uuid/uuid/uuid_test.go
generated
vendored
Normal file
390
Godeps/_workspace/src/code.google.com/p/go-uuid/uuid/uuid_test.go
generated
vendored
Normal file
@ -0,0 +1,390 @@
|
||||
// Copyright 2011 Google Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package uuid
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
type test struct {
|
||||
in string
|
||||
version Version
|
||||
variant Variant
|
||||
isuuid bool
|
||||
}
|
||||
|
||||
var tests = []test{
|
||||
{"f47ac10b-58cc-0372-8567-0e02b2c3d479", 0, RFC4122, true},
|
||||
{"f47ac10b-58cc-1372-8567-0e02b2c3d479", 1, RFC4122, true},
|
||||
{"f47ac10b-58cc-2372-8567-0e02b2c3d479", 2, RFC4122, true},
|
||||
{"f47ac10b-58cc-3372-8567-0e02b2c3d479", 3, RFC4122, true},
|
||||
{"f47ac10b-58cc-4372-8567-0e02b2c3d479", 4, RFC4122, true},
|
||||
{"f47ac10b-58cc-5372-8567-0e02b2c3d479", 5, RFC4122, true},
|
||||
{"f47ac10b-58cc-6372-8567-0e02b2c3d479", 6, RFC4122, true},
|
||||
{"f47ac10b-58cc-7372-8567-0e02b2c3d479", 7, RFC4122, true},
|
||||
{"f47ac10b-58cc-8372-8567-0e02b2c3d479", 8, RFC4122, true},
|
||||
{"f47ac10b-58cc-9372-8567-0e02b2c3d479", 9, RFC4122, true},
|
||||
{"f47ac10b-58cc-a372-8567-0e02b2c3d479", 10, RFC4122, true},
|
||||
{"f47ac10b-58cc-b372-8567-0e02b2c3d479", 11, RFC4122, true},
|
||||
{"f47ac10b-58cc-c372-8567-0e02b2c3d479", 12, RFC4122, true},
|
||||
{"f47ac10b-58cc-d372-8567-0e02b2c3d479", 13, RFC4122, true},
|
||||
{"f47ac10b-58cc-e372-8567-0e02b2c3d479", 14, RFC4122, true},
|
||||
{"f47ac10b-58cc-f372-8567-0e02b2c3d479", 15, RFC4122, true},
|
||||
|
||||
{"urn:uuid:f47ac10b-58cc-4372-0567-0e02b2c3d479", 4, Reserved, true},
|
||||
{"URN:UUID:f47ac10b-58cc-4372-0567-0e02b2c3d479", 4, Reserved, true},
|
||||
{"f47ac10b-58cc-4372-0567-0e02b2c3d479", 4, Reserved, true},
|
||||
{"f47ac10b-58cc-4372-1567-0e02b2c3d479", 4, Reserved, true},
|
||||
{"f47ac10b-58cc-4372-2567-0e02b2c3d479", 4, Reserved, true},
|
||||
{"f47ac10b-58cc-4372-3567-0e02b2c3d479", 4, Reserved, true},
|
||||
{"f47ac10b-58cc-4372-4567-0e02b2c3d479", 4, Reserved, true},
|
||||
{"f47ac10b-58cc-4372-5567-0e02b2c3d479", 4, Reserved, true},
|
||||
{"f47ac10b-58cc-4372-6567-0e02b2c3d479", 4, Reserved, true},
|
||||
{"f47ac10b-58cc-4372-7567-0e02b2c3d479", 4, Reserved, true},
|
||||
{"f47ac10b-58cc-4372-8567-0e02b2c3d479", 4, RFC4122, true},
|
||||
{"f47ac10b-58cc-4372-9567-0e02b2c3d479", 4, RFC4122, true},
|
||||
{"f47ac10b-58cc-4372-a567-0e02b2c3d479", 4, RFC4122, true},
|
||||
{"f47ac10b-58cc-4372-b567-0e02b2c3d479", 4, RFC4122, true},
|
||||
{"f47ac10b-58cc-4372-c567-0e02b2c3d479", 4, Microsoft, true},
|
||||
{"f47ac10b-58cc-4372-d567-0e02b2c3d479", 4, Microsoft, true},
|
||||
{"f47ac10b-58cc-4372-e567-0e02b2c3d479", 4, Future, true},
|
||||
{"f47ac10b-58cc-4372-f567-0e02b2c3d479", 4, Future, true},
|
||||
|
||||
{"f47ac10b158cc-5372-a567-0e02b2c3d479", 0, Invalid, false},
|
||||
{"f47ac10b-58cc25372-a567-0e02b2c3d479", 0, Invalid, false},
|
||||
{"f47ac10b-58cc-53723a567-0e02b2c3d479", 0, Invalid, false},
|
||||
{"f47ac10b-58cc-5372-a56740e02b2c3d479", 0, Invalid, false},
|
||||
{"f47ac10b-58cc-5372-a567-0e02-2c3d479", 0, Invalid, false},
|
||||
{"g47ac10b-58cc-4372-a567-0e02b2c3d479", 0, Invalid, false},
|
||||
}
|
||||
|
||||
var constants = []struct {
|
||||
c interface{}
|
||||
name string
|
||||
}{
|
||||
{Person, "Person"},
|
||||
{Group, "Group"},
|
||||
{Org, "Org"},
|
||||
{Invalid, "Invalid"},
|
||||
{RFC4122, "RFC4122"},
|
||||
{Reserved, "Reserved"},
|
||||
{Microsoft, "Microsoft"},
|
||||
{Future, "Future"},
|
||||
{Domain(17), "Domain17"},
|
||||
{Variant(42), "BadVariant42"},
|
||||
}
|
||||
|
||||
func testTest(t *testing.T, in string, tt test) {
|
||||
uuid := Parse(in)
|
||||
if ok := (uuid != nil); ok != tt.isuuid {
|
||||
t.Errorf("Parse(%s) got %v expected %v\b", in, ok, tt.isuuid)
|
||||
}
|
||||
if uuid == nil {
|
||||
return
|
||||
}
|
||||
|
||||
if v := uuid.Variant(); v != tt.variant {
|
||||
t.Errorf("Variant(%s) got %d expected %d\b", in, v, tt.variant)
|
||||
}
|
||||
if v, _ := uuid.Version(); v != tt.version {
|
||||
t.Errorf("Version(%s) got %d expected %d\b", in, v, tt.version)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUUID(t *testing.T) {
|
||||
for _, tt := range tests {
|
||||
testTest(t, tt.in, tt)
|
||||
testTest(t, strings.ToUpper(tt.in), tt)
|
||||
}
|
||||
}
|
||||
|
||||
func TestConstants(t *testing.T) {
|
||||
for x, tt := range constants {
|
||||
v, ok := tt.c.(fmt.Stringer)
|
||||
if !ok {
|
||||
t.Errorf("%x: %v: not a stringer", x, v)
|
||||
} else if s := v.String(); s != tt.name {
|
||||
v, _ := tt.c.(int)
|
||||
t.Errorf("%x: Constant %T:%d gives %q, expected %q\n", x, tt.c, v, s, tt.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRandomUUID(t *testing.T) {
|
||||
m := make(map[string]bool)
|
||||
for x := 1; x < 32; x++ {
|
||||
uuid := NewRandom()
|
||||
s := uuid.String()
|
||||
if m[s] {
|
||||
t.Errorf("NewRandom returned duplicated UUID %s\n", s)
|
||||
}
|
||||
m[s] = true
|
||||
if v, _ := uuid.Version(); v != 4 {
|
||||
t.Errorf("Random UUID of version %s\n", v)
|
||||
}
|
||||
if uuid.Variant() != RFC4122 {
|
||||
t.Errorf("Random UUID is variant %d\n", uuid.Variant())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestNew(t *testing.T) {
|
||||
m := make(map[string]bool)
|
||||
for x := 1; x < 32; x++ {
|
||||
s := New()
|
||||
if m[s] {
|
||||
t.Errorf("New returned duplicated UUID %s\n", s)
|
||||
}
|
||||
m[s] = true
|
||||
uuid := Parse(s)
|
||||
if uuid == nil {
|
||||
t.Errorf("New returned %q which does not decode\n", s)
|
||||
continue
|
||||
}
|
||||
if v, _ := uuid.Version(); v != 4 {
|
||||
t.Errorf("Random UUID of version %s\n", v)
|
||||
}
|
||||
if uuid.Variant() != RFC4122 {
|
||||
t.Errorf("Random UUID is variant %d\n", uuid.Variant())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func clockSeq(t *testing.T, uuid UUID) int {
|
||||
seq, ok := uuid.ClockSequence()
|
||||
if !ok {
|
||||
t.Fatalf("%s: invalid clock sequence\n", uuid)
|
||||
}
|
||||
return seq
|
||||
}
|
||||
|
||||
func TestClockSeq(t *testing.T) {
|
||||
// Fake time.Now for this test to return a monotonically advancing time; restore it at end.
|
||||
defer func(orig func() time.Time) { timeNow = orig }(timeNow)
|
||||
monTime := time.Now()
|
||||
timeNow = func() time.Time {
|
||||
monTime = monTime.Add(1 * time.Second)
|
||||
return monTime
|
||||
}
|
||||
|
||||
SetClockSequence(-1)
|
||||
uuid1 := NewUUID()
|
||||
uuid2 := NewUUID()
|
||||
|
||||
if clockSeq(t, uuid1) != clockSeq(t, uuid2) {
|
||||
t.Errorf("clock sequence %d != %d\n", clockSeq(t, uuid1), clockSeq(t, uuid2))
|
||||
}
|
||||
|
||||
SetClockSequence(-1)
|
||||
uuid2 = NewUUID()
|
||||
|
||||
// Just on the very off chance we generated the same sequence
|
||||
// two times we try again.
|
||||
if clockSeq(t, uuid1) == clockSeq(t, uuid2) {
|
||||
SetClockSequence(-1)
|
||||
uuid2 = NewUUID()
|
||||
}
|
||||
if clockSeq(t, uuid1) == clockSeq(t, uuid2) {
|
||||
t.Errorf("Duplicate clock sequence %d\n", clockSeq(t, uuid1))
|
||||
}
|
||||
|
||||
SetClockSequence(0x1234)
|
||||
uuid1 = NewUUID()
|
||||
if seq := clockSeq(t, uuid1); seq != 0x1234 {
|
||||
t.Errorf("%s: expected seq 0x1234 got 0x%04x\n", uuid1, seq)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCoding(t *testing.T) {
|
||||
text := "7d444840-9dc0-11d1-b245-5ffdce74fad2"
|
||||
urn := "urn:uuid:7d444840-9dc0-11d1-b245-5ffdce74fad2"
|
||||
data := UUID{
|
||||
0x7d, 0x44, 0x48, 0x40,
|
||||
0x9d, 0xc0,
|
||||
0x11, 0xd1,
|
||||
0xb2, 0x45,
|
||||
0x5f, 0xfd, 0xce, 0x74, 0xfa, 0xd2,
|
||||
}
|
||||
if v := data.String(); v != text {
|
||||
t.Errorf("%x: encoded to %s, expected %s\n", data, v, text)
|
||||
}
|
||||
if v := data.URN(); v != urn {
|
||||
t.Errorf("%x: urn is %s, expected %s\n", data, v, urn)
|
||||
}
|
||||
|
||||
uuid := Parse(text)
|
||||
if !Equal(uuid, data) {
|
||||
t.Errorf("%s: decoded to %s, expected %s\n", text, uuid, data)
|
||||
}
|
||||
}
|
||||
|
||||
func TestVersion1(t *testing.T) {
|
||||
uuid1 := NewUUID()
|
||||
uuid2 := NewUUID()
|
||||
|
||||
if Equal(uuid1, uuid2) {
|
||||
t.Errorf("%s:duplicate uuid\n", uuid1)
|
||||
}
|
||||
if v, _ := uuid1.Version(); v != 1 {
|
||||
t.Errorf("%s: version %s expected 1\n", uuid1, v)
|
||||
}
|
||||
if v, _ := uuid2.Version(); v != 1 {
|
||||
t.Errorf("%s: version %s expected 1\n", uuid2, v)
|
||||
}
|
||||
n1 := uuid1.NodeID()
|
||||
n2 := uuid2.NodeID()
|
||||
if !bytes.Equal(n1, n2) {
|
||||
t.Errorf("Different nodes %x != %x\n", n1, n2)
|
||||
}
|
||||
t1, ok := uuid1.Time()
|
||||
if !ok {
|
||||
t.Errorf("%s: invalid time\n", uuid1)
|
||||
}
|
||||
t2, ok := uuid2.Time()
|
||||
if !ok {
|
||||
t.Errorf("%s: invalid time\n", uuid2)
|
||||
}
|
||||
q1, ok := uuid1.ClockSequence()
|
||||
if !ok {
|
||||
t.Errorf("%s: invalid clock sequence\n", uuid1)
|
||||
}
|
||||
q2, ok := uuid2.ClockSequence()
|
||||
if !ok {
|
||||
t.Errorf("%s: invalid clock sequence", uuid2)
|
||||
}
|
||||
|
||||
switch {
|
||||
case t1 == t2 && q1 == q2:
|
||||
t.Errorf("time stopped\n")
|
||||
case t1 > t2 && q1 == q2:
|
||||
t.Errorf("time reversed\n")
|
||||
case t1 < t2 && q1 != q2:
|
||||
t.Errorf("clock sequence chaned unexpectedly\n")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNodeAndTime(t *testing.T) {
|
||||
// Time is February 5, 1998 12:30:23.136364800 AM GMT
|
||||
|
||||
uuid := Parse("7d444840-9dc0-11d1-b245-5ffdce74fad2")
|
||||
node := []byte{0x5f, 0xfd, 0xce, 0x74, 0xfa, 0xd2}
|
||||
|
||||
ts, ok := uuid.Time()
|
||||
if ok {
|
||||
c := time.Unix(ts.UnixTime())
|
||||
want := time.Date(1998, 2, 5, 0, 30, 23, 136364800, time.UTC)
|
||||
if !c.Equal(want) {
|
||||
t.Errorf("Got time %v, want %v", c, want)
|
||||
}
|
||||
} else {
|
||||
t.Errorf("%s: bad time\n", uuid)
|
||||
}
|
||||
if !bytes.Equal(node, uuid.NodeID()) {
|
||||
t.Errorf("Expected node %v got %v\n", node, uuid.NodeID())
|
||||
}
|
||||
}
|
||||
|
||||
func TestMD5(t *testing.T) {
|
||||
uuid := NewMD5(NameSpace_DNS, []byte("python.org")).String()
|
||||
want := "6fa459ea-ee8a-3ca4-894e-db77e160355e"
|
||||
if uuid != want {
|
||||
t.Errorf("MD5: got %q expected %q\n", uuid, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSHA1(t *testing.T) {
|
||||
uuid := NewSHA1(NameSpace_DNS, []byte("python.org")).String()
|
||||
want := "886313e1-3b8a-5372-9b90-0c9aee199e5d"
|
||||
if uuid != want {
|
||||
t.Errorf("SHA1: got %q expected %q\n", uuid, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNodeID(t *testing.T) {
|
||||
nid := []byte{1, 2, 3, 4, 5, 6}
|
||||
SetNodeInterface("")
|
||||
s := NodeInterface()
|
||||
if s == "" || s == "user" {
|
||||
t.Errorf("NodeInterface %q after SetInteface\n", s)
|
||||
}
|
||||
node1 := NodeID()
|
||||
if node1 == nil {
|
||||
t.Errorf("NodeID nil after SetNodeInterface\n", s)
|
||||
}
|
||||
SetNodeID(nid)
|
||||
s = NodeInterface()
|
||||
if s != "user" {
|
||||
t.Errorf("Expected NodeInterface %q got %q\n", "user", s)
|
||||
}
|
||||
node2 := NodeID()
|
||||
if node2 == nil {
|
||||
t.Errorf("NodeID nil after SetNodeID\n", s)
|
||||
}
|
||||
if bytes.Equal(node1, node2) {
|
||||
t.Errorf("NodeID not changed after SetNodeID\n", s)
|
||||
} else if !bytes.Equal(nid, node2) {
|
||||
t.Errorf("NodeID is %x, expected %x\n", node2, nid)
|
||||
}
|
||||
}
|
||||
|
||||
func testDCE(t *testing.T, name string, uuid UUID, domain Domain, id uint32) {
|
||||
if uuid == nil {
|
||||
t.Errorf("%s failed\n", name)
|
||||
return
|
||||
}
|
||||
if v, _ := uuid.Version(); v != 2 {
|
||||
t.Errorf("%s: %s: expected version 2, got %s\n", name, uuid, v)
|
||||
return
|
||||
}
|
||||
if v, ok := uuid.Domain(); !ok || v != domain {
|
||||
if !ok {
|
||||
t.Errorf("%s: %d: Domain failed\n", name, uuid)
|
||||
} else {
|
||||
t.Errorf("%s: %s: expected domain %d, got %d\n", name, uuid, domain, v)
|
||||
}
|
||||
}
|
||||
if v, ok := uuid.Id(); !ok || v != id {
|
||||
if !ok {
|
||||
t.Errorf("%s: %d: Id failed\n", name, uuid)
|
||||
} else {
|
||||
t.Errorf("%s: %s: expected id %d, got %d\n", name, uuid, id, v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDCE(t *testing.T) {
|
||||
testDCE(t, "NewDCESecurity", NewDCESecurity(42, 12345678), 42, 12345678)
|
||||
testDCE(t, "NewDCEPerson", NewDCEPerson(), Person, uint32(os.Getuid()))
|
||||
testDCE(t, "NewDCEGroup", NewDCEGroup(), Group, uint32(os.Getgid()))
|
||||
}
|
||||
|
||||
type badRand struct{}
|
||||
|
||||
func (r badRand) Read(buf []byte) (int, error) {
|
||||
for i, _ := range buf {
|
||||
buf[i] = byte(i)
|
||||
}
|
||||
return len(buf), nil
|
||||
}
|
||||
|
||||
func TestBadRand(t *testing.T) {
|
||||
SetRand(badRand{})
|
||||
uuid1 := New()
|
||||
uuid2 := New()
|
||||
if uuid1 != uuid2 {
|
||||
t.Errorf("execpted duplicates, got %q and %q\n", uuid1, uuid2)
|
||||
}
|
||||
SetRand(nil)
|
||||
uuid1 = New()
|
||||
uuid2 = New()
|
||||
if uuid1 == uuid2 {
|
||||
t.Errorf("unexecpted duplicates, got %q\n", uuid1)
|
||||
}
|
||||
}
|
41
Godeps/_workspace/src/code.google.com/p/go-uuid/uuid/version1.go
generated
vendored
Normal file
41
Godeps/_workspace/src/code.google.com/p/go-uuid/uuid/version1.go
generated
vendored
Normal file
@ -0,0 +1,41 @@
|
||||
// Copyright 2011 Google Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package uuid
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
)
|
||||
|
||||
// NewUUID returns a Version 1 UUID based on the current NodeID and clock
|
||||
// sequence, and the current time. If the NodeID has not been set by SetNodeID
|
||||
// or SetNodeInterface then it will be set automatically. If the NodeID cannot
|
||||
// be set NewUUID returns nil. If clock sequence has not been set by
|
||||
// SetClockSequence then it will be set automatically. If GetTime fails to
|
||||
// return the current NewUUID returns nil.
|
||||
func NewUUID() UUID {
|
||||
if nodeID == nil {
|
||||
SetNodeInterface("")
|
||||
}
|
||||
|
||||
now, err := GetTime()
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
uuid := make([]byte, 16)
|
||||
|
||||
time_low := uint32(now & 0xffffffff)
|
||||
time_mid := uint16((now >> 32) & 0xffff)
|
||||
time_hi := uint16((now >> 48) & 0x0fff)
|
||||
time_hi |= 0x1000 // Version 1
|
||||
|
||||
binary.BigEndian.PutUint32(uuid[0:], time_low)
|
||||
binary.BigEndian.PutUint16(uuid[4:], time_mid)
|
||||
binary.BigEndian.PutUint16(uuid[6:], time_hi)
|
||||
binary.BigEndian.PutUint16(uuid[8:], clock_seq)
|
||||
copy(uuid[10:], nodeID)
|
||||
|
||||
return uuid
|
||||
}
|
25
Godeps/_workspace/src/code.google.com/p/go-uuid/uuid/version4.go
generated
vendored
Normal file
25
Godeps/_workspace/src/code.google.com/p/go-uuid/uuid/version4.go
generated
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
// Copyright 2011 Google Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package uuid
|
||||
|
||||
// Random returns a Random (Version 4) UUID or panics.
|
||||
//
|
||||
// The strength of the UUIDs is based on the strength of the crypto/rand
|
||||
// package.
|
||||
//
|
||||
// A note about uniqueness derived from from the UUID Wikipedia entry:
|
||||
//
|
||||
// Randomly generated UUIDs have 122 random bits. One's annual risk of being
|
||||
// hit by a meteorite is estimated to be one chance in 17 billion, that
|
||||
// means the probability is about 0.00000000006 (6 × 10−11),
|
||||
// equivalent to the odds of creating a few tens of trillions of UUIDs in a
|
||||
// year and having one duplicate.
|
||||
func NewRandom() UUID {
|
||||
uuid := make([]byte, 16)
|
||||
randomBits([]byte(uuid))
|
||||
uuid[6] = (uuid[6] & 0x0f) | 0x40 // Version 4
|
||||
uuid[8] = (uuid[8] & 0x3f) | 0x80 // Variant is 10
|
||||
return uuid
|
||||
}
|
124
Godeps/_workspace/src/code.google.com/p/snappy-go/snappy/decode.go
generated
vendored
Normal file
124
Godeps/_workspace/src/code.google.com/p/snappy-go/snappy/decode.go
generated
vendored
Normal file
@ -0,0 +1,124 @@
|
||||
// Copyright 2011 The Snappy-Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package snappy
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
)
|
||||
|
||||
// ErrCorrupt reports that the input is invalid.
|
||||
var ErrCorrupt = errors.New("snappy: corrupt input")
|
||||
|
||||
// DecodedLen returns the length of the decoded block.
|
||||
func DecodedLen(src []byte) (int, error) {
|
||||
v, _, err := decodedLen(src)
|
||||
return v, err
|
||||
}
|
||||
|
||||
// decodedLen returns the length of the decoded block and the number of bytes
|
||||
// that the length header occupied.
|
||||
func decodedLen(src []byte) (blockLen, headerLen int, err error) {
|
||||
v, n := binary.Uvarint(src)
|
||||
if n == 0 {
|
||||
return 0, 0, ErrCorrupt
|
||||
}
|
||||
if uint64(int(v)) != v {
|
||||
return 0, 0, errors.New("snappy: decoded block is too large")
|
||||
}
|
||||
return int(v), n, nil
|
||||
}
|
||||
|
||||
// Decode returns the decoded form of src. The returned slice may be a sub-
|
||||
// slice of dst if dst was large enough to hold the entire decoded block.
|
||||
// Otherwise, a newly allocated slice will be returned.
|
||||
// It is valid to pass a nil dst.
|
||||
func Decode(dst, src []byte) ([]byte, error) {
|
||||
dLen, s, err := decodedLen(src)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(dst) < dLen {
|
||||
dst = make([]byte, dLen)
|
||||
}
|
||||
|
||||
var d, offset, length int
|
||||
for s < len(src) {
|
||||
switch src[s] & 0x03 {
|
||||
case tagLiteral:
|
||||
x := uint(src[s] >> 2)
|
||||
switch {
|
||||
case x < 60:
|
||||
s += 1
|
||||
case x == 60:
|
||||
s += 2
|
||||
if s > len(src) {
|
||||
return nil, ErrCorrupt
|
||||
}
|
||||
x = uint(src[s-1])
|
||||
case x == 61:
|
||||
s += 3
|
||||
if s > len(src) {
|
||||
return nil, ErrCorrupt
|
||||
}
|
||||
x = uint(src[s-2]) | uint(src[s-1])<<8
|
||||
case x == 62:
|
||||
s += 4
|
||||
if s > len(src) {
|
||||
return nil, ErrCorrupt
|
||||
}
|
||||
x = uint(src[s-3]) | uint(src[s-2])<<8 | uint(src[s-1])<<16
|
||||
case x == 63:
|
||||
s += 5
|
||||
if s > len(src) {
|
||||
return nil, ErrCorrupt
|
||||
}
|
||||
x = uint(src[s-4]) | uint(src[s-3])<<8 | uint(src[s-2])<<16 | uint(src[s-1])<<24
|
||||
}
|
||||
length = int(x + 1)
|
||||
if length <= 0 {
|
||||
return nil, errors.New("snappy: unsupported literal length")
|
||||
}
|
||||
if length > len(dst)-d || length > len(src)-s {
|
||||
return nil, ErrCorrupt
|
||||
}
|
||||
copy(dst[d:], src[s:s+length])
|
||||
d += length
|
||||
s += length
|
||||
continue
|
||||
|
||||
case tagCopy1:
|
||||
s += 2
|
||||
if s > len(src) {
|
||||
return nil, ErrCorrupt
|
||||
}
|
||||
length = 4 + int(src[s-2])>>2&0x7
|
||||
offset = int(src[s-2])&0xe0<<3 | int(src[s-1])
|
||||
|
||||
case tagCopy2:
|
||||
s += 3
|
||||
if s > len(src) {
|
||||
return nil, ErrCorrupt
|
||||
}
|
||||
length = 1 + int(src[s-3])>>2
|
||||
offset = int(src[s-2]) | int(src[s-1])<<8
|
||||
|
||||
case tagCopy4:
|
||||
return nil, errors.New("snappy: unsupported COPY_4 tag")
|
||||
}
|
||||
|
||||
end := d + length
|
||||
if offset > d || end > len(dst) {
|
||||
return nil, ErrCorrupt
|
||||
}
|
||||
for ; d < end; d++ {
|
||||
dst[d] = dst[d-offset]
|
||||
}
|
||||
}
|
||||
if d != dLen {
|
||||
return nil, ErrCorrupt
|
||||
}
|
||||
return dst[:d], nil
|
||||
}
|
174
Godeps/_workspace/src/code.google.com/p/snappy-go/snappy/encode.go
generated
vendored
Normal file
174
Godeps/_workspace/src/code.google.com/p/snappy-go/snappy/encode.go
generated
vendored
Normal file
@ -0,0 +1,174 @@
|
||||
// Copyright 2011 The Snappy-Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package snappy
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
)
|
||||
|
||||
// We limit how far copy back-references can go, the same as the C++ code.
|
||||
const maxOffset = 1 << 15
|
||||
|
||||
// emitLiteral writes a literal chunk and returns the number of bytes written.
|
||||
func emitLiteral(dst, lit []byte) int {
|
||||
i, n := 0, uint(len(lit)-1)
|
||||
switch {
|
||||
case n < 60:
|
||||
dst[0] = uint8(n)<<2 | tagLiteral
|
||||
i = 1
|
||||
case n < 1<<8:
|
||||
dst[0] = 60<<2 | tagLiteral
|
||||
dst[1] = uint8(n)
|
||||
i = 2
|
||||
case n < 1<<16:
|
||||
dst[0] = 61<<2 | tagLiteral
|
||||
dst[1] = uint8(n)
|
||||
dst[2] = uint8(n >> 8)
|
||||
i = 3
|
||||
case n < 1<<24:
|
||||
dst[0] = 62<<2 | tagLiteral
|
||||
dst[1] = uint8(n)
|
||||
dst[2] = uint8(n >> 8)
|
||||
dst[3] = uint8(n >> 16)
|
||||
i = 4
|
||||
case int64(n) < 1<<32:
|
||||
dst[0] = 63<<2 | tagLiteral
|
||||
dst[1] = uint8(n)
|
||||
dst[2] = uint8(n >> 8)
|
||||
dst[3] = uint8(n >> 16)
|
||||
dst[4] = uint8(n >> 24)
|
||||
i = 5
|
||||
default:
|
||||
panic("snappy: source buffer is too long")
|
||||
}
|
||||
if copy(dst[i:], lit) != len(lit) {
|
||||
panic("snappy: destination buffer is too short")
|
||||
}
|
||||
return i + len(lit)
|
||||
}
|
||||
|
||||
// emitCopy writes a copy chunk and returns the number of bytes written.
|
||||
func emitCopy(dst []byte, offset, length int) int {
|
||||
i := 0
|
||||
for length > 0 {
|
||||
x := length - 4
|
||||
if 0 <= x && x < 1<<3 && offset < 1<<11 {
|
||||
dst[i+0] = uint8(offset>>8)&0x07<<5 | uint8(x)<<2 | tagCopy1
|
||||
dst[i+1] = uint8(offset)
|
||||
i += 2
|
||||
break
|
||||
}
|
||||
|
||||
x = length
|
||||
if x > 1<<6 {
|
||||
x = 1 << 6
|
||||
}
|
||||
dst[i+0] = uint8(x-1)<<2 | tagCopy2
|
||||
dst[i+1] = uint8(offset)
|
||||
dst[i+2] = uint8(offset >> 8)
|
||||
i += 3
|
||||
length -= x
|
||||
}
|
||||
return i
|
||||
}
|
||||
|
||||
// Encode returns the encoded form of src. The returned slice may be a sub-
|
||||
// slice of dst if dst was large enough to hold the entire encoded block.
|
||||
// Otherwise, a newly allocated slice will be returned.
|
||||
// It is valid to pass a nil dst.
|
||||
func Encode(dst, src []byte) ([]byte, error) {
|
||||
if n := MaxEncodedLen(len(src)); len(dst) < n {
|
||||
dst = make([]byte, n)
|
||||
}
|
||||
|
||||
// The block starts with the varint-encoded length of the decompressed bytes.
|
||||
d := binary.PutUvarint(dst, uint64(len(src)))
|
||||
|
||||
// Return early if src is short.
|
||||
if len(src) <= 4 {
|
||||
if len(src) != 0 {
|
||||
d += emitLiteral(dst[d:], src)
|
||||
}
|
||||
return dst[:d], nil
|
||||
}
|
||||
|
||||
// Initialize the hash table. Its size ranges from 1<<8 to 1<<14 inclusive.
|
||||
const maxTableSize = 1 << 14
|
||||
shift, tableSize := uint(32-8), 1<<8
|
||||
for tableSize < maxTableSize && tableSize < len(src) {
|
||||
shift--
|
||||
tableSize *= 2
|
||||
}
|
||||
var table [maxTableSize]int
|
||||
|
||||
// Iterate over the source bytes.
|
||||
var (
|
||||
s int // The iterator position.
|
||||
t int // The last position with the same hash as s.
|
||||
lit int // The start position of any pending literal bytes.
|
||||
)
|
||||
for s+3 < len(src) {
|
||||
// Update the hash table.
|
||||
b0, b1, b2, b3 := src[s], src[s+1], src[s+2], src[s+3]
|
||||
h := uint32(b0) | uint32(b1)<<8 | uint32(b2)<<16 | uint32(b3)<<24
|
||||
p := &table[(h*0x1e35a7bd)>>shift]
|
||||
// We need to to store values in [-1, inf) in table. To save
|
||||
// some initialization time, (re)use the table's zero value
|
||||
// and shift the values against this zero: add 1 on writes,
|
||||
// subtract 1 on reads.
|
||||
t, *p = *p-1, s+1
|
||||
// If t is invalid or src[s:s+4] differs from src[t:t+4], accumulate a literal byte.
|
||||
if t < 0 || s-t >= maxOffset || b0 != src[t] || b1 != src[t+1] || b2 != src[t+2] || b3 != src[t+3] {
|
||||
s++
|
||||
continue
|
||||
}
|
||||
// Otherwise, we have a match. First, emit any pending literal bytes.
|
||||
if lit != s {
|
||||
d += emitLiteral(dst[d:], src[lit:s])
|
||||
}
|
||||
// Extend the match to be as long as possible.
|
||||
s0 := s
|
||||
s, t = s+4, t+4
|
||||
for s < len(src) && src[s] == src[t] {
|
||||
s++
|
||||
t++
|
||||
}
|
||||
// Emit the copied bytes.
|
||||
d += emitCopy(dst[d:], s-t, s-s0)
|
||||
lit = s
|
||||
}
|
||||
|
||||
// Emit any final pending literal bytes and return.
|
||||
if lit != len(src) {
|
||||
d += emitLiteral(dst[d:], src[lit:])
|
||||
}
|
||||
return dst[:d], nil
|
||||
}
|
||||
|
||||
// MaxEncodedLen returns the maximum length of a snappy block, given its
|
||||
// uncompressed length.
|
||||
func MaxEncodedLen(srcLen int) int {
|
||||
// Compressed data can be defined as:
|
||||
// compressed := item* literal*
|
||||
// item := literal* copy
|
||||
//
|
||||
// The trailing literal sequence has a space blowup of at most 62/60
|
||||
// since a literal of length 60 needs one tag byte + one extra byte
|
||||
// for length information.
|
||||
//
|
||||
// Item blowup is trickier to measure. Suppose the "copy" op copies
|
||||
// 4 bytes of data. Because of a special check in the encoding code,
|
||||
// we produce a 4-byte copy only if the offset is < 65536. Therefore
|
||||
// the copy op takes 3 bytes to encode, and this type of item leads
|
||||
// to at most the 62/60 blowup for representing literals.
|
||||
//
|
||||
// Suppose the "copy" op copies 5 bytes of data. If the offset is big
|
||||
// enough, it will take 5 bytes to encode the copy op. Therefore the
|
||||
// worst case here is a one-byte literal followed by a five-byte copy.
|
||||
// That is, 6 bytes of input turn into 7 bytes of "compressed" data.
|
||||
//
|
||||
// This last factor dominates the blowup, so the final estimate is:
|
||||
return 32 + srcLen + srcLen/6
|
||||
}
|
38
Godeps/_workspace/src/code.google.com/p/snappy-go/snappy/snappy.go
generated
vendored
Normal file
38
Godeps/_workspace/src/code.google.com/p/snappy-go/snappy/snappy.go
generated
vendored
Normal file
@ -0,0 +1,38 @@
|
||||
// Copyright 2011 The Snappy-Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package snappy implements the snappy block-based compression format.
|
||||
// It aims for very high speeds and reasonable compression.
|
||||
//
|
||||
// The C++ snappy implementation is at http://code.google.com/p/snappy/
|
||||
package snappy
|
||||
|
||||
/*
|
||||
Each encoded block begins with the varint-encoded length of the decoded data,
|
||||
followed by a sequence of chunks. Chunks begin and end on byte boundaries. The
|
||||
first byte of each chunk is broken into its 2 least and 6 most significant bits
|
||||
called l and m: l ranges in [0, 4) and m ranges in [0, 64). l is the chunk tag.
|
||||
Zero means a literal tag. All other values mean a copy tag.
|
||||
|
||||
For literal tags:
|
||||
- If m < 60, the next 1 + m bytes are literal bytes.
|
||||
- Otherwise, let n be the little-endian unsigned integer denoted by the next
|
||||
m - 59 bytes. The next 1 + n bytes after that are literal bytes.
|
||||
|
||||
For copy tags, length bytes are copied from offset bytes ago, in the style of
|
||||
Lempel-Ziv compression algorithms. In particular:
|
||||
- For l == 1, the offset ranges in [0, 1<<11) and the length in [4, 12).
|
||||
The length is 4 + the low 3 bits of m. The high 3 bits of m form bits 8-10
|
||||
of the offset. The next byte is bits 0-7 of the offset.
|
||||
- For l == 2, the offset ranges in [0, 1<<16) and the length in [1, 65).
|
||||
The length is 1 + m. The offset is the little-endian unsigned integer
|
||||
denoted by the next 2 bytes.
|
||||
- For l == 3, this tag is a legacy format that is no longer supported.
|
||||
*/
|
||||
const (
|
||||
tagLiteral = 0x00
|
||||
tagCopy1 = 0x01
|
||||
tagCopy2 = 0x02
|
||||
tagCopy4 = 0x03
|
||||
)
|
261
Godeps/_workspace/src/code.google.com/p/snappy-go/snappy/snappy_test.go
generated
vendored
Normal file
261
Godeps/_workspace/src/code.google.com/p/snappy-go/snappy/snappy_test.go
generated
vendored
Normal file
@ -0,0 +1,261 @@
|
||||
// Copyright 2011 The Snappy-Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package snappy
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var download = flag.Bool("download", false, "If true, download any missing files before running benchmarks")
|
||||
|
||||
func roundtrip(b, ebuf, dbuf []byte) error {
|
||||
e, err := Encode(ebuf, b)
|
||||
if err != nil {
|
||||
return fmt.Errorf("encoding error: %v", err)
|
||||
}
|
||||
d, err := Decode(dbuf, e)
|
||||
if err != nil {
|
||||
return fmt.Errorf("decoding error: %v", err)
|
||||
}
|
||||
if !bytes.Equal(b, d) {
|
||||
return fmt.Errorf("roundtrip mismatch:\n\twant %v\n\tgot %v", b, d)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestEmpty(t *testing.T) {
|
||||
if err := roundtrip(nil, nil, nil); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSmallCopy(t *testing.T) {
|
||||
for _, ebuf := range [][]byte{nil, make([]byte, 20), make([]byte, 64)} {
|
||||
for _, dbuf := range [][]byte{nil, make([]byte, 20), make([]byte, 64)} {
|
||||
for i := 0; i < 32; i++ {
|
||||
s := "aaaa" + strings.Repeat("b", i) + "aaaabbbb"
|
||||
if err := roundtrip([]byte(s), ebuf, dbuf); err != nil {
|
||||
t.Errorf("len(ebuf)=%d, len(dbuf)=%d, i=%d: %v", len(ebuf), len(dbuf), i, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSmallRand(t *testing.T) {
|
||||
rand.Seed(27354294)
|
||||
for n := 1; n < 20000; n += 23 {
|
||||
b := make([]byte, n)
|
||||
for i, _ := range b {
|
||||
b[i] = uint8(rand.Uint32())
|
||||
}
|
||||
if err := roundtrip(b, nil, nil); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSmallRegular(t *testing.T) {
|
||||
for n := 1; n < 20000; n += 23 {
|
||||
b := make([]byte, n)
|
||||
for i, _ := range b {
|
||||
b[i] = uint8(i%10 + 'a')
|
||||
}
|
||||
if err := roundtrip(b, nil, nil); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func benchDecode(b *testing.B, src []byte) {
|
||||
encoded, err := Encode(nil, src)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
// Bandwidth is in amount of uncompressed data.
|
||||
b.SetBytes(int64(len(src)))
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
Decode(src, encoded)
|
||||
}
|
||||
}
|
||||
|
||||
func benchEncode(b *testing.B, src []byte) {
|
||||
// Bandwidth is in amount of uncompressed data.
|
||||
b.SetBytes(int64(len(src)))
|
||||
dst := make([]byte, MaxEncodedLen(len(src)))
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
Encode(dst, src)
|
||||
}
|
||||
}
|
||||
|
||||
func readFile(b *testing.B, filename string) []byte {
|
||||
src, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
b.Fatalf("failed reading %s: %s", filename, err)
|
||||
}
|
||||
if len(src) == 0 {
|
||||
b.Fatalf("%s has zero length", filename)
|
||||
}
|
||||
return src
|
||||
}
|
||||
|
||||
// expand returns a slice of length n containing repeated copies of src.
|
||||
func expand(src []byte, n int) []byte {
|
||||
dst := make([]byte, n)
|
||||
for x := dst; len(x) > 0; {
|
||||
i := copy(x, src)
|
||||
x = x[i:]
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
func benchWords(b *testing.B, n int, decode bool) {
|
||||
// Note: the file is OS-language dependent so the resulting values are not
|
||||
// directly comparable for non-US-English OS installations.
|
||||
data := expand(readFile(b, "/usr/share/dict/words"), n)
|
||||
if decode {
|
||||
benchDecode(b, data)
|
||||
} else {
|
||||
benchEncode(b, data)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkWordsDecode1e3(b *testing.B) { benchWords(b, 1e3, true) }
|
||||
func BenchmarkWordsDecode1e4(b *testing.B) { benchWords(b, 1e4, true) }
|
||||
func BenchmarkWordsDecode1e5(b *testing.B) { benchWords(b, 1e5, true) }
|
||||
func BenchmarkWordsDecode1e6(b *testing.B) { benchWords(b, 1e6, true) }
|
||||
func BenchmarkWordsEncode1e3(b *testing.B) { benchWords(b, 1e3, false) }
|
||||
func BenchmarkWordsEncode1e4(b *testing.B) { benchWords(b, 1e4, false) }
|
||||
func BenchmarkWordsEncode1e5(b *testing.B) { benchWords(b, 1e5, false) }
|
||||
func BenchmarkWordsEncode1e6(b *testing.B) { benchWords(b, 1e6, false) }
|
||||
|
||||
// testFiles' values are copied directly from
|
||||
// https://code.google.com/p/snappy/source/browse/trunk/snappy_unittest.cc.
|
||||
// The label field is unused in snappy-go.
|
||||
var testFiles = []struct {
|
||||
label string
|
||||
filename string
|
||||
}{
|
||||
{"html", "html"},
|
||||
{"urls", "urls.10K"},
|
||||
{"jpg", "house.jpg"},
|
||||
{"pdf", "mapreduce-osdi-1.pdf"},
|
||||
{"html4", "html_x_4"},
|
||||
{"cp", "cp.html"},
|
||||
{"c", "fields.c"},
|
||||
{"lsp", "grammar.lsp"},
|
||||
{"xls", "kennedy.xls"},
|
||||
{"txt1", "alice29.txt"},
|
||||
{"txt2", "asyoulik.txt"},
|
||||
{"txt3", "lcet10.txt"},
|
||||
{"txt4", "plrabn12.txt"},
|
||||
{"bin", "ptt5"},
|
||||
{"sum", "sum"},
|
||||
{"man", "xargs.1"},
|
||||
{"pb", "geo.protodata"},
|
||||
{"gaviota", "kppkn.gtb"},
|
||||
}
|
||||
|
||||
// The test data files are present at this canonical URL.
|
||||
const baseURL = "https://snappy.googlecode.com/svn/trunk/testdata/"
|
||||
|
||||
func downloadTestdata(basename string) (errRet error) {
|
||||
filename := filepath.Join("testdata", basename)
|
||||
f, err := os.Create(filename)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create %s: %s", filename, err)
|
||||
}
|
||||
defer f.Close()
|
||||
defer func() {
|
||||
if errRet != nil {
|
||||
os.Remove(filename)
|
||||
}
|
||||
}()
|
||||
resp, err := http.Get(baseURL + basename)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to download %s: %s", baseURL+basename, err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
_, err = io.Copy(f, resp.Body)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to write %s: %s", filename, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func benchFile(b *testing.B, n int, decode bool) {
|
||||
filename := filepath.Join("testdata", testFiles[n].filename)
|
||||
if stat, err := os.Stat(filename); err != nil || stat.Size() == 0 {
|
||||
if !*download {
|
||||
b.Fatal("test data not found; skipping benchmark without the -download flag")
|
||||
}
|
||||
// Download the official snappy C++ implementation reference test data
|
||||
// files for benchmarking.
|
||||
if err := os.Mkdir("testdata", 0777); err != nil && !os.IsExist(err) {
|
||||
b.Fatalf("failed to create testdata: %s", err)
|
||||
}
|
||||
for _, tf := range testFiles {
|
||||
if err := downloadTestdata(tf.filename); err != nil {
|
||||
b.Fatalf("failed to download testdata: %s", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
data := readFile(b, filename)
|
||||
if decode {
|
||||
benchDecode(b, data)
|
||||
} else {
|
||||
benchEncode(b, data)
|
||||
}
|
||||
}
|
||||
|
||||
// Naming convention is kept similar to what snappy's C++ implementation uses.
|
||||
func Benchmark_UFlat0(b *testing.B) { benchFile(b, 0, true) }
|
||||
func Benchmark_UFlat1(b *testing.B) { benchFile(b, 1, true) }
|
||||
func Benchmark_UFlat2(b *testing.B) { benchFile(b, 2, true) }
|
||||
func Benchmark_UFlat3(b *testing.B) { benchFile(b, 3, true) }
|
||||
func Benchmark_UFlat4(b *testing.B) { benchFile(b, 4, true) }
|
||||
func Benchmark_UFlat5(b *testing.B) { benchFile(b, 5, true) }
|
||||
func Benchmark_UFlat6(b *testing.B) { benchFile(b, 6, true) }
|
||||
func Benchmark_UFlat7(b *testing.B) { benchFile(b, 7, true) }
|
||||
func Benchmark_UFlat8(b *testing.B) { benchFile(b, 8, true) }
|
||||
func Benchmark_UFlat9(b *testing.B) { benchFile(b, 9, true) }
|
||||
func Benchmark_UFlat10(b *testing.B) { benchFile(b, 10, true) }
|
||||
func Benchmark_UFlat11(b *testing.B) { benchFile(b, 11, true) }
|
||||
func Benchmark_UFlat12(b *testing.B) { benchFile(b, 12, true) }
|
||||
func Benchmark_UFlat13(b *testing.B) { benchFile(b, 13, true) }
|
||||
func Benchmark_UFlat14(b *testing.B) { benchFile(b, 14, true) }
|
||||
func Benchmark_UFlat15(b *testing.B) { benchFile(b, 15, true) }
|
||||
func Benchmark_UFlat16(b *testing.B) { benchFile(b, 16, true) }
|
||||
func Benchmark_UFlat17(b *testing.B) { benchFile(b, 17, true) }
|
||||
func Benchmark_ZFlat0(b *testing.B) { benchFile(b, 0, false) }
|
||||
func Benchmark_ZFlat1(b *testing.B) { benchFile(b, 1, false) }
|
||||
func Benchmark_ZFlat2(b *testing.B) { benchFile(b, 2, false) }
|
||||
func Benchmark_ZFlat3(b *testing.B) { benchFile(b, 3, false) }
|
||||
func Benchmark_ZFlat4(b *testing.B) { benchFile(b, 4, false) }
|
||||
func Benchmark_ZFlat5(b *testing.B) { benchFile(b, 5, false) }
|
||||
func Benchmark_ZFlat6(b *testing.B) { benchFile(b, 6, false) }
|
||||
func Benchmark_ZFlat7(b *testing.B) { benchFile(b, 7, false) }
|
||||
func Benchmark_ZFlat8(b *testing.B) { benchFile(b, 8, false) }
|
||||
func Benchmark_ZFlat9(b *testing.B) { benchFile(b, 9, false) }
|
||||
func Benchmark_ZFlat10(b *testing.B) { benchFile(b, 10, false) }
|
||||
func Benchmark_ZFlat11(b *testing.B) { benchFile(b, 11, false) }
|
||||
func Benchmark_ZFlat12(b *testing.B) { benchFile(b, 12, false) }
|
||||
func Benchmark_ZFlat13(b *testing.B) { benchFile(b, 13, false) }
|
||||
func Benchmark_ZFlat14(b *testing.B) { benchFile(b, 14, false) }
|
||||
func Benchmark_ZFlat15(b *testing.B) { benchFile(b, 15, false) }
|
||||
func Benchmark_ZFlat16(b *testing.B) { benchFile(b, 16, false) }
|
||||
func Benchmark_ZFlat17(b *testing.B) { benchFile(b, 17, false) }
|
5
Godeps/_workspace/src/github.com/ethereum/serpent-go/.gitignore
generated
vendored
Normal file
5
Godeps/_workspace/src/github.com/ethereum/serpent-go/.gitignore
generated
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
/tmp
|
||||
*/**/*un~
|
||||
*un~
|
||||
.DS_Store
|
||||
*/**/.DS_Store
|
3
Godeps/_workspace/src/github.com/ethereum/serpent-go/.gitmodules
generated
vendored
Normal file
3
Godeps/_workspace/src/github.com/ethereum/serpent-go/.gitmodules
generated
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
[submodule "serp"]
|
||||
path = serpent
|
||||
url = https://github.com/ethereum/serpent.git
|
12
Godeps/_workspace/src/github.com/ethereum/serpent-go/README.md
generated
vendored
Normal file
12
Godeps/_workspace/src/github.com/ethereum/serpent-go/README.md
generated
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
[serpent](https://github.com/ethereum/serpent) go bindings.
|
||||
|
||||
## Build instructions
|
||||
|
||||
```
|
||||
go get -d github.com/ethereum/serpent-go
|
||||
cd $GOPATH/src/github.com/ethereum/serpent-go
|
||||
git submodule init
|
||||
git submodule update
|
||||
```
|
||||
|
||||
You're now ready to go :-)
|
16
Godeps/_workspace/src/github.com/ethereum/serpent-go/all.cpp
generated
vendored
Normal file
16
Godeps/_workspace/src/github.com/ethereum/serpent-go/all.cpp
generated
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
#include "serpent/bignum.cpp"
|
||||
#include "serpent/util.cpp"
|
||||
#include "serpent/tokenize.cpp"
|
||||
#include "serpent/parser.cpp"
|
||||
#include "serpent/compiler.cpp"
|
||||
#include "serpent/funcs.cpp"
|
||||
#include "serpent/lllparser.cpp"
|
||||
#include "serpent/rewriter.cpp"
|
||||
|
||||
#include "serpent/opcodes.cpp"
|
||||
#include "serpent/optimize.cpp"
|
||||
#include "serpent/functions.cpp"
|
||||
#include "serpent/preprocess.cpp"
|
||||
#include "serpent/rewriteutils.cpp"
|
||||
|
||||
#include "cpp/api.cpp"
|
26
Godeps/_workspace/src/github.com/ethereum/serpent-go/cpp/api.cpp
generated
vendored
Normal file
26
Godeps/_workspace/src/github.com/ethereum/serpent-go/cpp/api.cpp
generated
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
#include <string>
|
||||
|
||||
#include "serpent/lllparser.h"
|
||||
#include "serpent/bignum.h"
|
||||
#include "serpent/util.h"
|
||||
#include "serpent/tokenize.h"
|
||||
#include "serpent/parser.h"
|
||||
#include "serpent/compiler.h"
|
||||
|
||||
#include "cpp/api.h"
|
||||
|
||||
const char *compileGo(char *code, int *err)
|
||||
{
|
||||
try {
|
||||
std::string c = binToHex(compile(std::string(code)));
|
||||
|
||||
return c.c_str();
|
||||
}
|
||||
catch(std::string &error) {
|
||||
*err = 1;
|
||||
return error.c_str();
|
||||
}
|
||||
catch(...) {
|
||||
return "Unknown error";
|
||||
}
|
||||
}
|
14
Godeps/_workspace/src/github.com/ethereum/serpent-go/cpp/api.h
generated
vendored
Normal file
14
Godeps/_workspace/src/github.com/ethereum/serpent-go/cpp/api.h
generated
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
#ifndef CPP_API_H
|
||||
#define CPP_API_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
const char *compileGo(char *code, int *err);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
27
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent.go
generated
vendored
Normal file
27
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent.go
generated
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
package serpent
|
||||
|
||||
// #cgo CXXFLAGS: -I. -Ilangs/ -std=c++0x -Wall -fno-strict-aliasing
|
||||
// #cgo LDFLAGS: -lstdc++
|
||||
//
|
||||
// #include "cpp/api.h"
|
||||
//
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func Compile(str string) ([]byte, error) {
|
||||
var err C.int
|
||||
out := C.GoString(C.compileGo(C.CString(str), (*C.int)(unsafe.Pointer(&err))))
|
||||
|
||||
if err == C.int(1) {
|
||||
return nil, errors.New(out)
|
||||
}
|
||||
|
||||
bytes, _ := hex.DecodeString(out)
|
||||
|
||||
return bytes, nil
|
||||
}
|
12
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/.gitignore
generated
vendored
Normal file
12
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/.gitignore
generated
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
[._]*.s[a-w][a-z]
|
||||
[._]s[a-w][a-z]
|
||||
*.un~
|
||||
Session.vim
|
||||
.netrwhist
|
||||
*~
|
||||
*.o
|
||||
serpent
|
||||
libserpent.a
|
||||
pyserpent.so
|
||||
dist
|
||||
*.egg-info
|
5
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/MANIFEST.in
generated
vendored
Normal file
5
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/MANIFEST.in
generated
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
include *.cpp
|
||||
include *.h
|
||||
include *py
|
||||
include README.md
|
||||
include Makefile
|
55
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/Makefile
generated
vendored
Normal file
55
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/Makefile
generated
vendored
Normal file
@ -0,0 +1,55 @@
|
||||
PLATFORM_OPTS =
|
||||
PYTHON = /usr/include/python2.7
|
||||
CXXFLAGS = -fPIC
|
||||
# -g3 -O0
|
||||
BOOST_INC = /usr/include
|
||||
BOOST_LIB = /usr/lib
|
||||
TARGET = pyserpent
|
||||
COMMON_OBJS = bignum.o util.o tokenize.o lllparser.o parser.o opcodes.o optimize.o functions.o rewriteutils.o preprocess.o rewriter.o compiler.o funcs.o
|
||||
HEADERS = bignum.h util.h tokenize.h lllparser.h parser.h opcodes.h functions.h optimize.h rewriteutils.h preprocess.h rewriter.h compiler.h funcs.h
|
||||
PYTHON_VERSION = 2.7
|
||||
|
||||
serpent : serpentc lib
|
||||
|
||||
lib:
|
||||
ar rvs libserpent.a $(COMMON_OBJS)
|
||||
g++ $(CXXFLAGS) -shared $(COMMON_OBJS) -o libserpent.so
|
||||
|
||||
serpentc: $(COMMON_OBJS) cmdline.o
|
||||
rm -rf serpent
|
||||
g++ -Wall $(COMMON_OBJS) cmdline.o -o serpent
|
||||
|
||||
bignum.o : bignum.cpp bignum.h
|
||||
|
||||
opcodes.o : opcodes.cpp opcodes.h
|
||||
|
||||
util.o : util.cpp util.h bignum.o
|
||||
|
||||
tokenize.o : tokenize.cpp tokenize.h util.o
|
||||
|
||||
lllparser.o : lllparser.cpp lllparser.h tokenize.o util.o
|
||||
|
||||
parser.o : parser.cpp parser.h tokenize.o util.o
|
||||
|
||||
rewriter.o : rewriter.cpp rewriter.h lllparser.o util.o rewriteutils.o preprocess.o opcodes.o functions.o
|
||||
|
||||
preprocessor.o: rewriteutils.o functions.o
|
||||
|
||||
compiler.o : compiler.cpp compiler.h util.o
|
||||
|
||||
funcs.o : funcs.cpp funcs.h
|
||||
|
||||
cmdline.o: cmdline.cpp
|
||||
|
||||
pyext.o: pyext.cpp
|
||||
|
||||
clean:
|
||||
rm -f serpent *\.o libserpent.a libserpent.so
|
||||
|
||||
install:
|
||||
cp serpent /usr/local/bin
|
||||
cp libserpent.a /usr/local/lib
|
||||
cp libserpent.so /usr/local/lib
|
||||
rm -rf /usr/local/include/libserpent
|
||||
mkdir -p /usr/local/include/libserpent
|
||||
cp $(HEADERS) /usr/local/include/libserpent
|
3
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/README.md
generated
vendored
Normal file
3
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/README.md
generated
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
Installation:
|
||||
|
||||
```make && sudo make install```
|
112
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/bignum.cpp
generated
vendored
Normal file
112
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/bignum.cpp
generated
vendored
Normal file
@ -0,0 +1,112 @@
|
||||
#include <stdio.h>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include "bignum.h"
|
||||
|
||||
//Integer to string conversion
|
||||
std::string unsignedToDecimal(unsigned branch) {
|
||||
if (branch < 10) return nums.substr(branch, 1);
|
||||
else return unsignedToDecimal(branch / 10) + nums.substr(branch % 10,1);
|
||||
}
|
||||
|
||||
//Add two strings representing decimal values
|
||||
std::string decimalAdd(std::string a, std::string b) {
|
||||
std::string o = a;
|
||||
while (b.length() < a.length()) b = "0" + b;
|
||||
while (o.length() < b.length()) o = "0" + o;
|
||||
bool carry = false;
|
||||
for (int i = o.length() - 1; i >= 0; i--) {
|
||||
o[i] = o[i] + b[i] - '0';
|
||||
if (carry) o[i]++;
|
||||
if (o[i] > '9') {
|
||||
o[i] -= 10;
|
||||
carry = true;
|
||||
}
|
||||
else carry = false;
|
||||
}
|
||||
if (carry) o = "1" + o;
|
||||
return o;
|
||||
}
|
||||
|
||||
//Helper function for decimalMul
|
||||
std::string decimalDigitMul(std::string a, int dig) {
|
||||
if (dig == 0) return "0";
|
||||
else return decimalAdd(a, decimalDigitMul(a, dig - 1));
|
||||
}
|
||||
|
||||
//Multiply two strings representing decimal values
|
||||
std::string decimalMul(std::string a, std::string b) {
|
||||
std::string o = "0";
|
||||
for (unsigned i = 0; i < b.length(); i++) {
|
||||
std::string n = decimalDigitMul(a, b[i] - '0');
|
||||
if (n != "0") {
|
||||
for (unsigned j = i + 1; j < b.length(); j++) n += "0";
|
||||
}
|
||||
o = decimalAdd(o, n);
|
||||
}
|
||||
return o;
|
||||
}
|
||||
|
||||
//Modexp
|
||||
std::string decimalModExp(std::string b, std::string e, std::string m) {
|
||||
if (e == "0") return "1";
|
||||
else if (e == "1") return b;
|
||||
else if (decimalMod(e, "2") == "0") {
|
||||
std::string o = decimalModExp(b, decimalDiv(e, "2"), m);
|
||||
return decimalMod(decimalMul(o, o), m);
|
||||
}
|
||||
else {
|
||||
std::string o = decimalModExp(b, decimalDiv(e, "2"), m);
|
||||
return decimalMod(decimalMul(decimalMul(o, o), b), m);
|
||||
}
|
||||
}
|
||||
|
||||
//Is a greater than b? Flag allows equality
|
||||
bool decimalGt(std::string a, std::string b, bool eqAllowed) {
|
||||
if (a == b) return eqAllowed;
|
||||
return (a.length() > b.length()) || (a.length() >= b.length() && a > b);
|
||||
}
|
||||
|
||||
//Subtract the two strings representing decimal values
|
||||
std::string decimalSub(std::string a, std::string b) {
|
||||
if (b == "0") return a;
|
||||
if (b == a) return "0";
|
||||
while (b.length() < a.length()) b = "0" + b;
|
||||
std::string c = b;
|
||||
for (unsigned i = 0; i < c.length(); i++) c[i] = '0' + ('9' - c[i]);
|
||||
std::string o = decimalAdd(decimalAdd(a, c).substr(1), "1");
|
||||
while (o.size() > 1 && o[0] == '0') o = o.substr(1);
|
||||
return o;
|
||||
}
|
||||
|
||||
//Divide the two strings representing decimal values
|
||||
std::string decimalDiv(std::string a, std::string b) {
|
||||
std::string c = b;
|
||||
if (decimalGt(c, a)) return "0";
|
||||
int zeroes = -1;
|
||||
while (decimalGt(a, c, true)) {
|
||||
zeroes += 1;
|
||||
c = c + "0";
|
||||
}
|
||||
c = c.substr(0, c.size() - 1);
|
||||
std::string quot = "0";
|
||||
while (decimalGt(a, c, true)) {
|
||||
a = decimalSub(a, c);
|
||||
quot = decimalAdd(quot, "1");
|
||||
}
|
||||
for (int i = 0; i < zeroes; i++) quot += "0";
|
||||
return decimalAdd(quot, decimalDiv(a, b));
|
||||
}
|
||||
|
||||
//Modulo the two strings representing decimal values
|
||||
std::string decimalMod(std::string a, std::string b) {
|
||||
return decimalSub(a, decimalMul(decimalDiv(a, b), b));
|
||||
}
|
||||
|
||||
//String to int conversion
|
||||
unsigned decimalToUnsigned(std::string a) {
|
||||
if (a.size() == 0) return 0;
|
||||
else return (a[a.size() - 1] - '0')
|
||||
+ decimalToUnsigned(a.substr(0,a.size()-1)) * 10;
|
||||
}
|
41
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/bignum.h
generated
vendored
Normal file
41
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/bignum.h
generated
vendored
Normal file
@ -0,0 +1,41 @@
|
||||
#ifndef ETHSERP_BIGNUM
|
||||
#define ETHSERP_BIGNUM
|
||||
|
||||
const std::string nums = "0123456789";
|
||||
|
||||
const std::string tt256 =
|
||||
"115792089237316195423570985008687907853269984665640564039457584007913129639936"
|
||||
;
|
||||
|
||||
const std::string tt256m1 =
|
||||
"115792089237316195423570985008687907853269984665640564039457584007913129639935"
|
||||
;
|
||||
|
||||
const std::string tt255 =
|
||||
"57896044618658097711785492504343953926634992332820282019728792003956564819968";
|
||||
|
||||
const std::string tt176 =
|
||||
"95780971304118053647396689196894323976171195136475136";
|
||||
|
||||
std::string unsignedToDecimal(unsigned branch);
|
||||
|
||||
std::string decimalAdd(std::string a, std::string b);
|
||||
|
||||
std::string decimalMul(std::string a, std::string b);
|
||||
|
||||
std::string decimalSub(std::string a, std::string b);
|
||||
|
||||
std::string decimalDiv(std::string a, std::string b);
|
||||
|
||||
std::string decimalMod(std::string a, std::string b);
|
||||
|
||||
std::string decimalModExp(std::string b, std::string e, std::string m);
|
||||
|
||||
bool decimalGt(std::string a, std::string b, bool eqAllowed=false);
|
||||
|
||||
unsigned decimalToUnsigned(std::string a);
|
||||
|
||||
#define utd unsignedToDecimal
|
||||
#define dtu decimalToUnsigned
|
||||
|
||||
#endif
|
132
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/cmdline.cpp
generated
vendored
Normal file
132
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/cmdline.cpp
generated
vendored
Normal file
@ -0,0 +1,132 @@
|
||||
#include <stdio.h>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include "funcs.h"
|
||||
|
||||
int main(int argv, char** argc) {
|
||||
if (argv == 1) {
|
||||
std::cerr << "Must provide a command and arguments! Try parse, rewrite, compile, assemble\n";
|
||||
return 0;
|
||||
}
|
||||
if (argv == 2 && std::string(argc[1]) == "--help" || std::string(argc[1]) == "-h" ) {
|
||||
std::cout << argc[1] << "\n";
|
||||
|
||||
std::cout << "serpent command input\n";
|
||||
std::cout << "where input -s for from stdin, a file, or interpreted as serpent code if does not exist as file.";
|
||||
std::cout << "where command: \n";
|
||||
std::cout << " parse: Just parses and returns s-expression code.\n";
|
||||
std::cout << " rewrite: Parse, use rewrite rules print s-expressions of result.\n";
|
||||
std::cout << " compile: Return resulting compiled EVM code in hex.\n";
|
||||
std::cout << " assemble: Return result from step before compilation.\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::string flag = "";
|
||||
std::string command = argc[1];
|
||||
std::string input;
|
||||
std::string secondInput;
|
||||
if (std::string(argc[1]) == "-s") {
|
||||
flag = command.substr(1);
|
||||
command = argc[2];
|
||||
input = "";
|
||||
std::string line;
|
||||
while (std::getline(std::cin, line)) {
|
||||
input += line + "\n";
|
||||
}
|
||||
secondInput = argv == 3 ? "" : argc[3];
|
||||
}
|
||||
else {
|
||||
if (argv == 2) {
|
||||
std::cerr << "Not enough arguments for serpent cmdline\n";
|
||||
throw(0);
|
||||
}
|
||||
input = argc[2];
|
||||
secondInput = argv == 3 ? "" : argc[3];
|
||||
}
|
||||
bool haveSec = secondInput.length() > 0;
|
||||
if (command == "parse" || command == "parse_serpent") {
|
||||
std::cout << printAST(parseSerpent(input), haveSec) << "\n";
|
||||
}
|
||||
else if (command == "rewrite") {
|
||||
std::cout << printAST(rewrite(parseLLL(input, true)), haveSec) << "\n";
|
||||
}
|
||||
else if (command == "compile_to_lll") {
|
||||
std::cout << printAST(compileToLLL(input), haveSec) << "\n";
|
||||
}
|
||||
else if (command == "rewrite_chunk") {
|
||||
std::cout << printAST(rewriteChunk(parseLLL(input, true)), haveSec) << "\n";
|
||||
}
|
||||
else if (command == "compile_chunk_to_lll") {
|
||||
std::cout << printAST(compileChunkToLLL(input), haveSec) << "\n";
|
||||
}
|
||||
else if (command == "build_fragtree") {
|
||||
std::cout << printAST(buildFragmentTree(parseLLL(input, true))) << "\n";
|
||||
}
|
||||
else if (command == "compile_lll") {
|
||||
std::cout << binToHex(compileLLL(parseLLL(input, true))) << "\n";
|
||||
}
|
||||
else if (command == "dereference") {
|
||||
std::cout << printAST(dereference(parseLLL(input, true)), haveSec) <<"\n";
|
||||
}
|
||||
else if (command == "pretty_assemble") {
|
||||
std::cout << printTokens(prettyAssemble(parseLLL(input, true))) <<"\n";
|
||||
}
|
||||
else if (command == "pretty_compile_lll") {
|
||||
std::cout << printTokens(prettyCompileLLL(parseLLL(input, true))) << "\n";
|
||||
}
|
||||
else if (command == "pretty_compile") {
|
||||
std::cout << printTokens(prettyCompile(input)) << "\n";
|
||||
}
|
||||
else if (command == "pretty_compile_chunk") {
|
||||
std::cout << printTokens(prettyCompileChunk(input)) << "\n";
|
||||
}
|
||||
else if (command == "assemble") {
|
||||
std::cout << assemble(parseLLL(input, true)) << "\n";
|
||||
}
|
||||
else if (command == "serialize") {
|
||||
std::cout << binToHex(serialize(tokenize(input, Metadata(), false))) << "\n";
|
||||
}
|
||||
else if (command == "flatten") {
|
||||
std::cout << printTokens(flatten(parseLLL(input, true))) << "\n";
|
||||
}
|
||||
else if (command == "deserialize") {
|
||||
std::cout << printTokens(deserialize(hexToBin(input))) << "\n";
|
||||
}
|
||||
else if (command == "compile") {
|
||||
std::cout << binToHex(compile(input)) << "\n";
|
||||
}
|
||||
else if (command == "compile_chunk") {
|
||||
std::cout << binToHex(compileChunk(input)) << "\n";
|
||||
}
|
||||
else if (command == "encode_datalist") {
|
||||
std::vector<Node> tokens = tokenize(input);
|
||||
std::vector<std::string> o;
|
||||
for (int i = 0; i < (int)tokens.size(); i++) {
|
||||
o.push_back(tokens[i].val);
|
||||
}
|
||||
std::cout << binToHex(encodeDatalist(o)) << "\n";
|
||||
}
|
||||
else if (command == "decode_datalist") {
|
||||
std::vector<std::string> o = decodeDatalist(hexToBin(input));
|
||||
std::vector<Node> tokens;
|
||||
for (int i = 0; i < (int)o.size(); i++)
|
||||
tokens.push_back(token(o[i]));
|
||||
std::cout << printTokens(tokens) << "\n";
|
||||
}
|
||||
else if (command == "tokenize") {
|
||||
std::cout << printTokens(tokenize(input));
|
||||
}
|
||||
else if (command == "biject") {
|
||||
if (argv == 3)
|
||||
std::cerr << "Not enough arguments for biject\n";
|
||||
int pos = decimalToUnsigned(secondInput);
|
||||
std::vector<Node> n = prettyCompile(input);
|
||||
if (pos >= (int)n.size())
|
||||
std::cerr << "Code position too high\n";
|
||||
Metadata m = n[pos].metadata;
|
||||
std::cout << "Opcode: " << n[pos].val << ", file: " << m.file <<
|
||||
", line: " << m.ln << ", char: " << m.ch << "\n";
|
||||
}
|
||||
}
|
554
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/compiler.cpp
generated
vendored
Normal file
554
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/compiler.cpp
generated
vendored
Normal file
@ -0,0 +1,554 @@
|
||||
#include <stdio.h>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include "util.h"
|
||||
#include "bignum.h"
|
||||
#include "opcodes.h"
|
||||
|
||||
struct programAux {
|
||||
std::map<std::string, std::string> vars;
|
||||
int nextVarMem;
|
||||
bool allocUsed;
|
||||
bool calldataUsed;
|
||||
int step;
|
||||
int labelLength;
|
||||
};
|
||||
|
||||
struct programVerticalAux {
|
||||
int height;
|
||||
std::string innerScopeName;
|
||||
std::map<std::string, int> dupvars;
|
||||
std::map<std::string, int> funvars;
|
||||
std::vector<mss> scopes;
|
||||
};
|
||||
|
||||
struct programData {
|
||||
programAux aux;
|
||||
Node code;
|
||||
int outs;
|
||||
};
|
||||
|
||||
programAux Aux() {
|
||||
programAux o;
|
||||
o.allocUsed = false;
|
||||
o.calldataUsed = false;
|
||||
o.step = 0;
|
||||
o.nextVarMem = 32;
|
||||
return o;
|
||||
}
|
||||
|
||||
programVerticalAux verticalAux() {
|
||||
programVerticalAux o;
|
||||
o.height = 0;
|
||||
o.dupvars = std::map<std::string, int>();
|
||||
o.funvars = std::map<std::string, int>();
|
||||
o.scopes = std::vector<mss>();
|
||||
return o;
|
||||
}
|
||||
|
||||
programData pd(programAux aux = Aux(), Node code=token("_"), int outs=0) {
|
||||
programData o;
|
||||
o.aux = aux;
|
||||
o.code = code;
|
||||
o.outs = outs;
|
||||
return o;
|
||||
}
|
||||
|
||||
Node multiToken(Node nodes[], int len, Metadata met) {
|
||||
std::vector<Node> out;
|
||||
for (int i = 0; i < len; i++) {
|
||||
out.push_back(nodes[i]);
|
||||
}
|
||||
return astnode("_", out, met);
|
||||
}
|
||||
|
||||
Node finalize(programData c);
|
||||
|
||||
Node popwrap(Node node) {
|
||||
Node nodelist[] = {
|
||||
node,
|
||||
token("POP", node.metadata)
|
||||
};
|
||||
return multiToken(nodelist, 2, node.metadata);
|
||||
}
|
||||
|
||||
// Grabs variables
|
||||
mss getVariables(Node node, mss cur=mss()) {
|
||||
Metadata m = node.metadata;
|
||||
// Tokens don't contain any variables
|
||||
if (node.type == TOKEN)
|
||||
return cur;
|
||||
// Don't descend into call fragments
|
||||
else if (node.val == "lll")
|
||||
return getVariables(node.args[1], cur);
|
||||
// At global scope get/set/ref also declare
|
||||
else if (node.val == "get" || node.val == "set" || node.val == "ref") {
|
||||
if (node.args[0].type != TOKEN)
|
||||
err("Variable name must be simple token,"
|
||||
" not complex expression!", m);
|
||||
if (!cur.count(node.args[0].val)) {
|
||||
cur[node.args[0].val] = utd(cur.size() * 32 + 32);
|
||||
//std::cerr << node.args[0].val << " " << cur[node.args[0].val] << "\n";
|
||||
}
|
||||
}
|
||||
// Recursively process children
|
||||
for (unsigned i = 0; i < node.args.size(); i++) {
|
||||
cur = getVariables(node.args[i], cur);
|
||||
}
|
||||
return cur;
|
||||
}
|
||||
|
||||
// Turns LLL tree into tree of code fragments
|
||||
programData opcodeify(Node node,
|
||||
programAux aux=Aux(),
|
||||
programVerticalAux vaux=verticalAux()) {
|
||||
std::string symb = "_"+mkUniqueToken();
|
||||
Metadata m = node.metadata;
|
||||
// Get variables
|
||||
if (!aux.vars.size()) {
|
||||
aux.vars = getVariables(node);
|
||||
aux.nextVarMem = aux.vars.size() * 32 + 32;
|
||||
}
|
||||
// Numbers
|
||||
if (node.type == TOKEN) {
|
||||
return pd(aux, nodeToNumeric(node), 1);
|
||||
}
|
||||
else if (node.val == "ref" || node.val == "get" || node.val == "set") {
|
||||
std::string varname = node.args[0].val;
|
||||
// Determine reference to variable
|
||||
Node varNode = tkn(aux.vars[varname], m);
|
||||
//std::cerr << varname << " " << printSimple(varNode) << "\n";
|
||||
// Set variable
|
||||
if (node.val == "set") {
|
||||
programData sub = opcodeify(node.args[1], aux, vaux);
|
||||
if (!sub.outs)
|
||||
err("Value to set variable must have nonzero arity!", m);
|
||||
// What if we are setting a stack variable?
|
||||
if (vaux.dupvars.count(node.args[0].val)) {
|
||||
int h = vaux.height - vaux.dupvars[node.args[0].val];
|
||||
if (h > 16) err("Too deep for stack variable (max 16)", m);
|
||||
Node nodelist[] = {
|
||||
sub.code,
|
||||
token("SWAP"+unsignedToDecimal(h), m),
|
||||
token("POP", m)
|
||||
};
|
||||
return pd(sub.aux, multiToken(nodelist, 3, m), 0);
|
||||
}
|
||||
// Setting a memory variable
|
||||
else {
|
||||
Node nodelist[] = {
|
||||
sub.code,
|
||||
varNode,
|
||||
token("MSTORE", m),
|
||||
};
|
||||
return pd(sub.aux, multiToken(nodelist, 3, m), 0);
|
||||
}
|
||||
}
|
||||
// Get variable
|
||||
else if (node.val == "get") {
|
||||
// Getting a stack variable
|
||||
if (vaux.dupvars.count(node.args[0].val)) {
|
||||
int h = vaux.height - vaux.dupvars[node.args[0].val];
|
||||
if (h > 16) err("Too deep for stack variable (max 16)", m);
|
||||
return pd(aux, token("DUP"+unsignedToDecimal(h)), 1);
|
||||
}
|
||||
// Getting a memory variable
|
||||
else {
|
||||
Node nodelist[] =
|
||||
{ varNode, token("MLOAD", m) };
|
||||
return pd(aux, multiToken(nodelist, 2, m), 1);
|
||||
}
|
||||
}
|
||||
// Refer variable
|
||||
else if (node.val == "ref") {
|
||||
if (vaux.dupvars.count(node.args[0].val))
|
||||
err("Cannot ref stack variable!", m);
|
||||
return pd(aux, varNode, 1);
|
||||
}
|
||||
}
|
||||
// Comments do nothing
|
||||
else if (node.val == "comment") {
|
||||
Node nodelist[] = { };
|
||||
return pd(aux, multiToken(nodelist, 0, m), 0);
|
||||
}
|
||||
// Custom operation sequence
|
||||
// eg. (ops bytez id msize swap1 msize add 0 swap1 mstore) == alloc
|
||||
if (node.val == "ops") {
|
||||
std::vector<Node> subs2;
|
||||
int depth = 0;
|
||||
for (unsigned i = 0; i < node.args.size(); i++) {
|
||||
std::string op = upperCase(node.args[i].val);
|
||||
if (node.args[i].type == ASTNODE || opinputs(op) == -1) {
|
||||
programVerticalAux vaux2 = vaux;
|
||||
vaux2.height = vaux.height - i - 1 + node.args.size();
|
||||
programData sub = opcodeify(node.args[i], aux, vaux2);
|
||||
aux = sub.aux;
|
||||
depth += sub.outs;
|
||||
subs2.push_back(sub.code);
|
||||
}
|
||||
else {
|
||||
subs2.push_back(token(op, m));
|
||||
depth += opoutputs(op) - opinputs(op);
|
||||
}
|
||||
}
|
||||
if (depth < 0 || depth > 1) err("Stack depth mismatch", m);
|
||||
return pd(aux, astnode("_", subs2, m), 0);
|
||||
}
|
||||
// Code blocks
|
||||
if (node.val == "lll" && node.args.size() == 2) {
|
||||
if (node.args[1].val != "0") aux.allocUsed = true;
|
||||
std::vector<Node> o;
|
||||
o.push_back(finalize(opcodeify(node.args[0])));
|
||||
programData sub = opcodeify(node.args[1], aux, vaux);
|
||||
Node code = astnode("____CODE", o, m);
|
||||
Node nodelist[] = {
|
||||
token("$begincode"+symb+".endcode"+symb, m), token("DUP1", m),
|
||||
token("$begincode"+symb, m), sub.code, token("CODECOPY", m),
|
||||
token("$endcode"+symb, m), token("JUMP", m),
|
||||
token("~begincode"+symb, m), code,
|
||||
token("~endcode"+symb, m), token("JUMPDEST", m)
|
||||
};
|
||||
return pd(sub.aux, multiToken(nodelist, 11, m), 1);
|
||||
}
|
||||
// Stack variables
|
||||
if (node.val == "with") {
|
||||
programData initial = opcodeify(node.args[1], aux, vaux);
|
||||
programVerticalAux vaux2 = vaux;
|
||||
vaux2.dupvars[node.args[0].val] = vaux.height;
|
||||
vaux2.height += 1;
|
||||
if (!initial.outs)
|
||||
err("Initial variable value must have nonzero arity!", m);
|
||||
programData sub = opcodeify(node.args[2], initial.aux, vaux2);
|
||||
Node nodelist[] = {
|
||||
initial.code,
|
||||
sub.code
|
||||
};
|
||||
programData o = pd(sub.aux, multiToken(nodelist, 2, m), sub.outs);
|
||||
if (sub.outs)
|
||||
o.code.args.push_back(token("SWAP1", m));
|
||||
o.code.args.push_back(token("POP", m));
|
||||
return o;
|
||||
}
|
||||
// Seq of multiple statements
|
||||
if (node.val == "seq") {
|
||||
std::vector<Node> children;
|
||||
int lastOut = 0;
|
||||
for (unsigned i = 0; i < node.args.size(); i++) {
|
||||
programData sub = opcodeify(node.args[i], aux, vaux);
|
||||
aux = sub.aux;
|
||||
if (sub.outs == 1) {
|
||||
if (i < node.args.size() - 1) sub.code = popwrap(sub.code);
|
||||
else lastOut = 1;
|
||||
}
|
||||
children.push_back(sub.code);
|
||||
}
|
||||
return pd(aux, astnode("_", children, m), lastOut);
|
||||
}
|
||||
// 2-part conditional (if gets rewritten to unless in rewrites)
|
||||
else if (node.val == "unless" && node.args.size() == 2) {
|
||||
programData cond = opcodeify(node.args[0], aux, vaux);
|
||||
programData action = opcodeify(node.args[1], cond.aux, vaux);
|
||||
aux = action.aux;
|
||||
if (!cond.outs) err("Condition of if/unless statement has arity 0", m);
|
||||
if (action.outs) action.code = popwrap(action.code);
|
||||
Node nodelist[] = {
|
||||
cond.code,
|
||||
token("$endif"+symb, m), token("JUMPI", m),
|
||||
action.code,
|
||||
token("~endif"+symb, m), token("JUMPDEST", m)
|
||||
};
|
||||
return pd(aux, multiToken(nodelist, 6, m), 0);
|
||||
}
|
||||
// 3-part conditional
|
||||
else if (node.val == "if" && node.args.size() == 3) {
|
||||
programData ifd = opcodeify(node.args[0], aux, vaux);
|
||||
programData thend = opcodeify(node.args[1], ifd.aux, vaux);
|
||||
programData elsed = opcodeify(node.args[2], thend.aux, vaux);
|
||||
aux = elsed.aux;
|
||||
if (!ifd.outs)
|
||||
err("Condition of if/unless statement has arity 0", m);
|
||||
// Handle cases where one conditional outputs something
|
||||
// and the other does not
|
||||
int outs = (thend.outs && elsed.outs) ? 1 : 0;
|
||||
if (thend.outs > outs) thend.code = popwrap(thend.code);
|
||||
if (elsed.outs > outs) elsed.code = popwrap(elsed.code);
|
||||
Node nodelist[] = {
|
||||
ifd.code,
|
||||
token("ISZERO", m),
|
||||
token("$else"+symb, m), token("JUMPI", m),
|
||||
thend.code,
|
||||
token("$endif"+symb, m), token("JUMP", m),
|
||||
token("~else"+symb, m), token("JUMPDEST", m),
|
||||
elsed.code,
|
||||
token("~endif"+symb, m), token("JUMPDEST", m)
|
||||
};
|
||||
return pd(aux, multiToken(nodelist, 12, m), outs);
|
||||
}
|
||||
// While (rewritten to this in rewrites)
|
||||
else if (node.val == "until") {
|
||||
programData cond = opcodeify(node.args[0], aux, vaux);
|
||||
programData action = opcodeify(node.args[1], cond.aux, vaux);
|
||||
aux = action.aux;
|
||||
if (!cond.outs)
|
||||
err("Condition of while/until loop has arity 0", m);
|
||||
if (action.outs) action.code = popwrap(action.code);
|
||||
Node nodelist[] = {
|
||||
token("~beg"+symb, m), token("JUMPDEST", m),
|
||||
cond.code,
|
||||
token("$end"+symb, m), token("JUMPI", m),
|
||||
action.code,
|
||||
token("$beg"+symb, m), token("JUMP", m),
|
||||
token("~end"+symb, m), token("JUMPDEST", m),
|
||||
};
|
||||
return pd(aux, multiToken(nodelist, 10, m));
|
||||
}
|
||||
// Memory allocations
|
||||
else if (node.val == "alloc") {
|
||||
programData bytez = opcodeify(node.args[0], aux, vaux);
|
||||
aux = bytez.aux;
|
||||
if (!bytez.outs)
|
||||
err("Alloc input has arity 0", m);
|
||||
aux.allocUsed = true;
|
||||
Node nodelist[] = {
|
||||
bytez.code,
|
||||
token("MSIZE", m), token("SWAP1", m), token("MSIZE", m),
|
||||
token("ADD", m),
|
||||
token("0", m), token("SWAP1", m), token("MSTORE", m)
|
||||
};
|
||||
return pd(aux, multiToken(nodelist, 8, m), 1);
|
||||
}
|
||||
// All other functions/operators
|
||||
else {
|
||||
std::vector<Node> subs2;
|
||||
int depth = opinputs(upperCase(node.val));
|
||||
if (depth == -1)
|
||||
err("Not a function or opcode: "+node.val, m);
|
||||
if ((int)node.args.size() != depth)
|
||||
err("Invalid arity for "+node.val, m);
|
||||
for (int i = node.args.size() - 1; i >= 0; i--) {
|
||||
programVerticalAux vaux2 = vaux;
|
||||
vaux2.height = vaux.height - i - 1 + node.args.size();
|
||||
programData sub = opcodeify(node.args[i], aux, vaux2);
|
||||
aux = sub.aux;
|
||||
if (!sub.outs)
|
||||
err("Input "+unsignedToDecimal(i)+" has arity 0", sub.code.metadata);
|
||||
subs2.push_back(sub.code);
|
||||
}
|
||||
subs2.push_back(token(upperCase(node.val), m));
|
||||
int outdepth = opoutputs(upperCase(node.val));
|
||||
return pd(aux, astnode("_", subs2, m), outdepth);
|
||||
}
|
||||
}
|
||||
|
||||
// Adds necessary wrappers to a program
|
||||
Node finalize(programData c) {
|
||||
std::vector<Node> bottom;
|
||||
Metadata m = c.code.metadata;
|
||||
// If we are using both alloc and variables, we need to pre-zfill
|
||||
// some memory
|
||||
if ((c.aux.allocUsed || c.aux.calldataUsed) && c.aux.vars.size() > 0) {
|
||||
Node nodelist[] = {
|
||||
token("0", m),
|
||||
token(unsignedToDecimal(c.aux.nextVarMem - 1)),
|
||||
token("MSTORE8", m)
|
||||
};
|
||||
bottom.push_back(multiToken(nodelist, 3, m));
|
||||
}
|
||||
// The actual code
|
||||
bottom.push_back(c.code);
|
||||
return astnode("_", bottom, m);
|
||||
}
|
||||
|
||||
//LLL -> code fragment tree
|
||||
Node buildFragmentTree(Node node) {
|
||||
return finalize(opcodeify(node));
|
||||
}
|
||||
|
||||
|
||||
// Builds a dictionary mapping labels to variable names
|
||||
programAux buildDict(Node program, programAux aux, int labelLength) {
|
||||
Metadata m = program.metadata;
|
||||
// Token
|
||||
if (program.type == TOKEN) {
|
||||
if (isNumberLike(program)) {
|
||||
aux.step += 1 + toByteArr(program.val, m).size();
|
||||
}
|
||||
else if (program.val[0] == '~') {
|
||||
aux.vars[program.val.substr(1)] = unsignedToDecimal(aux.step);
|
||||
}
|
||||
else if (program.val[0] == '$') {
|
||||
aux.step += labelLength + 1;
|
||||
}
|
||||
else aux.step += 1;
|
||||
}
|
||||
// A sub-program (ie. LLL)
|
||||
else if (program.val == "____CODE") {
|
||||
programAux auks = Aux();
|
||||
for (unsigned i = 0; i < program.args.size(); i++) {
|
||||
auks = buildDict(program.args[i], auks, labelLength);
|
||||
}
|
||||
for (std::map<std::string,std::string>::iterator it=auks.vars.begin();
|
||||
it != auks.vars.end();
|
||||
it++) {
|
||||
aux.vars[(*it).first] = (*it).second;
|
||||
}
|
||||
aux.step += auks.step;
|
||||
}
|
||||
// Normal sub-block
|
||||
else {
|
||||
for (unsigned i = 0; i < program.args.size(); i++) {
|
||||
aux = buildDict(program.args[i], aux, labelLength);
|
||||
}
|
||||
}
|
||||
return aux;
|
||||
}
|
||||
|
||||
// Applies that dictionary
|
||||
Node substDict(Node program, programAux aux, int labelLength) {
|
||||
Metadata m = program.metadata;
|
||||
std::vector<Node> out;
|
||||
std::vector<Node> inner;
|
||||
if (program.type == TOKEN) {
|
||||
if (program.val[0] == '$') {
|
||||
std::string tokStr = "PUSH"+unsignedToDecimal(labelLength);
|
||||
out.push_back(token(tokStr, m));
|
||||
int dotLoc = program.val.find('.');
|
||||
if (dotLoc == -1) {
|
||||
std::string val = aux.vars[program.val.substr(1)];
|
||||
inner = toByteArr(val, m, labelLength);
|
||||
}
|
||||
else {
|
||||
std::string start = aux.vars[program.val.substr(1, dotLoc-1)],
|
||||
end = aux.vars[program.val.substr(dotLoc + 1)],
|
||||
dist = decimalSub(end, start);
|
||||
inner = toByteArr(dist, m, labelLength);
|
||||
}
|
||||
out.push_back(astnode("_", inner, m));
|
||||
}
|
||||
else if (program.val[0] == '~') { }
|
||||
else if (isNumberLike(program)) {
|
||||
inner = toByteArr(program.val, m);
|
||||
out.push_back(token("PUSH"+unsignedToDecimal(inner.size())));
|
||||
out.push_back(astnode("_", inner, m));
|
||||
}
|
||||
else return program;
|
||||
}
|
||||
else {
|
||||
for (unsigned i = 0; i < program.args.size(); i++) {
|
||||
Node n = substDict(program.args[i], aux, labelLength);
|
||||
if (n.type == TOKEN || n.args.size()) out.push_back(n);
|
||||
}
|
||||
}
|
||||
return astnode("_", out, m);
|
||||
}
|
||||
|
||||
// Compiled fragtree -> compiled fragtree without labels
|
||||
Node dereference(Node program) {
|
||||
int sz = treeSize(program) * 4;
|
||||
int labelLength = 1;
|
||||
while (sz >= 256) { labelLength += 1; sz /= 256; }
|
||||
programAux aux = buildDict(program, Aux(), labelLength);
|
||||
return substDict(program, aux, labelLength);
|
||||
}
|
||||
|
||||
// Dereferenced fragtree -> opcodes
|
||||
std::vector<Node> flatten(Node derefed) {
|
||||
std::vector<Node> o;
|
||||
if (derefed.type == TOKEN) {
|
||||
o.push_back(derefed);
|
||||
}
|
||||
else {
|
||||
for (unsigned i = 0; i < derefed.args.size(); i++) {
|
||||
std::vector<Node> oprime = flatten(derefed.args[i]);
|
||||
for (unsigned j = 0; j < oprime.size(); j++) o.push_back(oprime[j]);
|
||||
}
|
||||
}
|
||||
return o;
|
||||
}
|
||||
|
||||
// Opcodes -> bin
|
||||
std::string serialize(std::vector<Node> codons) {
|
||||
std::string o;
|
||||
for (unsigned i = 0; i < codons.size(); i++) {
|
||||
int v;
|
||||
if (isNumberLike(codons[i])) {
|
||||
v = decimalToUnsigned(codons[i].val);
|
||||
}
|
||||
else if (codons[i].val.substr(0,4) == "PUSH") {
|
||||
v = 95 + decimalToUnsigned(codons[i].val.substr(4));
|
||||
}
|
||||
else {
|
||||
v = opcode(codons[i].val);
|
||||
}
|
||||
o += (char)v;
|
||||
}
|
||||
return o;
|
||||
}
|
||||
|
||||
// Bin -> opcodes
|
||||
std::vector<Node> deserialize(std::string ser) {
|
||||
std::vector<Node> o;
|
||||
int backCount = 0;
|
||||
for (unsigned i = 0; i < ser.length(); i++) {
|
||||
unsigned char v = (unsigned char)ser[i];
|
||||
std::string oper = op((int)v);
|
||||
if (oper != "" && backCount <= 0) o.push_back(token(oper));
|
||||
else if (v >= 96 && v < 128 && backCount <= 0) {
|
||||
o.push_back(token("PUSH"+unsignedToDecimal(v - 95)));
|
||||
}
|
||||
else o.push_back(token(unsignedToDecimal(v)));
|
||||
if (v >= 96 && v < 128 && backCount <= 0) {
|
||||
backCount = v - 95;
|
||||
}
|
||||
else backCount--;
|
||||
}
|
||||
return o;
|
||||
}
|
||||
|
||||
// Fragtree -> bin
|
||||
std::string assemble(Node fragTree) {
|
||||
return serialize(flatten(dereference(fragTree)));
|
||||
}
|
||||
|
||||
// Fragtree -> tokens
|
||||
std::vector<Node> prettyAssemble(Node fragTree) {
|
||||
return flatten(dereference(fragTree));
|
||||
}
|
||||
|
||||
// LLL -> bin
|
||||
std::string compileLLL(Node program) {
|
||||
return assemble(buildFragmentTree(program));
|
||||
}
|
||||
|
||||
// LLL -> tokens
|
||||
std::vector<Node> prettyCompileLLL(Node program) {
|
||||
return prettyAssemble(buildFragmentTree(program));
|
||||
}
|
||||
|
||||
// Converts a list of integer values to binary transaction data
|
||||
std::string encodeDatalist(std::vector<std::string> vals) {
|
||||
std::string o;
|
||||
for (unsigned i = 0; i < vals.size(); i++) {
|
||||
std::vector<Node> n = toByteArr(strToNumeric(vals[i]), Metadata(), 32);
|
||||
for (unsigned j = 0; j < n.size(); j++) {
|
||||
int v = decimalToUnsigned(n[j].val);
|
||||
o += (char)v;
|
||||
}
|
||||
}
|
||||
return o;
|
||||
}
|
||||
|
||||
// Converts binary transaction data into a list of integer values
|
||||
std::vector<std::string> decodeDatalist(std::string ser) {
|
||||
std::vector<std::string> out;
|
||||
for (unsigned i = 0; i < ser.length(); i+= 32) {
|
||||
std::string o = "0";
|
||||
for (unsigned j = i; j < i + 32; j++) {
|
||||
int vj = (int)(unsigned char)ser[j];
|
||||
o = decimalAdd(decimalMul(o, "256"), unsignedToDecimal(vj));
|
||||
}
|
||||
out.push_back(o);
|
||||
}
|
||||
return out;
|
||||
}
|
43
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/compiler.h
generated
vendored
Normal file
43
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/compiler.h
generated
vendored
Normal file
@ -0,0 +1,43 @@
|
||||
#ifndef ETHSERP_COMPILER
|
||||
#define ETHSERP_COMPILER
|
||||
|
||||
#include <stdio.h>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include "util.h"
|
||||
|
||||
// Compiled fragtree -> compiled fragtree without labels
|
||||
Node dereference(Node program);
|
||||
|
||||
// LLL -> fragtree
|
||||
Node buildFragmentTree(Node program);
|
||||
|
||||
// Dereferenced fragtree -> opcodes
|
||||
std::vector<Node> flatten(Node derefed);
|
||||
|
||||
// opcodes -> bin
|
||||
std::string serialize(std::vector<Node> codons);
|
||||
|
||||
// Fragtree -> bin
|
||||
std::string assemble(Node fragTree);
|
||||
|
||||
// Fragtree -> opcodes
|
||||
std::vector<Node> prettyAssemble(Node fragTree);
|
||||
|
||||
// LLL -> bin
|
||||
std::string compileLLL(Node program);
|
||||
|
||||
// LLL -> opcodes
|
||||
std::vector<Node> prettyCompileLLL(Node program);
|
||||
|
||||
// bin -> opcodes
|
||||
std::vector<Node> deserialize(std::string ser);
|
||||
|
||||
// Converts a list of integer values to binary transaction data
|
||||
std::string encodeDatalist(std::vector<std::string> vals);
|
||||
|
||||
// Converts binary transaction data into a list of integer values
|
||||
std::vector<std::string> decodeDatalist(std::string ser);
|
||||
|
||||
#endif
|
11
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/example.cpp
generated
vendored
Normal file
11
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/example.cpp
generated
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
#include <libserpent/funcs.h>
|
||||
#include <libserpent/bignum.h>
|
||||
#include <iostream>
|
||||
|
||||
using namespace std;
|
||||
|
||||
int main() {
|
||||
cout << printAST(compileToLLL(get_file_contents("examples/namecoin.se"))) << "\n";
|
||||
cout << decimalSub("10234", "10234") << "\n";
|
||||
cout << decimalSub("10234", "10233") << "\n";
|
||||
}
|
11
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/collatz.se
generated
vendored
Normal file
11
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/collatz.se
generated
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
x = msg.data[0]
|
||||
steps = 0
|
||||
|
||||
while x > 1:
|
||||
steps += 1
|
||||
if (x % 2) == 0:
|
||||
x /= 2
|
||||
else:
|
||||
x = 3 * x + 1
|
||||
|
||||
return(steps)
|
274
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/counterparty/counterparty.se
generated
vendored
Normal file
274
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/counterparty/counterparty.se
generated
vendored
Normal file
@ -0,0 +1,274 @@
|
||||
# Ethereum forks Counterparty in 340 lines of serpent
|
||||
# Not yet tested
|
||||
|
||||
# assets[i] = a registered asset, assets[i].holders[j] = former or current i-holder
|
||||
data assets[2^50](creator, name, calldate, callprice, dividend_paid, holders[2^50], holdersCount)
|
||||
data nextAssetId
|
||||
|
||||
# holdersMap: holdersMap[addr][asset] = 1 if addr holds asset
|
||||
data holdersMap[2^160][2^50]
|
||||
|
||||
# balances[x][y] = how much of y x holds
|
||||
data balances[2^160][2^50]
|
||||
|
||||
# orders[a][b] = heap of indices to (c, d, e)
|
||||
# = c offers to sell d units of a at a price of e units of b per 10^18 units
|
||||
# of a
|
||||
data orderbooks[2^50][2^50]
|
||||
|
||||
# store of general order data
|
||||
data orders[2^50](seller, asset_sold, quantity, price)
|
||||
data ordersCount
|
||||
|
||||
# data feeds
|
||||
data feeds[2^50](owner, value)
|
||||
data feedCount
|
||||
|
||||
# heap
|
||||
data heap
|
||||
extern heap: [register, push, pop, top, size]
|
||||
|
||||
data cfds[2^50](maker, acceptor, feed, asset, strike, leverage, min, max, maturity)
|
||||
data cfdCount
|
||||
|
||||
data bets[2^50](maker, acceptor, feed, asset, makerstake, acceptorstake, eqtest, maturity)
|
||||
data betCount
|
||||
|
||||
def init():
|
||||
heap = create('heap.se')
|
||||
|
||||
# Add units (internal method)
|
||||
def add(to, asset, value):
|
||||
assert msg.sender == self
|
||||
self.balances[to][asset] += value
|
||||
# Add the holder to the holders list
|
||||
if not self.holdersMap[to][asset]:
|
||||
self.holdersMap[to][asset] = 1
|
||||
c = self.assets[asset].holdersCount
|
||||
self.assets[asset].holders[c] = to
|
||||
self.assets[asset].holdersCount = c + 1
|
||||
|
||||
# Register a new asset
|
||||
def register_asset(q, name, calldate, callprice):
|
||||
newid = self.nextAssetId
|
||||
self.assets[newid].creator = msg.sender
|
||||
self.assets[newid].name = name
|
||||
self.assets[newid].calldate = calldate
|
||||
self.assets[newid].callprice = callprice
|
||||
self.assets[newid].holders[0] = msg.sender
|
||||
self.assets[newid].holdersCount = 1
|
||||
self.balances[msg.sender][newid] = q
|
||||
self.holdersMap[msg.sender][newid] = 1
|
||||
|
||||
# Send
|
||||
def send(to, asset, value):
|
||||
fromval = self.balances[msg.sender][asset]
|
||||
if fromval >= value:
|
||||
self.balances[msg.sender][asset] -= value
|
||||
self.add(to, asset, value)
|
||||
|
||||
# Order
|
||||
def mkorder(selling, buying, quantity, price):
|
||||
# Make sure you have enough to pay for the order
|
||||
assert self.balances[msg.sender][selling] >= quantity:
|
||||
# Try to match existing orders
|
||||
o = orderbooks[buying][selling]
|
||||
if not o:
|
||||
o = self.heap.register()
|
||||
orderbooks[selling][buying] = o
|
||||
sz = self.heap.size(o)
|
||||
invprice = 10^36 / price
|
||||
while quantity > 0 and sz > 0:
|
||||
orderid = self.heap.pop()
|
||||
p = self.orders[orderid].price
|
||||
if p > invprice:
|
||||
sz = 0
|
||||
else:
|
||||
q = self.orders[orderid].quantity
|
||||
oq = min(q, quantity)
|
||||
b = self.orders[orderid].seller
|
||||
self.balances[msg.sender][selling] -= oq * p / 10^18
|
||||
self.add(msg.sender, buying, oq)
|
||||
self.add(b, selling, oq * p / 10^18)
|
||||
self.orders[orderid].quantity = q - oq
|
||||
if oq == q:
|
||||
self.orders[orderid].seller = 0
|
||||
self.orders[orderid].price = 0
|
||||
self.orders[orderid].asset_sold = 0
|
||||
quantity -= oq
|
||||
sz -= 1
|
||||
assert quantity > 0
|
||||
# Make the order
|
||||
c = self.ordersCount
|
||||
self.orders[c].seller = msg.sender
|
||||
self.orders[c].asset_sold = selling
|
||||
self.orders[c].quantity = quantity
|
||||
self.orders[c].price = price
|
||||
self.ordersCount += 1
|
||||
# Add it to the heap
|
||||
o = orderbooks[selling][buying]
|
||||
if not o:
|
||||
o = self.heap.register()
|
||||
orderbooks[selling][buying] = o
|
||||
self.balances[msg.sender][selling] -= quantity
|
||||
self.heap.push(o, price, c)
|
||||
return(c)
|
||||
|
||||
def cancel_order(id):
|
||||
if self.orders[id].seller == msg.sender:
|
||||
self.orders[id].seller = 0
|
||||
self.orders[id].price = 0
|
||||
self.balances[msg.sender][self.orders[id].asset_sold] += self.orders[id].quantity
|
||||
self.orders[id].quantity = 0
|
||||
self.orders[id].asset_sold = 0
|
||||
|
||||
def register_feed():
|
||||
c = self.feedCount
|
||||
self.feeds[c].owner = msg.sender
|
||||
self.feedCount = c + 1
|
||||
return(c)
|
||||
|
||||
def set_feed(id, v):
|
||||
if self.feeds[id].owner == msg.sender:
|
||||
self.feeds[id].value = v
|
||||
|
||||
def mk_cfd_offer(feed, asset, strike, leverage, min, max, maturity):
|
||||
b = self.balances[msg.sender][asset]
|
||||
req = max((strike - min) * leverage, (strike - max) * leverage)
|
||||
assert b >= req
|
||||
self.balances[msg.sender][asset] = b - req
|
||||
c = self.cfdCount
|
||||
self.cfds[c].maker = msg.sender
|
||||
self.cfds[c].feed = feed
|
||||
self.cfds[c].asset = asset
|
||||
self.cfds[c].strike = strike
|
||||
self.cfds[c].leverage = leverage
|
||||
self.cfds[c].min = min
|
||||
self.cfds[c].max = max
|
||||
self.cfds[c].maturity = maturity
|
||||
self.cfdCount = c + 1
|
||||
return(c)
|
||||
|
||||
def accept_cfd_offer(c):
|
||||
assert not self.cfds[c].acceptor and self.cfds[c].maker
|
||||
asset = self.cfds[c].asset
|
||||
strike = self.cfds[c].strike
|
||||
min = self.cfds[c].min
|
||||
max = self.cfds[c].max
|
||||
leverage = self.cfds[c].leverage
|
||||
b = self.balances[msg.sender][asset]
|
||||
req = max((min - strike) * leverage, (max - strike) * leverage)
|
||||
assert b >= req
|
||||
self.balances[msg.sender][asset] = b - req
|
||||
self.cfds[c].acceptor = msg.sender
|
||||
self.cfds[c].maturity += block.timestamp
|
||||
|
||||
def claim_cfd_offer(c):
|
||||
asset = self.cfds[c].asset
|
||||
strike = self.cfds[c].strike
|
||||
min = self.cfds[c].min
|
||||
max = self.cfds[c].max
|
||||
leverage = self.cfds[c].leverage
|
||||
v = self.feeds[self.cfds[c].feed].value
|
||||
assert v <= min or v >= max or block.timestamp >= self.cfds[c].maturity
|
||||
maker_req = max((strike - min) * leverage, (strike - max) * leverage)
|
||||
acceptor_req = max((min - strike) * leverage, (max - strike) * leverage)
|
||||
paydelta = (strike - v) * leverage
|
||||
self.add(self.cfds[c].maker, asset, maker_req + paydelta)
|
||||
self.add(self.cfds[c].acceptor, asset, acceptor_req - paydelta)
|
||||
self.cfds[c].maker = 0
|
||||
self.cfds[c].acceptor = 0
|
||||
self.cfds[c].feed = 0
|
||||
self.cfds[c].asset = 0
|
||||
self.cfds[c].strike = 0
|
||||
self.cfds[c].leverage = 0
|
||||
self.cfds[c].min = 0
|
||||
self.cfds[c].max = 0
|
||||
self.cfds[c].maturity = 0
|
||||
|
||||
def withdraw_cfd_offer(c):
|
||||
if self.cfds[c].maker == msg.sender and not self.cfds[c].acceptor:
|
||||
asset = self.cfds[c].asset
|
||||
strike = self.cfds[c].strike
|
||||
min = self.cfds[c].min
|
||||
max = self.cfds[c].max
|
||||
leverage = self.cfds[c].leverage
|
||||
maker_req = max((strike - min) * leverage, (strike - max) * leverage)
|
||||
self.balances[self.cfds[c].maker][asset] += maker_req
|
||||
self.cfds[c].maker = 0
|
||||
self.cfds[c].acceptor = 0
|
||||
self.cfds[c].feed = 0
|
||||
self.cfds[c].asset = 0
|
||||
self.cfds[c].strike = 0
|
||||
self.cfds[c].leverage = 0
|
||||
self.cfds[c].min = 0
|
||||
self.cfds[c].max = 0
|
||||
self.cfds[c].maturity = 0
|
||||
|
||||
|
||||
def mk_bet_offer(feed, asset, makerstake, acceptorstake, eqtest, maturity):
|
||||
assert self.balances[msg.sender][asset] >= makerstake
|
||||
c = self.betCount
|
||||
self.bets[c].maker = msg.sender
|
||||
self.bets[c].feed = feed
|
||||
self.bets[c].asset = asset
|
||||
self.bets[c].makerstake = makerstake
|
||||
self.bets[c].acceptorstake = acceptorstake
|
||||
self.bets[c].eqtest = eqtest
|
||||
self.bets[c].maturity = maturity
|
||||
self.balances[msg.sender][asset] -= makerstake
|
||||
self.betCount = c + 1
|
||||
return(c)
|
||||
|
||||
def accept_bet_offer(c):
|
||||
assert self.bets[c].maker and not self.bets[c].acceptor
|
||||
asset = self.bets[c].asset
|
||||
acceptorstake = self.bets[c].acceptorstake
|
||||
assert self.balances[msg.sender][asset] >= acceptorstake
|
||||
self.balances[msg.sender][asset] -= acceptorstake
|
||||
self.bets[c].acceptor = msg.sender
|
||||
|
||||
def claim_bet_offer(c):
|
||||
assert block.timestamp >= self.bets[c].maturity
|
||||
v = self.feeds[self.bets[c].feed].value
|
||||
totalstake = self.bets[c].makerstake + self.bets[c].acceptorstake
|
||||
if v == self.bets[c].eqtest:
|
||||
self.add(self.bets[c].maker, self.bets[c].asset, totalstake)
|
||||
else:
|
||||
self.add(self.bets[c].acceptor, self.bets[c].asset, totalstake)
|
||||
self.bets[c].maker = 0
|
||||
self.bets[c].feed = 0
|
||||
self.bets[c].asset = 0
|
||||
self.bets[c].makerstake = 0
|
||||
self.bets[c].acceptorstake = 0
|
||||
self.bets[c].eqtest = 0
|
||||
self.bets[c].maturity = 0
|
||||
|
||||
def cancel_bet(c):
|
||||
assert not self.bets[c].acceptor and msg.sender == self.bets[c].maker
|
||||
self.balances[msg.sender][self.bets[c].asset] += self.bets[c].makerstake
|
||||
self.bets[c].maker = 0
|
||||
self.bets[c].feed = 0
|
||||
self.bets[c].asset = 0
|
||||
self.bets[c].makerstake = 0
|
||||
self.bets[c].acceptorstake = 0
|
||||
self.bets[c].eqtest = 0
|
||||
self.bets[c].maturity = 0
|
||||
|
||||
def dividend(holder_asset, divvying_asset, ratio):
|
||||
i = 0
|
||||
sz = self.assets[holder_asset].holdersCount
|
||||
t = 0
|
||||
holders = array(sz)
|
||||
payments = array(sz)
|
||||
while i < sz:
|
||||
holders[i] = self.assets[holder_asset].holders[i]
|
||||
payments[i] = self.balances[holders[i]][holder_asset] * ratio / 10^18
|
||||
t += payments[i]
|
||||
i += 1
|
||||
if self.balances[msg.sender][divvying_asset] >= t:
|
||||
i = 0
|
||||
while i < sz:
|
||||
self.add(holders[i], divvying_asset, payments[i])
|
||||
i += 1
|
||||
self.balances[msg.sender][divvying_asset] -= t
|
69
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/counterparty/heap.se
generated
vendored
Normal file
69
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/counterparty/heap.se
generated
vendored
Normal file
@ -0,0 +1,69 @@
|
||||
data heaps[2^50](owner, size, nodes[2^50](key, value))
|
||||
data heapIndex
|
||||
|
||||
def register():
|
||||
i = self.heapIndex
|
||||
self.heaps[i].owner = msg.sender
|
||||
self.heapIndex = i + 1
|
||||
return(i)
|
||||
|
||||
def push(heap, key, value):
|
||||
assert msg.sender == self.heaps[heap].owner
|
||||
sz = self.heaps[heap].size
|
||||
self.heaps[heap].nodes[sz].key = key
|
||||
self.heaps[heap].nodes[sz].value = value
|
||||
k = sz + 1
|
||||
while k > 1:
|
||||
bottom = self.heaps[heap].nodes[k].key
|
||||
top = self.heaps[heap].nodes[k/2].key
|
||||
if bottom < top:
|
||||
tvalue = self.heaps[heap].nodes[k/2].value
|
||||
bvalue = self.heaps[heap].nodes[k].value
|
||||
self.heaps[heap].nodes[k].key = top
|
||||
self.heaps[heap].nodes[k].value = tvalue
|
||||
self.heaps[heap].nodes[k/2].key = bottom
|
||||
self.heaps[heap].nodes[k/2].value = bvalue
|
||||
k /= 2
|
||||
else:
|
||||
k = 0
|
||||
self.heaps[heap].size = sz + 1
|
||||
|
||||
def pop(heap):
|
||||
sz = self.heaps[heap].size
|
||||
assert sz
|
||||
prevtop = self.heaps[heap].nodes[1].value
|
||||
self.heaps[heap].nodes[1].key = self.heaps[heap].nodes[sz].key
|
||||
self.heaps[heap].nodes[1].value = self.heaps[heap].nodes[sz].value
|
||||
self.heaps[heap].nodes[sz].key = 0
|
||||
self.heaps[heap].nodes[sz].value = 0
|
||||
top = self.heaps[heap].nodes[1].key
|
||||
k = 1
|
||||
while k * 2 < sz:
|
||||
bottom1 = self.heaps[heap].nodes[k * 2].key
|
||||
bottom2 = self.heaps[heap].nodes[k * 2 + 1].key
|
||||
if bottom1 < top and (bottom1 < bottom2 or k * 2 + 1 >= sz):
|
||||
tvalue = self.heaps[heap].nodes[1].value
|
||||
bvalue = self.heaps[heap].nodes[k * 2].value
|
||||
self.heaps[heap].nodes[k].key = bottom1
|
||||
self.heaps[heap].nodes[k].value = bvalue
|
||||
self.heaps[heap].nodes[k * 2].key = top
|
||||
self.heaps[heap].nodes[k * 2].value = tvalue
|
||||
k = k * 2
|
||||
elif bottom2 < top and bottom2 < bottom1 and k * 2 + 1 < sz:
|
||||
tvalue = self.heaps[heap].nodes[1].value
|
||||
bvalue = self.heaps[heap].nodes[k * 2 + 1].value
|
||||
self.heaps[heap].nodes[k].key = bottom2
|
||||
self.heaps[heap].nodes[k].value = bvalue
|
||||
self.heaps[heap].nodes[k * 2 + 1].key = top
|
||||
self.heaps[heap].nodes[k * 2 + 1].value = tvalue
|
||||
k = k * 2 + 1
|
||||
else:
|
||||
k = sz
|
||||
self.heaps[heap].size = sz - 1
|
||||
return(prevtop)
|
||||
|
||||
def top(heap):
|
||||
return(self.heaps[heap].nodes[1].value)
|
||||
|
||||
def size(heap):
|
||||
return(self.heaps[heap].size)
|
53
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/crowdfund.se
generated
vendored
Normal file
53
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/crowdfund.se
generated
vendored
Normal file
@ -0,0 +1,53 @@
|
||||
data campaigns[2^80](recipient, goal, deadline, contrib_total, contrib_count, contribs[2^50](sender, value))
|
||||
|
||||
def create_campaign(id, recipient, goal, timelimit):
|
||||
if self.campaigns[id].recipient:
|
||||
return(0)
|
||||
self.campaigns[id].recipient = recipient
|
||||
self.campaigns[id].goal = goal
|
||||
self.campaigns[id].deadline = block.timestamp + timelimit
|
||||
|
||||
def contribute(id):
|
||||
# Update contribution total
|
||||
total_contributed = self.campaigns[id].contrib_total + msg.value
|
||||
self.campaigns[id].contrib_total = total_contributed
|
||||
|
||||
# Record new contribution
|
||||
sub_index = self.campaigns[id].contrib_count
|
||||
self.campaigns[id].contribs[sub_index].sender = msg.sender
|
||||
self.campaigns[id].contribs[sub_index].value = msg.value
|
||||
self.campaigns[id].contrib_count = sub_index + 1
|
||||
|
||||
# Enough funding?
|
||||
if total_contributed >= self.campaigns[id].goal:
|
||||
send(self.campaigns[id].recipient, total_contributed)
|
||||
self.clear(id)
|
||||
return(1)
|
||||
|
||||
# Expired?
|
||||
if block.timestamp > self.campaigns[id].deadline:
|
||||
i = 0
|
||||
c = self.campaigns[id].contrib_count
|
||||
while i < c:
|
||||
send(self.campaigns[id].contribs[i].sender, self.campaigns[id].contribs[i].value)
|
||||
i += 1
|
||||
self.clear(id)
|
||||
return(2)
|
||||
|
||||
def progress_report(id):
|
||||
return(self.campaigns[id].contrib_total)
|
||||
|
||||
# Clearing function for internal use
|
||||
def clear(id):
|
||||
if self == msg.sender:
|
||||
self.campaigns[id].recipient = 0
|
||||
self.campaigns[id].goal = 0
|
||||
self.campaigns[id].deadline = 0
|
||||
c = self.campaigns[id].contrib_count
|
||||
self.campaigns[id].contrib_count = 0
|
||||
self.campaigns[id].contrib_total = 0
|
||||
i = 0
|
||||
while i < c:
|
||||
self.campaigns[id].contribs[i].sender = 0
|
||||
self.campaigns[id].contribs[i].value = 0
|
||||
i += 1
|
136
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/cyberdyne/futarchy.se
generated
vendored
Normal file
136
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/cyberdyne/futarchy.se
generated
vendored
Normal file
@ -0,0 +1,136 @@
|
||||
# 0: current epoch
|
||||
# 1: number of proposals
|
||||
# 2: master currency
|
||||
# 3: last winning market
|
||||
# 4: last txid
|
||||
# 5: long-term ema currency units purchased
|
||||
# 6: last block when currency units purchased
|
||||
# 7: ether allocated to last round
|
||||
# 8: last block when currency units claimed
|
||||
# 9: ether allocated to current round
|
||||
# 1000+: [proposal address, market ID, totprice, totvolume]
|
||||
|
||||
init:
|
||||
# We technically have two levels of epoch here. We have
|
||||
# one epoch of 1000, to synchronize with the 1000 epoch
|
||||
# of the market, and then 100 of those epochs make a
|
||||
# meta-epoch (I'll nominate the term "seculum") over
|
||||
# which the futarchy protocol will take place
|
||||
contract.storage[0] = block.number / 1000
|
||||
# The master currency of the futarchy. The futarchy will
|
||||
# assign currency units to whoever the prediction market
|
||||
# thinks will best increase the currency's value
|
||||
master_currency = create('subcurrency.se')
|
||||
contract.storage[2] = master_currency
|
||||
code:
|
||||
curepoch = block.number / 1000
|
||||
prevepoch = contract.storage[0]
|
||||
if curepoch > prevepoch:
|
||||
if (curepoch % 100) > 50:
|
||||
# Collect price data
|
||||
# We take an average over 50 subepochs to determine
|
||||
# the price of each asset, weighting by volume to
|
||||
# prevent abuse
|
||||
contract.storage[0] = curepoch
|
||||
i = 0
|
||||
numprop = contract.storage[1]
|
||||
while i < numprop:
|
||||
market = contract.storage[1001 + i * 4]
|
||||
price = call(market, 2)
|
||||
volume = call(market, 3)
|
||||
contract.storage[1002 + i * 4] += price
|
||||
contract.storage[1003 + i * 4] += volume * price
|
||||
i += 1
|
||||
if (curepoch / 100) > (prevepoch / 100):
|
||||
# If we are entering a new seculum, we determine the
|
||||
# market with the highest total average price
|
||||
best = 0
|
||||
bestmarket = 0
|
||||
besti = 0
|
||||
i = 0
|
||||
while i < numprop:
|
||||
curtotprice = contract.storage[1002 + i * 4]
|
||||
curvolume = contract.storage[1002 + i * 4]
|
||||
curavgprice = curtotprice / curvolume
|
||||
if curavgprice > best:
|
||||
best = curavgprice
|
||||
besti = i
|
||||
bestmarket = contract.storage[1003 + i * 4]
|
||||
i += 1
|
||||
# Reset the number of proposals to 0
|
||||
contract.storage[1] = 0
|
||||
# Reward the highest proposal
|
||||
call(contract.storage[2], [best, 10^9, 0], 3)
|
||||
# Record the winning market so we can later appropriately
|
||||
# compensate the participants
|
||||
contract.storage[2] = bestmarket
|
||||
# The amount of ether allocated to the last round
|
||||
contract.storage[7] = contract.storage[9]
|
||||
# The amount of ether allocated to the next round
|
||||
contract.storage[9] = contract.balance / 2
|
||||
# Make a proposal [0, address]
|
||||
if msg.data[0] == 0 and curepoch % 100 < 50:
|
||||
pid = contract.storage[1]
|
||||
market = create('market.se')
|
||||
c1 = create('subcurrency.se')
|
||||
c2 = create('subcurrency.se')
|
||||
call(market, [c1, c2], 2)
|
||||
contract.storage[1000 + pid * 4] = msg.data[1]
|
||||
contract.storage[1001 + pid * 4] = market
|
||||
contract.storage[1] += 1
|
||||
# Claim ether [1, address]
|
||||
# One unit of the first currency in the last round's winning
|
||||
# market entitles you to a quantity of ether that was decided
|
||||
# at the start of that epoch
|
||||
elif msg.data[0] == 1:
|
||||
first_subcurrency = call(contract.storage[2], 3)
|
||||
# We ask the first subcurrency contract what the last transaction was. The
|
||||
# way to make a claim is to send the amount of first currency units that
|
||||
# you wish to claim with, and then immediately call this contract. For security
|
||||
# it makes sense to set up a tx which sends both messages in sequence atomically
|
||||
data = call(first_subcurrency, [], 0, 4)
|
||||
from = data[0]
|
||||
to = data[1]
|
||||
value = data[2]
|
||||
txid = data[3]
|
||||
if txid > contract.storage[4] and to == contract.address:
|
||||
send(to, contract.storage[7] * value / 10^9)
|
||||
contract.storage[4] = txid
|
||||
# Claim second currency [2, address]
|
||||
# One unit of the second currency in the last round's winning
|
||||
# market entitles you to one unit of the futarchy's master
|
||||
# currency
|
||||
elif msg.data[0] == 2:
|
||||
second_subcurrency = call(contract.storage[2], 3)
|
||||
data = call(first_subcurrency, [], 0, 4)
|
||||
from = data[0]
|
||||
to = data[1]
|
||||
value = data[2]
|
||||
txid = data[3]
|
||||
if txid > contract.storage[4] and to == contract.address:
|
||||
call(contract.storage[2], [to, value], 2)
|
||||
contract.storage[4] = txid
|
||||
# Purchase currency for ether (target releasing 10^9 units per seculum)
|
||||
# Price starts off 1 eth for 10^9 units but increases hyperbolically to
|
||||
# limit issuance
|
||||
elif msg.data[0] == 3:
|
||||
pre_ema = contract.storage[5]
|
||||
post_ema = pre_ema + msg.value
|
||||
pre_reserve = 10^18 / (10^9 + pre_ema / 10^9)
|
||||
post_reserve = 10^18 / (10^9 + post_ema / 10^9)
|
||||
call(contract.storage[2], [msg.sender, pre_reserve - post_reserve], 2)
|
||||
last_sold = contract.storage[6]
|
||||
contract.storage[5] = pre_ema * (100000 + last_sold - block.number) + msg.value
|
||||
contract.storage[6] = block.number
|
||||
# Claim all currencies as the ether miner of the current block
|
||||
elif msg.data[0] == 2 and msg.sender == block.coinbase and block.number > contract.storage[8]:
|
||||
i = 0
|
||||
numproposals = contract.storage[1]
|
||||
while i < numproposals:
|
||||
market = contract.storage[1001 + i * 3]
|
||||
fc = call(market, 4)
|
||||
sc = call(market, 5)
|
||||
call(fc, [msg.sender, 1000], 2)
|
||||
call(sc, [msg.sender, 1000], 2)
|
||||
i += 1
|
||||
contract.storage[8] = block.number
|
55
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/cyberdyne/heap.se
generated
vendored
Normal file
55
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/cyberdyne/heap.se
generated
vendored
Normal file
@ -0,0 +1,55 @@
|
||||
# 0: size
|
||||
# 1-n: elements
|
||||
|
||||
init:
|
||||
contract.storage[1000] = msg.sender
|
||||
code:
|
||||
# Only owner of the heap is allowed to modify it
|
||||
if contract.storage[1000] != msg.sender:
|
||||
stop
|
||||
# push
|
||||
if msg.data[0] == 0:
|
||||
sz = contract.storage[0]
|
||||
contract.storage[sz + 1] = msg.data[1]
|
||||
k = sz + 1
|
||||
while k > 1:
|
||||
bottom = contract.storage[k]
|
||||
top = contract.storage[k/2]
|
||||
if bottom < top:
|
||||
contract.storage[k] = top
|
||||
contract.storage[k/2] = bottom
|
||||
k /= 2
|
||||
else:
|
||||
k = 0
|
||||
contract.storage[0] = sz + 1
|
||||
# pop
|
||||
elif msg.data[0] == 1:
|
||||
sz = contract.storage[0]
|
||||
if !sz:
|
||||
return(0)
|
||||
prevtop = contract.storage[1]
|
||||
contract.storage[1] = contract.storage[sz]
|
||||
contract.storage[sz] = 0
|
||||
top = contract.storage[1]
|
||||
k = 1
|
||||
while k * 2 < sz:
|
||||
bottom1 = contract.storage[k * 2]
|
||||
bottom2 = contract.storage[k * 2 + 1]
|
||||
if bottom1 < top and (bottom1 < bottom2 or k * 2 + 1 >= sz):
|
||||
contract.storage[k] = bottom1
|
||||
contract.storage[k * 2] = top
|
||||
k = k * 2
|
||||
elif bottom2 < top and bottom2 < bottom1 and k * 2 + 1 < sz:
|
||||
contract.storage[k] = bottom2
|
||||
contract.storage[k * 2 + 1] = top
|
||||
k = k * 2 + 1
|
||||
else:
|
||||
k = sz
|
||||
contract.storage[0] = sz - 1
|
||||
return(prevtop)
|
||||
# top
|
||||
elif msg.data[0] == 2:
|
||||
return(contract.storage[1])
|
||||
# size
|
||||
elif msg.data[0] == 3:
|
||||
return(contract.storage[0])
|
117
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/cyberdyne/market.se
generated
vendored
Normal file
117
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/cyberdyne/market.se
generated
vendored
Normal file
@ -0,0 +1,117 @@
|
||||
# Creates a decentralized market between any two subcurrencies
|
||||
|
||||
# Here, the first subcurrency is the base asset and the second
|
||||
# subcurrency is the asset priced against the base asset. Hence,
|
||||
# "buying" refers to trading the first for the second, and
|
||||
# "selling" refers to trading the second for the first
|
||||
|
||||
# storage 0: buy orders
|
||||
# storage 1: sell orders
|
||||
# storage 1000: first subcurrency
|
||||
# storage 1001: last first subcurrency txid
|
||||
# storage 2000: second subcurrency
|
||||
# storage 2001: last second subcurrency txid
|
||||
# storage 3000: current epoch
|
||||
# storage 4000: price
|
||||
# storage 4001: volume
|
||||
|
||||
init:
|
||||
# Heap for buy orders
|
||||
contract.storage[0] = create('heap.se')
|
||||
# Heap for sell orders
|
||||
contract.storage[1] = create('heap.se')
|
||||
code:
|
||||
# Initialize with [ first_subcurrency, second_subcurrency ]
|
||||
if !contract.storage[1000]:
|
||||
contract.storage[1000] = msg.data[0] # First subcurrency
|
||||
contract.storage[1001] = -1
|
||||
contract.storage[2000] = msg.data[1] # Second subcurrency
|
||||
contract.storage[2001] = -1
|
||||
contract.storage[3000] = block.number / 1000
|
||||
stop
|
||||
first_subcurrency = contract.storage[1000]
|
||||
second_subcurrency = contract.storage[2000]
|
||||
buy_heap = contract.storage[0]
|
||||
sell_heap = contract.storage[1]
|
||||
# This contract operates in "epochs" of 100 blocks
|
||||
# At the end of each epoch, we process all orders
|
||||
# simultaneously, independent of order. This algorithm
|
||||
# prevents front-running, and generates a profit from
|
||||
# the spread. The profit is permanently kept in the
|
||||
# market (ie. destroyed), making both subcurrencies
|
||||
# more valuable
|
||||
|
||||
# Epoch transition code
|
||||
if contract.storage[3000] < block.number / 100:
|
||||
done = 0
|
||||
volume = 0
|
||||
while !done:
|
||||
# Grab the top buy and sell order from each heap
|
||||
topbuy = call(buy_heap, 1)
|
||||
topsell = call(sell_heap, 1)
|
||||
# An order is recorded in the heap as:
|
||||
# Buys: (2^48 - 1 - price) * 2^208 + units of first currency * 2^160 + from
|
||||
# Sells: price * 2^208 + units of second currency * 2^160 + from
|
||||
buyprice = -(topbuy / 2^208)
|
||||
buyfcvalue = (topbuy / 2^160) % 2^48
|
||||
buyer = topbuy % 2^160
|
||||
sellprice = topsell / 2^208
|
||||
sellscvalue = (topsell / 2^160) % 2^48
|
||||
seller = topsell % 2^160
|
||||
# Heap empty, or no more matching orders
|
||||
if not topbuy or not topsell or buyprice < sellprice:
|
||||
done = 1
|
||||
else:
|
||||
# Add to volume counter
|
||||
volume += buyfcvalue
|
||||
# Calculate how much of the second currency the buyer gets, and
|
||||
# how much of the first currency the seller gets
|
||||
sellfcvalue = sellscvalue / buyprice
|
||||
buyscvalue = buyfcvalue * sellprice
|
||||
# Send the currency units along
|
||||
call(second_subcurrency, [buyer, buyscvalue], 2)
|
||||
call(first_subcurrency, [seller, sellfcvalue], 2)
|
||||
if volume:
|
||||
contract.storage[4000] = (buyprice + sellprice) / 2
|
||||
contract.storage[4001] = volume
|
||||
contract.storage[3000] = block.number / 100
|
||||
# Make buy order [0, price]
|
||||
if msg.data[0] == 0:
|
||||
# We ask the first subcurrency contract what the last transaction was. The
|
||||
# way to make a buy order is to send the amount of first currency units that
|
||||
# you wish to buy with, and then immediately call this contract. For security
|
||||
# it makes sense to set up a tx which sends both messages in sequence atomically
|
||||
data = call(first_subcurrency, [], 0, 4)
|
||||
from = data[0]
|
||||
to = data[1]
|
||||
value = data[2]
|
||||
txid = data[3]
|
||||
price = msg.data[1]
|
||||
if txid > contract.storage[1001] and to == contract.address:
|
||||
contract.storage[1001] = txid
|
||||
# Adds the order to the heap
|
||||
call(buy_heap, [0, -price * 2^208 + (value % 2^48) * 2^160 + from], 2)
|
||||
# Make sell order [1, price]
|
||||
elif msg.data[0] == 1:
|
||||
# Same mechanics as buying
|
||||
data = call(second_subcurrency, [], 0, 4)
|
||||
from = data[0]
|
||||
to = data[1]
|
||||
value = data[2]
|
||||
txid = data[3]
|
||||
price = msg.data[1]
|
||||
if txid > contract.storage[2001] and to == contract.address:
|
||||
contract.storage[2001] = txid
|
||||
call(sell_heap, [0, price * 2^208 + (value % 2^48) * 2^160 + from], 2)
|
||||
# Ask for price
|
||||
elif msg.data[0] == 2:
|
||||
return(contract.storage[4000])
|
||||
# Ask for volume
|
||||
elif msg.data[0] == 3:
|
||||
return(contract.storage[1000])
|
||||
# Ask for first currency
|
||||
elif msg.data[0] == 4:
|
||||
return(contract.storage[2000])
|
||||
# Ask for second currency
|
||||
elif msg.data[0] == 5:
|
||||
return(contract.storage[4001])
|
35
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/cyberdyne/subcurrency.se
generated
vendored
Normal file
35
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/cyberdyne/subcurrency.se
generated
vendored
Normal file
@ -0,0 +1,35 @@
|
||||
# Initialization
|
||||
# Admin can issue and delete at will
|
||||
init:
|
||||
contract.storage[0] = msg.sender
|
||||
code:
|
||||
# If a message with one item is sent, that's a balance query
|
||||
if msg.datasize == 1:
|
||||
addr = msg.data[0]
|
||||
return(contract.storage[addr])
|
||||
# If a message with two items [to, value] are sent, that's a transfer request
|
||||
elif msg.datasize == 2:
|
||||
from = msg.sender
|
||||
fromvalue = contract.storage[from]
|
||||
to = msg.data[0]
|
||||
value = msg.data[1]
|
||||
if fromvalue >= value and value > 0 and to > 4:
|
||||
contract.storage[from] = fromvalue - value
|
||||
contract.storage[to] += value
|
||||
contract.storage[2] = from
|
||||
contract.storage[3] = to
|
||||
contract.storage[4] = value
|
||||
contract.storage[5] += 1
|
||||
return(1)
|
||||
return(0)
|
||||
elif msg.datasize == 3 and msg.sender == contract.storage[0]:
|
||||
# Admin can issue at will by sending a [to, value, 0] message
|
||||
if msg.data[2] == 0:
|
||||
contract.storage[msg.data[0]] += msg.data[1]
|
||||
# Change admin [ newadmin, 0, 1 ]
|
||||
# Set admin to 0 to disable administration
|
||||
elif msg.data[2] == 1:
|
||||
contract.storage[0] = msg.data[0]
|
||||
# Fetch last transaction
|
||||
else:
|
||||
return([contract.storage[2], contract.storage[3], contract.storage[4], contract.storage[5]], 4)
|
39
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/cyberdyne/test.py
generated
vendored
Normal file
39
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/cyberdyne/test.py
generated
vendored
Normal file
@ -0,0 +1,39 @@
|
||||
from __future__ import print_function
|
||||
import pyethereum
|
||||
t = pyethereum.tester
|
||||
s = t.state()
|
||||
# Create currencies
|
||||
c1 = s.contract('subcurrency.se')
|
||||
print("First currency: %s" % c1)
|
||||
c2 = s.contract('subcurrency.se')
|
||||
print("First currency: %s" % c2)
|
||||
# Allocate units
|
||||
s.send(t.k0, c1, 0, [t.a0, 1000, 0])
|
||||
s.send(t.k0, c1, 0, [t.a1, 1000, 0])
|
||||
s.send(t.k0, c2, 0, [t.a2, 1000000, 0])
|
||||
s.send(t.k0, c2, 0, [t.a3, 1000000, 0])
|
||||
print("Allocated units")
|
||||
# Market
|
||||
m = s.contract('market.se')
|
||||
s.send(t.k0, m, 0, [c1, c2])
|
||||
# Place orders
|
||||
s.send(t.k0, c1, 0, [m, 1000])
|
||||
s.send(t.k0, m, 0, [0, 1200])
|
||||
s.send(t.k1, c1, 0, [m, 1000])
|
||||
s.send(t.k1, m, 0, [0, 1400])
|
||||
s.send(t.k2, c2, 0, [m, 1000000])
|
||||
s.send(t.k2, m, 0, [1, 800])
|
||||
s.send(t.k3, c2, 0, [m, 1000000])
|
||||
s.send(t.k3, m, 0, [1, 600])
|
||||
print("Orders placed")
|
||||
# Next epoch and ping
|
||||
s.mine(100)
|
||||
print("Mined 100")
|
||||
s.send(t.k0, m, 0, [])
|
||||
print("Updating")
|
||||
# Check
|
||||
assert s.send(t.k0, c2, 0, [t.a0]) == [800000]
|
||||
assert s.send(t.k0, c2, 0, [t.a1]) == [600000]
|
||||
assert s.send(t.k0, c1, 0, [t.a2]) == [833]
|
||||
assert s.send(t.k0, c1, 0, [t.a3]) == [714]
|
||||
print("Balance checks passed")
|
12
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/datafeed.se
generated
vendored
Normal file
12
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/datafeed.se
generated
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
# Database updateable only by the original creator
|
||||
data creator
|
||||
|
||||
def init():
|
||||
self.creator = msg.sender
|
||||
|
||||
def update(k, v):
|
||||
if msg.sender == self.creator:
|
||||
self.storage[k] = v
|
||||
|
||||
def query(k):
|
||||
return(self.storage[k])
|
40
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/ecc/ecrecover.se
generated
vendored
Normal file
40
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/ecc/ecrecover.se
generated
vendored
Normal file
@ -0,0 +1,40 @@
|
||||
# So I looked up on Wikipedia what Jacobian form actually is, and noticed that it's
|
||||
# actually a rather different and more clever construction than the naive version
|
||||
# that I created. It may possible to achieve a further 20-50% savings by applying
|
||||
# that version.
|
||||
|
||||
extern all: [call]
|
||||
|
||||
data JORDANMUL
|
||||
data JORDANADD
|
||||
data EXP
|
||||
|
||||
def init():
|
||||
self.JORDANMUL = create('jacobian_mul.se')
|
||||
self.JORDANADD = create('jacobian_add.se')
|
||||
self.EXP = create('modexp.se')
|
||||
|
||||
def call(h, v, r, s):
|
||||
N = -432420386565659656852420866394968145599
|
||||
P = -4294968273
|
||||
h = mod(h, N)
|
||||
r = mod(r, P)
|
||||
s = mod(s, N)
|
||||
Gx = 55066263022277343669578718895168534326250603453777594175500187360389116729240
|
||||
Gy = 32670510020758816978083085130507043184471273380659243275938904335757337482424
|
||||
x = r
|
||||
xcubed = mulmod(mulmod(x, x, P), x, P)
|
||||
beta = self.EXP.call(addmod(xcubed, 7, P), div(P + 1, 4), P)
|
||||
|
||||
# Static-gascost ghetto conditional
|
||||
y_is_positive = mod(v, 2) xor mod(beta, 2)
|
||||
y = beta * y_is_positive + (P - beta) * (1 - y_is_positive)
|
||||
|
||||
GZ = self.JORDANMUL.call(Gx, 1, Gy, 1, N - h, outsz=4)
|
||||
XY = self.JORDANMUL.call(x, 1, y, 1, s, outsz=4)
|
||||
COMB = self.JORDANADD.call(GZ[0], GZ[1], GZ[2], GZ[3], XY[0], XY[1], XY[2], XY[3], 1, outsz=5)
|
||||
COMB[4] = self.EXP.call(r, N - 2, N)
|
||||
Q = self.JORDANMUL.call(data=COMB, datasz=5, outsz=4)
|
||||
ox = mulmod(Q[0], self.EXP.call(Q[1], P - 2, P), P)
|
||||
oy = mulmod(Q[2], self.EXP.call(Q[3], P - 2, P), P)
|
||||
return([ox, oy], 2)
|
1
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/ecc/ecrecover_compiled.evm
generated
vendored
Normal file
1
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/ecc/ecrecover_compiled.evm
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
32
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/ecc/jacobian_add.se
generated
vendored
Normal file
32
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/ecc/jacobian_add.se
generated
vendored
Normal file
@ -0,0 +1,32 @@
|
||||
extern all: [call]
|
||||
data DOUBLE
|
||||
|
||||
def init():
|
||||
self.DOUBLE = create('jacobian_double.se')
|
||||
|
||||
def call(axn, axd, ayn, ayd, bxn, bxd, byn, byd):
|
||||
if !axn and !ayn:
|
||||
o = [bxn, bxd, byn, byd]
|
||||
if !bxn and !byn:
|
||||
o = [axn, axd, ayn, ayd]
|
||||
if o:
|
||||
return(o, 4)
|
||||
with P = -4294968273:
|
||||
if addmod(mulmod(axn, bxd, P), P - mulmod(axd, bxn, P), P) == 0:
|
||||
if addmod(mulmod(ayn, byd, P), P - mulmod(ayd, byn, P), P) == 0:
|
||||
return(self.DOUBLE.call(axn, axd, ayn, ayd, outsz=4), 4)
|
||||
else:
|
||||
return([0, 1, 0, 1], 4)
|
||||
with mn = mulmod(addmod(mulmod(byn, ayd, P), P - mulmod(ayn, byd, P), P), mulmod(bxd, axd, P), P):
|
||||
with md = mulmod(mulmod(byd, ayd, P), addmod(mulmod(bxn, axd, P), P - mulmod(axn, bxd, P), P), P):
|
||||
with msqn = mulmod(mn, mn, P):
|
||||
with msqd = mulmod(md, md, P):
|
||||
with msqman = addmod(mulmod(msqn, axd, P), P - mulmod(msqd, axn, P), P):
|
||||
with msqmad = mulmod(msqd, axd, P):
|
||||
with xn = addmod(mulmod(msqman, bxd, P), P - mulmod(msqmad, bxn, P), P):
|
||||
with xd = mulmod(msqmad, bxd, P):
|
||||
with mamxn = mulmod(mn, addmod(mulmod(axn, xd, P), P - mulmod(xn, axd, P), P), P):
|
||||
with mamxd = mulmod(md, mulmod(axd, xd, P), P):
|
||||
with yn = addmod(mulmod(mamxn, ayd, P), P - mulmod(mamxd, ayn, P), P):
|
||||
with yd = mulmod(mamxd, ayd, P):
|
||||
return([xn, xd, yn, yd], 4)
|
16
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/ecc/jacobian_double.se
generated
vendored
Normal file
16
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/ecc/jacobian_double.se
generated
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
def call(axn, axd, ayn, ayd):
|
||||
if !axn and !ayn:
|
||||
return([0, 1, 0, 1], 4)
|
||||
with P = -4294968273:
|
||||
# No need to add (A, 1) because A = 0 for bitcoin
|
||||
with mn = mulmod(mulmod(mulmod(axn, axn, P), 3, P), ayd, P):
|
||||
with md = mulmod(mulmod(axd, axd, P), mulmod(ayn, 2, P), P):
|
||||
with msqn = mulmod(mn, mn, P):
|
||||
with msqd = mulmod(md, md, P):
|
||||
with xn = addmod(mulmod(msqn, axd, P), P - mulmod(msqd, mulmod(axn, 2, P), P), P):
|
||||
with xd = mulmod(msqd, axd, P):
|
||||
with mamxn = mulmod(addmod(mulmod(axn, xd, P), P - mulmod(axd, xn, P), P), mn, P):
|
||||
with mamxd = mulmod(mulmod(axd, xd, P), md, P):
|
||||
with yn = addmod(mulmod(mamxn, ayd, P), P - mulmod(mamxd, ayn, P), P):
|
||||
with yd = mulmod(mamxd, ayd, P):
|
||||
return([xn, xd, yn, yd], 4)
|
37
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/ecc/jacobian_mul.se
generated
vendored
Normal file
37
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/ecc/jacobian_mul.se
generated
vendored
Normal file
@ -0,0 +1,37 @@
|
||||
# Expected gas cost
|
||||
#
|
||||
# def expect(n, point_at_infinity=False):
|
||||
# n = n % (2**256 - 432420386565659656852420866394968145599)
|
||||
# if point_at_infinity:
|
||||
# return 79
|
||||
# if n == 0:
|
||||
# return 34479
|
||||
# L = int(1 + math.log(n) / math.log(2))
|
||||
# H = len([x for x in b.encode(n, 2) if x == '1'])
|
||||
# return 34221 + 94 * L + 343 * H
|
||||
|
||||
data DOUBLE
|
||||
data ADD
|
||||
|
||||
def init():
|
||||
self.DOUBLE = create('jacobian_double.se')
|
||||
self.ADD = create('jacobian_add.se')
|
||||
|
||||
def call(axn, axd, ayn, ayd, n):
|
||||
n = mod(n, -432420386565659656852420866394968145599)
|
||||
if !axn * !ayn + !n: # Constant-gas version of !axn and !ayn or !n
|
||||
return([0, 1, 0, 1], 4)
|
||||
with o = [0, 0, 1, 0, 1, 0, 0, 0, 0]:
|
||||
with b = 2 ^ 255:
|
||||
while gt(b, 0):
|
||||
if n & b:
|
||||
~call(20000, self.DOUBLE, 0, o + 31, 129, o + 32, 128)
|
||||
o[5] = axn
|
||||
o[6] = axd
|
||||
o[7] = ayn
|
||||
o[8] = ayd
|
||||
~call(20000, self.ADD, 0, o + 31, 257, o + 32, 128)
|
||||
else:
|
||||
~call(20000, self.DOUBLE, 0, o + 31, 129, o + 32, 128)
|
||||
b = div(b, 2)
|
||||
return(o + 32, 4)
|
11
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/ecc/modexp.se
generated
vendored
Normal file
11
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/ecc/modexp.se
generated
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
def call(b, e, m):
|
||||
with o = 1:
|
||||
with bit = 2 ^ 255:
|
||||
while gt(bit, 0):
|
||||
# A touch of loop unrolling for 20% efficiency gain
|
||||
o = mulmod(mulmod(o, o, m), b ^ !(!(e & bit)), m)
|
||||
o = mulmod(mulmod(o, o, m), b ^ !(!(e & div(bit, 2))), m)
|
||||
o = mulmod(mulmod(o, o, m), b ^ !(!(e & div(bit, 4))), m)
|
||||
o = mulmod(mulmod(o, o, m), b ^ !(!(e & div(bit, 8))), m)
|
||||
bit = div(bit, 16)
|
||||
return(o)
|
78
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/ecc/substitutes.py
generated
vendored
Normal file
78
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/ecc/substitutes.py
generated
vendored
Normal file
@ -0,0 +1,78 @@
|
||||
import bitcoin as b
|
||||
import math
|
||||
import sys
|
||||
|
||||
|
||||
def signed(o):
|
||||
return map(lambda x: x - 2**256 if x >= 2**255 else x, o)
|
||||
|
||||
|
||||
def hamming_weight(n):
|
||||
return len([x for x in b.encode(n, 2) if x == '1'])
|
||||
|
||||
|
||||
def binary_length(n):
|
||||
return len(b.encode(n, 2))
|
||||
|
||||
|
||||
def jacobian_mul_substitute(A, B, C, D, N):
|
||||
if A == 0 and C == 0 or (N % b.N) == 0:
|
||||
return {"gas": 86, "output": [0, 1, 0, 1]}
|
||||
else:
|
||||
output = b.jordan_multiply(((A, B), (C, D)), N)
|
||||
return {
|
||||
"gas": 35262 + 95 * binary_length(N % b.N) + 355 * hamming_weight(N % b.N),
|
||||
"output": signed(list(output[0]) + list(output[1]))
|
||||
}
|
||||
|
||||
|
||||
def jacobian_add_substitute(A, B, C, D, E, F, G, H):
|
||||
if A == 0 or E == 0:
|
||||
gas = 149
|
||||
elif (A * F - B * E) % b.P == 0:
|
||||
if (C * H - D * G) % b.P == 0:
|
||||
gas = 442
|
||||
else:
|
||||
gas = 177
|
||||
else:
|
||||
gas = 301
|
||||
output = b.jordan_add(((A, B), (C, D)), ((E, F), (G, H)))
|
||||
return {
|
||||
"gas": gas,
|
||||
"output": signed(list(output[0]) + list(output[1]))
|
||||
}
|
||||
|
||||
|
||||
def modexp_substitute(base, exp, mod):
|
||||
return {
|
||||
"gas": 5150,
|
||||
"output": signed([pow(base, exp, mod) if mod > 0 else 0])
|
||||
}
|
||||
|
||||
|
||||
def ecrecover_substitute(z, v, r, s):
|
||||
P, A, B, N, Gx, Gy = b.P, b.A, b.B, b.N, b.Gx, b.Gy
|
||||
x = r
|
||||
beta = pow(x*x*x+A*x+B, (P + 1) / 4, P)
|
||||
BETA_PREMIUM = modexp_substitute(x, (P + 1) / 4, P)["gas"]
|
||||
y = beta if v % 2 ^ beta % 2 else (P - beta)
|
||||
Gz = b.jordan_multiply(((Gx, 1), (Gy, 1)), (N - z) % N)
|
||||
GZ_PREMIUM = jacobian_mul_substitute(Gx, 1, Gy, 1, (N - z) % N)["gas"]
|
||||
XY = b.jordan_multiply(((x, 1), (y, 1)), s)
|
||||
XY_PREMIUM = jacobian_mul_substitute(x, 1, y, 1, s % N)["gas"]
|
||||
Qr = b.jordan_add(Gz, XY)
|
||||
QR_PREMIUM = jacobian_add_substitute(Gz[0][0], Gz[0][1], Gz[1][0], Gz[1][1],
|
||||
XY[0][0], XY[0][1], XY[1][0], XY[1][1]
|
||||
)["gas"]
|
||||
Q = b.jordan_multiply(Qr, pow(r, N - 2, N))
|
||||
Q_PREMIUM = jacobian_mul_substitute(Qr[0][0], Qr[0][1], Qr[1][0], Qr[1][1],
|
||||
pow(r, N - 2, N))["gas"]
|
||||
R_PREMIUM = modexp_substitute(r, N - 2, N)["gas"]
|
||||
OX_PREMIUM = modexp_substitute(Q[0][1], P - 2, P)["gas"]
|
||||
OY_PREMIUM = modexp_substitute(Q[1][1], P - 2, P)["gas"]
|
||||
Q = b.from_jordan(Q)
|
||||
return {
|
||||
"gas": 991 + BETA_PREMIUM + GZ_PREMIUM + XY_PREMIUM + QR_PREMIUM +
|
||||
Q_PREMIUM + R_PREMIUM + OX_PREMIUM + OY_PREMIUM,
|
||||
"output": signed(Q)
|
||||
}
|
129
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/ecc/test.py
generated
vendored
Normal file
129
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/ecc/test.py
generated
vendored
Normal file
@ -0,0 +1,129 @@
|
||||
import bitcoin as b
|
||||
import random
|
||||
import sys
|
||||
import math
|
||||
from pyethereum import tester as t
|
||||
import substitutes
|
||||
import time
|
||||
|
||||
vals = [random.randrange(2**256) for i in range(12)]
|
||||
|
||||
test_points = [list(p[0]) + list(p[1]) for p in
|
||||
[b.jordan_multiply(((b.Gx, 1), (b.Gy, 1)), r) for r in vals]]
|
||||
|
||||
G = [b.Gx, 1, b.Gy, 1]
|
||||
Z = [0, 1, 0, 1]
|
||||
|
||||
|
||||
def neg_point(p):
|
||||
return [p[0], b.P - p[1], p[2], b.P - p[3]]
|
||||
|
||||
s = t.state()
|
||||
s.block.gas_limit = 10000000
|
||||
t.gas_limit = 1000000
|
||||
|
||||
|
||||
c = s.contract('modexp.se')
|
||||
print "Starting modexp tests"
|
||||
|
||||
for i in range(0, len(vals) - 2, 3):
|
||||
o1 = substitutes.modexp_substitute(vals[i], vals[i+1], vals[i+2])
|
||||
o2 = s.profile(t.k0, c, 0, funid=0, abi=vals[i:i+3])
|
||||
#assert o1["gas"] == o2["gas"], (o1, o2)
|
||||
assert o1["output"] == o2["output"], (o1, o2)
|
||||
|
||||
c = s.contract('jacobian_add.se')
|
||||
print "Starting addition tests"
|
||||
|
||||
for i in range(2):
|
||||
P = test_points[i * 2]
|
||||
Q = test_points[i * 2 + 1]
|
||||
NP = neg_point(P)
|
||||
|
||||
o1 = substitutes.jacobian_add_substitute(*(P + Q))
|
||||
o2 = s.profile(t.k0, c, 0, funid=0, abi=P + Q)
|
||||
#assert o1["gas"] == o2["gas"], (o1, o2)
|
||||
assert o1["output"] == o2["output"], (o1, o2)
|
||||
|
||||
o1 = substitutes.jacobian_add_substitute(*(P + NP))
|
||||
o2 = s.profile(t.k0, c, 0, funid=0, abi=P + NP)
|
||||
#assert o1["gas"] == o2["gas"], (o1, o2)
|
||||
assert o1["output"] == o2["output"], (o1, o2)
|
||||
|
||||
o1 = substitutes.jacobian_add_substitute(*(P + P))
|
||||
o2 = s.profile(t.k0, c, 0, funid=0, abi=P + P)
|
||||
#assert o1["gas"] == o2["gas"], (o1, o2)
|
||||
assert o1["output"] == o2["output"], (o1, o2)
|
||||
|
||||
o1 = substitutes.jacobian_add_substitute(*(P + Z))
|
||||
o2 = s.profile(t.k0, c, 0, funid=0, abi=P + Z)
|
||||
#assert o1["gas"] == o2["gas"], (o1, o2)
|
||||
assert o1["output"] == o2["output"], (o1, o2)
|
||||
|
||||
o1 = substitutes.jacobian_add_substitute(*(Z + P))
|
||||
o2 = s.profile(t.k0, c, 0, funid=0, abi=Z + P)
|
||||
#assert o1["gas"] == o2["gas"], (o1, o2)
|
||||
assert o1["output"] == o2["output"], (o1, o2)
|
||||
|
||||
|
||||
c = s.contract('jacobian_mul.se')
|
||||
print "Starting multiplication tests"
|
||||
|
||||
|
||||
mul_tests = [
|
||||
Z + [0],
|
||||
Z + [vals[0]],
|
||||
test_points[0] + [0],
|
||||
test_points[1] + [b.N],
|
||||
test_points[2] + [1],
|
||||
test_points[2] + [2],
|
||||
test_points[2] + [3],
|
||||
test_points[2] + [4],
|
||||
test_points[3] + [5],
|
||||
test_points[3] + [6],
|
||||
test_points[4] + [7],
|
||||
test_points[4] + [2**254],
|
||||
test_points[4] + [vals[1]],
|
||||
test_points[4] + [vals[2]],
|
||||
test_points[4] + [vals[3]],
|
||||
test_points[5] + [2**256 - 1],
|
||||
]
|
||||
|
||||
for i, test in enumerate(mul_tests):
|
||||
print 'trying mul_test %i' % i, test
|
||||
o1 = substitutes.jacobian_mul_substitute(*test)
|
||||
o2 = s.profile(t.k0, c, 0, funid=0, abi=test)
|
||||
# assert o1["gas"] == o2["gas"], (o1, o2, test)
|
||||
assert o1["output"] == o2["output"], (o1, o2, test)
|
||||
|
||||
c = s.contract('ecrecover.se')
|
||||
print "Starting ecrecover tests"
|
||||
|
||||
for i in range(5):
|
||||
print 'trying ecrecover_test', vals[i*2], vals[i*2+1]
|
||||
k = vals[i*2]
|
||||
h = vals[i*2+1]
|
||||
V, R, S = b.ecdsa_raw_sign(b.encode(h, 256, 32), k)
|
||||
aa = time.time()
|
||||
o1 = substitutes.ecrecover_substitute(h, V, R, S)
|
||||
print 'sub', time.time() - aa
|
||||
a = time.time()
|
||||
o2 = s.profile(t.k0, c, 0, funid=0, abi=[h, V, R, S])
|
||||
print time.time() - a
|
||||
# assert o1["gas"] == o2["gas"], (o1, o2, h, V, R, S)
|
||||
assert o1["output"] == o2["output"], (o1, o2, h, V, R, S)
|
||||
|
||||
# Explicit tests
|
||||
|
||||
data = [[
|
||||
0xf007a9c78a4b2213220adaaf50c89a49d533fbefe09d52bbf9b0da55b0b90b60,
|
||||
0x1b,
|
||||
0x5228fc9e2fabfe470c32f459f4dc17ef6a0a81026e57e4d61abc3bc268fc92b5,
|
||||
0x697d4221cd7bc5943b482173de95d3114b9f54c5f37cc7f02c6910c6dd8bd107
|
||||
]]
|
||||
|
||||
for datum in data:
|
||||
o1 = substitutes.ecrecover_substitute(*datum)
|
||||
o2 = s.profile(t.k0, c, 0, funid=0, abi=datum)
|
||||
#assert o1["gas"] == o2["gas"], (o1, o2, datum)
|
||||
assert o1["output"] == o2["output"], (o1, o2, datum)
|
45
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/eth15/channel.se
generated
vendored
Normal file
45
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/eth15/channel.se
generated
vendored
Normal file
@ -0,0 +1,45 @@
|
||||
if msg.data[0] == 0:
|
||||
new_id = contract.storage[-1]
|
||||
# store [from, to, value, maxvalue, timeout] in contract storage
|
||||
contract.storage[new_id] = msg.sender
|
||||
contract.storage[new_id + 1] = msg.data[1]
|
||||
contract.storage[new_id + 2] = 0
|
||||
contract.storage[new_id + 3] = msg.value
|
||||
contract.storage[new_id + 4] = 2^254
|
||||
# increment next id
|
||||
contract.storage[-1] = new_id + 10
|
||||
# return id of this channel
|
||||
return(new_id)
|
||||
|
||||
# Increase payment on channel: [1, id, value, v, r, s]
|
||||
elif msg.data[0] == 1:
|
||||
# Ecrecover native extension; will be a different address in testnet and live
|
||||
ecrecover = 0x46a8d0b21b1336d83b06829f568d7450df36883f
|
||||
# Message data parameters
|
||||
id = msg.data[1] % 2^160
|
||||
value = msg.data[2]
|
||||
# Determine sender from signature
|
||||
h = sha3([id, value], 2)
|
||||
sender = call(ecrecover, [h, msg.data[3], msg.data[4], msg.data[5]], 4)
|
||||
# Check sender matches and new value is greater than old
|
||||
if sender == contract.storage[id]:
|
||||
if value > contract.storage[id + 2] and value <= contract.storage[id + 3]:
|
||||
# Update channel, increasing value and setting timeout
|
||||
contract.storage[id + 2] = value
|
||||
contract.storage[id + 4] = block.number + 1000
|
||||
|
||||
# Cash out channel: [2, id]
|
||||
elif msg.data[0] == 2:
|
||||
id = msg.data[1] % 2^160
|
||||
# Check if timeout has run out
|
||||
if block.number >= contract.storage[id + 3]:
|
||||
# Send funds
|
||||
send(contract.storage[id + 1], contract.storage[id + 2])
|
||||
# Send refund
|
||||
send(contract.storage[id], contract.storage[id + 3] - contract.storage[id + 2])
|
||||
# Clear storage
|
||||
contract.storage[id] = 0
|
||||
contract.storage[id + 1] = 0
|
||||
contract.storage[id + 2] = 0
|
||||
contract.storage[id + 3] = 0
|
||||
contract.storage[id + 4] = 0
|
19
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/eth15/map.se
generated
vendored
Normal file
19
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/eth15/map.se
generated
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
# An implementation of a contract for storing a key/value binding
|
||||
init:
|
||||
# Set owner
|
||||
contract.storage[0] = msg.sender
|
||||
code:
|
||||
# Check ownership
|
||||
if msg.sender == contract.storage[0]:
|
||||
# Get: returns (found, val)
|
||||
if msg.data[0] == 0:
|
||||
s = sha3(msg.data[1])
|
||||
return([contract.storage[s], contract.storage[s+1]], 2)
|
||||
# Set: sets map[k] = v
|
||||
elif msg.data[0] == 1:
|
||||
s = sha3(msg.data[1])
|
||||
contract.storage[s] = 1
|
||||
contract.storage[s + 1] = msg.data[2]
|
||||
# Suicide
|
||||
elif msg.data[2] == 1:
|
||||
suicide(0)
|
14
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/eth15/multiforward.se
generated
vendored
Normal file
14
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/eth15/multiforward.se
generated
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
init:
|
||||
contract.storage[0] = msg.sender
|
||||
code:
|
||||
if msg.sender != contract.storage[0]:
|
||||
stop
|
||||
i = 0
|
||||
while i < ~calldatasize():
|
||||
to = ~calldataload(i)
|
||||
value = ~calldataload(i+20) / 256^12
|
||||
datasize = ~calldataload(i+32) / 256^30
|
||||
data = alloc(datasize)
|
||||
~calldatacopy(data, i+34, datasize)
|
||||
~call(tx.gas - 25, to, value, data, datasize, 0, 0)
|
||||
i += 34 + datasize
|
166
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/eth15/shadowchain.se
generated
vendored
Normal file
166
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/eth15/shadowchain.se
generated
vendored
Normal file
@ -0,0 +1,166 @@
|
||||
# Exists in state:
|
||||
# (i) last committed block
|
||||
# (ii) chain of uncommitted blocks (linear only)
|
||||
# (iii) transactions, each tx with an associated block number
|
||||
#
|
||||
# Uncommitted block =
|
||||
# [ numtxs, numkvs, tx1 (N words), tx2 (N words) ..., [k1, v1], [k2, v2], [k3, v3] ... ]
|
||||
#
|
||||
# Block checking process
|
||||
#
|
||||
# Suppose last committed state is m
|
||||
# Last uncommitted state is n
|
||||
# Contested block is b
|
||||
#
|
||||
# 1. Temporarily apply all state transitions from
|
||||
# m to b
|
||||
# 2. Run code, get list of changes
|
||||
# 3. Check is list of changes matches deltas
|
||||
# * if yes, do nothing
|
||||
# * if no, set last uncommitted state to pre-b
|
||||
#
|
||||
# Storage variables:
|
||||
#
|
||||
# Last committed block: 0
|
||||
# Last uncommitted block: 1
|
||||
# Contract holding code: 2
|
||||
# Uncommitted map: 3
|
||||
# Transaction length (parameter): 4
|
||||
# Block b: 2^160 + b * 2^40:
|
||||
# + 1: submission blknum
|
||||
# + 2: submitter
|
||||
# + 3: data in uncommitted block format above
|
||||
# Last committed storage:
|
||||
# sha3(k): index k
|
||||
|
||||
# Initialize: [0, c, txlength], set address of the code-holding contract and the transaction
|
||||
# length
|
||||
if not contract.storage[2]:
|
||||
contract.storage[2] = msg.data[1]
|
||||
contract.storage[4] = msg.data[2]
|
||||
stop
|
||||
|
||||
# Sequentially commit all uncommitted blocks that are more than 1000 mainchain-blocks old
|
||||
last_committed_block = contract.storage[0]
|
||||
last_uncommitted_block = contract.storage[1]
|
||||
lcb_storage_index = 2^160 + last_committed_block * 2^40
|
||||
while contract.storage[lcb_storage_index + 1] < block.number - 1000 and last_committed_block < last_uncommitted_block:
|
||||
kvpairs = contract.storage[lcb_storage_index]
|
||||
i = 0
|
||||
while i < kvpairs:
|
||||
k = contract.storage[lcb_storage_index + 3 + i * 2]
|
||||
v = contract.storage[lcb_storage_index + 4 + i * 2]
|
||||
contract.storage[sha3(k)] = v
|
||||
i += 1
|
||||
last_committed_block += 1
|
||||
lcb_storage_index += 2^40
|
||||
contract.storage[0] = last_committed_block
|
||||
|
||||
|
||||
# Propose block: [ 0, block number, data in block format above ... ]
|
||||
if msg.data[0] == 0:
|
||||
blknumber = msg.data[1]
|
||||
# Block number must be correct
|
||||
if blknumber != contract.storage[1]:
|
||||
stop
|
||||
# Deposit requirement
|
||||
if msg.value < 10^19:
|
||||
stop
|
||||
# Store the proposal in storage as
|
||||
# [ 0, main-chain block number, sender, block data...]
|
||||
start_index = 2^160 + blknumber * 2^40
|
||||
numkvs = (msg.datasize - 2) / 2
|
||||
contract.storage[start_index + 1] = block.number
|
||||
1ontract.storage[start_index + 2] = msg.sender
|
||||
i = 0
|
||||
while i < msg.datasize - 2:
|
||||
contract.storage[start_index + 3 + i] = msg.data[2 + i]
|
||||
i += 1
|
||||
contract.storage[1] = blknumber + 1
|
||||
|
||||
# Challenge block: [ 1, b ]
|
||||
elif msg.data[0] == 1:
|
||||
blknumber = msg.data[1]
|
||||
txwidth = contract.storage[4]
|
||||
last_uncommitted_block = contract.storage[1]
|
||||
last_committed_block = contract.storage[0]
|
||||
# Cannot challenge nonexistent or committed blocks
|
||||
if blknumber <= last_uncommitted_block or blknumber > last_committed_block:
|
||||
stop
|
||||
# Create a contract to serve as a map that maintains keys and values
|
||||
# temporarily
|
||||
tempstore = create('map.se')
|
||||
contract.storage[3] = tempstore
|
||||
# Unquestioningly apply the state transitions from the last committed block
|
||||
# up to b
|
||||
b = last_committed_block
|
||||
cur_storage_index = 2^160 + last_committed_block * 2^40
|
||||
while b < blknumber:
|
||||
numtxs = contract.storage[cur_storage_index + 3]
|
||||
numkvs = contract.storage[cur_storage_index + 4]
|
||||
kv0index = cur_storage_index + 5 + numtxs * txwidth
|
||||
i = 0
|
||||
while i < numkvs:
|
||||
k = contract.storage[kv0index + i * 2]
|
||||
v = contract.storage[kx0index + i * 2 + 1]
|
||||
call(tempstore, [1, k, v], 3)
|
||||
i += 1
|
||||
b += 1
|
||||
cur_storage_index += 2^40
|
||||
# Run the actual code, and see what state transitions it outputs
|
||||
# The way that the code is expected to work is to:
|
||||
#
|
||||
# (1) take as input the list of transactions (the contract should
|
||||
# use msg.datasize to determine how many txs there are, and it should
|
||||
# be aware of the value of txwidth)
|
||||
# (2) call this contract with [2, k] to read current state data
|
||||
# (3) call this contract with [3, k, v] to write current state data
|
||||
# (4) return as output a list of all state transitions that it made
|
||||
# in the form [kvcount, k1, v1, k2, v2 ... ]
|
||||
#
|
||||
# The reason for separating (2) from (3) is that sometimes the state
|
||||
# transition may end up changing a given key many times, and we don't
|
||||
# need to inefficiently store that in storage
|
||||
numkvs = contract.storage[cur_storage_index + 3]
|
||||
numtxs = contract.storage[cur_storage_index + 4]
|
||||
# Populate input array
|
||||
inpwidth = numtxs * txwidth
|
||||
inp = array(inpwidth)
|
||||
i = 0
|
||||
while i < inpwidth:
|
||||
inp[i] = contract.storage[cur_storage_index + 5 + i]
|
||||
i += 1
|
||||
out = call(contract.storage[2], inp, inpwidth, numkvs * 2 + 1)
|
||||
# Check that the number of state transitions is the same
|
||||
if out[0] != kvcount:
|
||||
send(msg.sender, 10^19)
|
||||
contract.storage[0] = last_committed_block
|
||||
stop
|
||||
kv0index = cur_storage_index + 5 + numtxs * txwidth
|
||||
i = 0
|
||||
while i < kvcount:
|
||||
# Check that each individual state transition matches
|
||||
k = contract.storage[kv0index + i * 2 + 1]
|
||||
v = contract.storage[kv0index + i * 2 + 2]
|
||||
if k != out[i * 2 + 1] or v != out[i * 2 + 2]:
|
||||
send(msg.sender, 10^19)
|
||||
contract.storage[0] = last_committed_block
|
||||
stop
|
||||
i += 1
|
||||
# Suicide tempstore
|
||||
call(tempstore, 2)
|
||||
|
||||
|
||||
# Read data [2, k]
|
||||
elif msg.data[0] == 2:
|
||||
tempstore = contract.storage[3]
|
||||
o = call(tempstore, [0, msg.data[1]], 2, 2)
|
||||
if o[0]:
|
||||
return(o[1])
|
||||
else:
|
||||
return contract.storage[sha3(msg.data[1])]
|
||||
|
||||
# Write data [3, k, v]
|
||||
elif msg.data[0] == 3:
|
||||
tempstore = contract.storage[3]
|
||||
call(tempstore, [1, msg.data[1], msg.data[2]], 3, 2)
|
31
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/fixedpoint.se
generated
vendored
Normal file
31
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/fixedpoint.se
generated
vendored
Normal file
@ -0,0 +1,31 @@
|
||||
type f: [a, b, c, d, e]
|
||||
|
||||
macro f($a) + f($b):
|
||||
f(add($a, $b))
|
||||
|
||||
macro f($a) - f($b):
|
||||
f(sub($a, $b))
|
||||
|
||||
macro f($a) * f($b):
|
||||
f(mul($a, $b) / 10000)
|
||||
|
||||
macro f($a) / f($b):
|
||||
f(sdiv($a * 10000, $b))
|
||||
|
||||
macro f($a) % f($b):
|
||||
f(smod($a, $b))
|
||||
|
||||
macro f($v) = f($w):
|
||||
$v = $w
|
||||
|
||||
macro unfify(f($a)):
|
||||
$a / 10000
|
||||
|
||||
macro fify($a):
|
||||
f($a * 10000)
|
||||
|
||||
a = fify(5)
|
||||
b = fify(2)
|
||||
c = a / b
|
||||
e = c + (a / b)
|
||||
return(unfify(e))
|
116
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/long_integer_macros.se
generated
vendored
Normal file
116
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/long_integer_macros.se
generated
vendored
Normal file
@ -0,0 +1,116 @@
|
||||
macro smin($a, $b):
|
||||
with $1 = $a:
|
||||
with $2 = $b:
|
||||
if(slt($1, $2), $1, $2)
|
||||
|
||||
macro smax($a, $b):
|
||||
with $1 = $a:
|
||||
with $2 = $b:
|
||||
if(slt($1, $2), $2, $1)
|
||||
|
||||
def omul(x, y):
|
||||
o = expose(mklong(x) * mklong(y))
|
||||
return(slice(o, 1), o[0]+1)
|
||||
|
||||
def oadd(x, y):
|
||||
o = expose(mklong(x) + mklong(y))
|
||||
return(slice(o, 1), o[0]+1)
|
||||
|
||||
def osub(x, y):
|
||||
o = expose(mklong(x) - mklong(y))
|
||||
return(slice(o, 1), o[0]+1)
|
||||
|
||||
def odiv(x, y):
|
||||
o = expose(mklong(x) / mklong(y))
|
||||
return(slice(o, 1), o[0]+1)
|
||||
|
||||
def comb(a:a, b:a, sign):
|
||||
sz = smax(a[0], b[0])
|
||||
msz = smin(a[0], b[0])
|
||||
c = array(sz + 2)
|
||||
c[0] = sz
|
||||
i = 0
|
||||
carry = 0
|
||||
while i < msz:
|
||||
m = a[i + 1] + sign * b[i + 1] + carry
|
||||
c[i + 1] = mod(m + 2^127, 2^128) - 2^127
|
||||
carry = (div(m + 2^127, 2^128) + 2^127) % 2^128 - 2^127
|
||||
i += 1
|
||||
u = if(a[0] > msz, a, b)
|
||||
s = if(a[0] > msz, 1, sign)
|
||||
while i < sz:
|
||||
m = s * u[i + 1] + carry
|
||||
c[i + 1] = mod(m + 2^127, 2^128) - 2^127
|
||||
carry = (div(m + 2^127, 2^128) + 2^127) % 2^128 - 2^127
|
||||
i += 1
|
||||
if carry:
|
||||
c[0] += 1
|
||||
c[sz + 1] = carry
|
||||
return(c, c[0]+1)
|
||||
|
||||
def mul(a:a, b:a):
|
||||
c = array(a[0] + b[0] + 2)
|
||||
c[0] = a[0] + b[0]
|
||||
i = 0
|
||||
while i < a[0]:
|
||||
j = 0
|
||||
carry = 0
|
||||
while j < b[0]:
|
||||
m = c[i + j + 1] + a[i + 1] * b[j + 1] + carry
|
||||
c[i + j + 1] = mod(m + 2^127, 2^128) - 2^127
|
||||
carry = (div(m + 2^127, 2^128) + 2^127) % 2^128 - 2^127
|
||||
j += 1
|
||||
if carry:
|
||||
c[0] = a[0] + b[0] + 1
|
||||
c[i + j + 1] += carry
|
||||
i += 1
|
||||
return(c, c[0]+1)
|
||||
|
||||
macro long($a) + long($b):
|
||||
long(self.comb($a:$a[0]+1, $b:$b[0]+1, 1, outsz=$a[0]+$b[0]+2))
|
||||
|
||||
macro long($a) - long($b):
|
||||
long(self.comb($a:$a[0]+1, $b:$b[0]+1, -1, outsz=$a[0]+$b[0]+2))
|
||||
|
||||
macro long($a) * long($b):
|
||||
long(self.mul($a:$a[0]+1, $b:$b[0]+1, outsz=$a[0]+$b[0]+2))
|
||||
|
||||
macro long($a) / long($b):
|
||||
long(self.div($a:$a[0]+1, $b:$b[0]+1, outsz=$a[0]+$b[0]+2))
|
||||
|
||||
macro mulexpand(long($a), $k, $m):
|
||||
long:
|
||||
with $c = array($a[0]+k+2):
|
||||
$c[0] = $a[0]+$k
|
||||
with i = 0:
|
||||
while i < $a[0]:
|
||||
v = $a[i+1] * $m + $c[i+$k+1]
|
||||
$c[i+$k+1] = mod(v + 2^127, 2^128) - 2^127
|
||||
$c[i+$k+2] = div(v + 2^127, 2^128)
|
||||
i += 1
|
||||
$c
|
||||
|
||||
def div(a:a, b:a):
|
||||
asz = a[0]
|
||||
bsz = b[0]
|
||||
while b[bsz] == 0 and bsz > 0:
|
||||
bsz -= 1
|
||||
c = array(asz+2)
|
||||
c[0] = asz+1
|
||||
while 1:
|
||||
while a[asz] == 0 and asz > 0:
|
||||
asz -= 1
|
||||
if asz < bsz:
|
||||
return(c, c[0]+1)
|
||||
sub = expose(mulexpand(long(b), asz - bsz, a[asz] / b[bsz]))
|
||||
c[asz - bsz+1] = a[asz] / b[bsz]
|
||||
a = expose(long(a) - long(sub))
|
||||
a[asz-1] += 2^128 * a[asz]
|
||||
a[asz] = 0
|
||||
|
||||
macro mklong($i):
|
||||
long([2, mod($i + 2^127, 2^128) - 2^127, div($i + 2^127, 2^128)])
|
||||
|
||||
macro expose(long($i)):
|
||||
$i
|
||||
|
2
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/mul2.se
generated
vendored
Normal file
2
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/mul2.se
generated
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
def double(v):
|
||||
return(v*2)
|
187
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/mutuala.se
generated
vendored
Normal file
187
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/mutuala.se
generated
vendored
Normal file
@ -0,0 +1,187 @@
|
||||
# mutuala - subcurrency
|
||||
|
||||
# We want to issue a currency that reduces in value as you store it through negative interest.
|
||||
# That negative interest would be stored in a commons account. It's like the p2p version of a
|
||||
# capital tax
|
||||
|
||||
# the same things goes for transactions - you pay as you use the currency. However, the more
|
||||
# you pay, the more you get to say about what the tax is used for
|
||||
|
||||
# each participant can propose a recipient for a payout to be made out of the commons account,
|
||||
# others can vote on it by awarding it tax_credits.
|
||||
|
||||
# TODO should proposal have expiration timestamp?, after which the tax_credits are refunded
|
||||
# TODO multiple proposals can take more credits that available in the Commons, how to handle this
|
||||
# TODO how to handle lost accounts, after which no longer possible to get 2/3 majority
|
||||
|
||||
shared:
|
||||
COMMONS = 42
|
||||
ADMIN = 666
|
||||
CAPITAL_TAX_PER_DAY = 7305 # 5% per year
|
||||
PAYMENT_TAX = 20 # 5%
|
||||
|
||||
ACCOUNT_LIST_OFFSET = 2^160
|
||||
ACCOUNT_MAP_OFFSET = 2^161
|
||||
PROPOSAL_LIST_OFFSET = 2^162
|
||||
PROPOSAL_MAP_OFFSET = 2^163
|
||||
|
||||
init:
|
||||
contract.storage[ADMIN] = msg.sender
|
||||
contract.storage[ACCOUNT_LIST_OFFSET - 1] = 1
|
||||
contract.storage[ACCOUNT_LIST_OFFSET] = msg.sender
|
||||
contract.storage[ACCOUNT_MAP_OFFSET + msg.sender] = 10^12
|
||||
contract.storage[ACCOUNT_MAP_OFFSET + msg.sender + 1] = block.timestamp
|
||||
|
||||
# contract.storage[COMMONS] = balance commons
|
||||
|
||||
# contract.storage[ACCOUNT_LIST_OFFSET - 1] = number of accounts
|
||||
# contract.storage[ACCOUNT_LIST_OFFSET + n] = account n
|
||||
|
||||
# contract.storage[PROPOSAL_LIST_OFFSET - 1] contains the number of proposals
|
||||
# contract.storage[PROPOSAL_LIST_OFFSET + n] = proposal n
|
||||
|
||||
# per account:
|
||||
# contract.storage[ACCOUNT_MAP_OFFSET + account] = balance
|
||||
# contract.storage[ACCOUNT_MAP_OFFSET + account+1] = timestamp_last_transaction
|
||||
# contract.storage[ACCOUNT_MAP_OFFSET + account+2] = tax_credits
|
||||
|
||||
# per proposal:
|
||||
# contract.storage[PROPOSAL_MAP_OFFSET + proposal_id] = recipient
|
||||
# contract.storage[PROPOSAL_MAP_OFFSET + proposal_id+1] = amount
|
||||
# contract.storage[PROPOSAL_MAP_OFFSET + proposal_id+2] = total vote credits
|
||||
|
||||
code:
|
||||
if msg.data[0] == "suicide" and msg.sender == contract.storage[ADMIN]:
|
||||
suicide(msg.sender)
|
||||
|
||||
elif msg.data[0] == "balance":
|
||||
addr = msg.data[1]
|
||||
return(contract.storage[ACCOUNT_MAP_OFFSET + addr])
|
||||
|
||||
elif msg.data[0] == "pay":
|
||||
from = msg.sender
|
||||
fromvalue = contract.storage[ACCOUNT_MAP_OFFSET + from]
|
||||
to = msg.data[1]
|
||||
if to == 0 or to >= 2^160:
|
||||
return([0, "invalid address"], 2)
|
||||
value = msg.data[2]
|
||||
tax = value / PAYMENT_TAX
|
||||
|
||||
if fromvalue >= value + tax:
|
||||
contract.storage[ACCOUNT_MAP_OFFSET + from] = fromvalue - (value + tax)
|
||||
contract.storage[ACCOUNT_MAP_OFFSET + to] += value
|
||||
# tax
|
||||
contract.storage[COMMONS] += tax
|
||||
contract.storage[ACCOUNT_MAP_OFFSET + from + 2] += tax
|
||||
|
||||
# check timestamp field to see if target account exists
|
||||
if contract.storage[ACCOUNT_MAP_OFFSET + to + 1] == 0:
|
||||
# register new account
|
||||
nr_accounts = contract.storage[ACCOUNT_LIST_OFFSET - 1]
|
||||
contract.storage[ACCOUNT_LIST_OFFSET + nr_accounts] = to
|
||||
contract.storage[ACCOUNT_LIST_OFFSET - 1] += 1
|
||||
contract.storage[ACCOUNT_MAP_OFFSET + to + 1] = block.timestamp
|
||||
|
||||
return(1)
|
||||
else:
|
||||
return([0, "insufficient balance"], 2)
|
||||
|
||||
elif msg.data[0] == "hash":
|
||||
proposal_id = sha3(msg.data[1])
|
||||
return(proposal_id)
|
||||
|
||||
elif msg.data[0] == "propose":
|
||||
from = msg.sender
|
||||
# check if sender has an account and has tax credits
|
||||
if contract.storage[ACCOUNT_MAP_OFFSET + from + 2] == 0:
|
||||
return([0, "sender has no tax credits"], 2)
|
||||
|
||||
proposal_id = sha3(msg.data[1])
|
||||
# check if proposal doesn't already exist
|
||||
if contract.storage[PROPOSAL_MAP_OFFSET + proposal_id]:
|
||||
return([0, "proposal already exists"])
|
||||
|
||||
to = msg.data[2]
|
||||
# check if recipient is a valid address and has an account (with timestamp)
|
||||
if to == 0 or to >= 2^160:
|
||||
return([0, "invalid address"], 2)
|
||||
if contract.storage[ACCOUNT_MAP_OFFSET + to + 1] == 0:
|
||||
return([0, "invalid to account"], 2)
|
||||
|
||||
value = msg.data[3]
|
||||
# check if there is enough money in the commons account
|
||||
if value > contract.storage[COMMONS]:
|
||||
return([0, "not enough credits in commons"], 2)
|
||||
|
||||
# record proposal in list
|
||||
nr_proposals = contract.storage[PROPOSAL_LIST_OFFSET - 1]
|
||||
contract.storage[PROPOSAL_LIST_OFFSET + nr_proposals] = proposal_id
|
||||
contract.storage[PROPOSAL_LIST_OFFSET - 1] += 1
|
||||
|
||||
# record proposal in map
|
||||
contract.storage[PROPOSAL_MAP_OFFSET + proposal_id] = to
|
||||
contract.storage[PROPOSAL_MAP_OFFSET + proposal_id + 1] = value
|
||||
|
||||
return(proposal_id)
|
||||
|
||||
elif msg.data[0] == "vote":
|
||||
from = msg.sender
|
||||
proposal_id = sha3(msg.data[1])
|
||||
value = msg.data[2]
|
||||
# check if sender has an account and has tax credits
|
||||
if value < contract.storage[ACCOUNT_MAP_OFFSET + from + 2]:
|
||||
return([0, "sender doesn't have enough tax credits"], 2)
|
||||
|
||||
# check if proposal exist
|
||||
if contract.storage[PROPOSAL_MAP_OFFSET + proposal_id] == 0:
|
||||
return([0, "proposal doesn't exist"], 2)
|
||||
|
||||
# increase votes
|
||||
contract.storage[PROPOSAL_MAP_OFFSET + proposal_id + 2] += value
|
||||
# withdraw tax credits
|
||||
contract.storage[ACCOUNT_MAP_OFFSET + from + 2] -= value
|
||||
|
||||
# did we reach 2/3 threshold?
|
||||
if contract.storage[PROPOSAL_MAP_OFFSET + proposal_id + 2] >= contract.storage[COMMONS] * 2 / 3:
|
||||
# got majority
|
||||
to = contract.storage[PROPOSAL_MAP_OFFSET + proposal_id]
|
||||
amount = contract.storage[PROPOSAL_MAP_OFFSET + proposal_id + 1]
|
||||
|
||||
# adjust balances
|
||||
contract.storage[ACCOUNT_MAP_OFFSET + to] += amount
|
||||
contract.storage[COMMONS] -= amount
|
||||
|
||||
# reset proposal
|
||||
contract.storage[PROPOSAL_MAP_OFFSET + proposal_id] = 0
|
||||
contract.storage[PROPOSAL_MAP_OFFSET + proposal_id + 1] = 0
|
||||
contract.storage[PROPOSAL_MAP_OFFSET + proposal_id + 2] = 0
|
||||
return(1)
|
||||
|
||||
return(proposal_id)
|
||||
|
||||
elif msg.data[0] == "tick":
|
||||
nr_accounts = contract.storage[ACCOUNT_LIST_OFFSET - 1]
|
||||
account_idx = 0
|
||||
tax_paid = 0
|
||||
# process all accounts and see if they have to pay their daily capital tax
|
||||
while account_idx < nr_accounts:
|
||||
cur_account = contract.storage[ACCOUNT_LIST_OFFSET + account_idx]
|
||||
last_timestamp = contract.storage[ACCOUNT_MAP_OFFSET + cur_account + 1]
|
||||
time_diff = block.timestamp - last_timestamp
|
||||
if time_diff >= 86400:
|
||||
tax_days = time_diff / 86400
|
||||
balance = contract.storage[ACCOUNT_MAP_OFFSET + cur_account]
|
||||
tax = tax_days * (balance / CAPITAL_TAX_PER_DAY)
|
||||
if tax > 0:
|
||||
# charge capital tax, but give tax credits in return
|
||||
contract.storage[ACCOUNT_MAP_OFFSET + cur_account] -= tax
|
||||
contract.storage[ACCOUNT_MAP_OFFSET + cur_account + 1] += tax_days * 86400
|
||||
contract.storage[ACCOUNT_MAP_OFFSET + cur_account + 2] += tax
|
||||
|
||||
contract.storage[COMMONS] += tax
|
||||
tax_paid += 1
|
||||
account_idx += 1
|
||||
return(tax_paid) # how many accounts did we charge tax on
|
||||
|
||||
else:
|
||||
return([0, "unknown command"], 2)
|
7
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/namecoin.se
generated
vendored
Normal file
7
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/namecoin.se
generated
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
def register(k, v):
|
||||
if !self.storage[k]: # Is the key not yet taken?
|
||||
# Then take it!
|
||||
self.storage[k] = v
|
||||
return(1)
|
||||
else:
|
||||
return(0) // Otherwise do nothing
|
43
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/peano.se
generated
vendored
Normal file
43
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/peano.se
generated
vendored
Normal file
@ -0,0 +1,43 @@
|
||||
macro padd($x, psuc($y)):
|
||||
psuc(padd($x, $y))
|
||||
|
||||
macro padd($x, z()):
|
||||
$x
|
||||
|
||||
macro dec(psuc($x)):
|
||||
dec($x) + 1
|
||||
|
||||
macro dec(z()):
|
||||
0
|
||||
|
||||
macro pmul($x, z()):
|
||||
z()
|
||||
|
||||
macro pmul($x, psuc($y)):
|
||||
padd(pmul($x, $y), $x)
|
||||
|
||||
macro pexp($x, z()):
|
||||
one()
|
||||
|
||||
macro pexp($x, psuc($y)):
|
||||
pmul($x, pexp($x, $y))
|
||||
|
||||
macro fac(z()):
|
||||
one()
|
||||
|
||||
macro fac(psuc($x)):
|
||||
pmul(psuc($x), fac($x))
|
||||
|
||||
macro one():
|
||||
psuc(z())
|
||||
|
||||
macro two():
|
||||
psuc(psuc(z()))
|
||||
|
||||
macro three():
|
||||
psuc(psuc(psuc(z())))
|
||||
|
||||
macro five():
|
||||
padd(three(), two())
|
||||
|
||||
return([dec(pmul(three(), pmul(three(), three()))), dec(fac(five()))], 2)
|
4
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/returnten.se
generated
vendored
Normal file
4
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/returnten.se
generated
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
extern mul2: [double]
|
||||
|
||||
x = create("mul2.se")
|
||||
return(x.double(5))
|
33
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/schellingcoin/quicksort.se
generated
vendored
Normal file
33
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/schellingcoin/quicksort.se
generated
vendored
Normal file
@ -0,0 +1,33 @@
|
||||
def kall():
|
||||
argcount = ~calldatasize() / 32
|
||||
if argcount == 1:
|
||||
return(~calldataload(1))
|
||||
|
||||
args = array(argcount)
|
||||
~calldatacopy(args, 1, argcount * 32)
|
||||
low = array(argcount)
|
||||
lsz = 0
|
||||
high = array(argcount)
|
||||
hsz = 0
|
||||
i = 1
|
||||
while i < argcount:
|
||||
if args[i] < args[0]:
|
||||
low[lsz] = args[i]
|
||||
lsz += 1
|
||||
else:
|
||||
high[hsz] = args[i]
|
||||
hsz += 1
|
||||
i += 1
|
||||
low = self.kall(data=low, datasz=lsz, outsz=lsz)
|
||||
high = self.kall(data=high, datasz=hsz, outsz=hsz)
|
||||
o = array(argcount)
|
||||
i = 0
|
||||
while i < lsz:
|
||||
o[i] = low[i]
|
||||
i += 1
|
||||
o[lsz] = args[0]
|
||||
j = 0
|
||||
while j < hsz:
|
||||
o[lsz + 1 + j] = high[j]
|
||||
j += 1
|
||||
return(o, argcount)
|
46
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/schellingcoin/quicksort_pairs.se
generated
vendored
Normal file
46
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/schellingcoin/quicksort_pairs.se
generated
vendored
Normal file
@ -0,0 +1,46 @@
|
||||
# Quicksort pairs
|
||||
# eg. input of the form [ 30, 1, 90, 2, 70, 3, 50, 4]
|
||||
# outputs [ 30, 1, 50, 4, 70, 3, 90, 2 ]
|
||||
#
|
||||
# Note: this can be used as a generalized sorting algorithm:
|
||||
# map every object to [ key, ref ] where `ref` is the index
|
||||
# in memory to all of the properties and `key` is the key to
|
||||
# sort by
|
||||
|
||||
|
||||
def kall():
|
||||
argcount = ~calldatasize() / 64
|
||||
if argcount == 1:
|
||||
return([~calldataload(1), ~calldataload(33)], 2)
|
||||
|
||||
args = array(argcount * 2)
|
||||
~calldatacopy(args, 1, argcount * 64)
|
||||
low = array(argcount * 2)
|
||||
lsz = 0
|
||||
high = array(argcount * 2)
|
||||
hsz = 0
|
||||
i = 2
|
||||
while i < argcount * 2:
|
||||
if args[i] < args[0]:
|
||||
low[lsz] = args[i]
|
||||
low[lsz + 1] = args[i + 1]
|
||||
lsz += 2
|
||||
else:
|
||||
high[hsz] = args[i]
|
||||
high[hsz + 1] = args[i + 1]
|
||||
hsz += 2
|
||||
i = i + 2
|
||||
low = self.kall(data=low, datasz=lsz, outsz=lsz)
|
||||
high = self.kall(data=high, datasz=hsz, outsz=hsz)
|
||||
o = array(argcount * 2)
|
||||
i = 0
|
||||
while i < lsz:
|
||||
o[i] = low[i]
|
||||
i += 1
|
||||
o[lsz] = args[0]
|
||||
o[lsz + 1] = args[1]
|
||||
j = 0
|
||||
while j < hsz:
|
||||
o[lsz + 2 + j] = high[j]
|
||||
j += 1
|
||||
return(o, argcount * 2)
|
94
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/schellingcoin/schellingcoin.se
generated
vendored
Normal file
94
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/schellingcoin/schellingcoin.se
generated
vendored
Normal file
@ -0,0 +1,94 @@
|
||||
# SchellingCoin implementation
|
||||
#
|
||||
# Epoch length: 100 blocks
|
||||
# Target savings depletion rate: 0.1% per epoch
|
||||
|
||||
data epoch
|
||||
data hashes_submitted
|
||||
data output
|
||||
data quicksort_pairs
|
||||
data accounts[2^160]
|
||||
data submissions[2^80](hash, deposit, address, value)
|
||||
extern any: [call]
|
||||
|
||||
|
||||
def init():
|
||||
self.epoch = block.number / 100
|
||||
self.quicksort_pairs = create('quicksort_pairs.se')
|
||||
|
||||
def any():
|
||||
if block.number / 100 > epoch:
|
||||
# Sort all values submitted
|
||||
N = self.hashes_submitted
|
||||
o = array(N * 2)
|
||||
i = 0
|
||||
j = 0
|
||||
while i < N:
|
||||
v = self.submissions[i].value
|
||||
if v:
|
||||
o[j] = v
|
||||
o[j + 1] = i
|
||||
j += 2
|
||||
i += 1
|
||||
values = self.quicksort_pairs.call(data=o, datasz=j, outsz=j)
|
||||
|
||||
# Calculate total deposit, refund non-submitters and
|
||||
# cleanup
|
||||
|
||||
deposits = array(j / 2)
|
||||
addresses = array(j / 2)
|
||||
|
||||
i = 0
|
||||
total_deposit = 0
|
||||
while i < j / 2:
|
||||
base_index = HASHES + values[i * 2 + 1] * 3
|
||||
deposits[i] = self.submissions[i].deposit
|
||||
addresses[i] = self.submissions[i].address
|
||||
if self.submissions[values[i * 2 + 1]].value:
|
||||
total_deposit += deposits[i]
|
||||
else:
|
||||
send(addresses[i], deposits[i] * 999 / 1000)
|
||||
i += 1
|
||||
|
||||
inverse_profit_ratio = total_deposit / (contract.balance / 1000) + 1
|
||||
|
||||
# Reward everyone
|
||||
i = 0
|
||||
running_deposit_sum = 0
|
||||
halfway_passed = 0
|
||||
while i < j / 2:
|
||||
new_deposit_sum = running_deposit_sum + deposits[i]
|
||||
if new_deposit_sum > total_deposit / 4 and running_deposit_sum < total_deposit * 3 / 4:
|
||||
send(addresses[i], deposits[i] + deposits[i] / inverse_profit_ratio * 2)
|
||||
else:
|
||||
send(addresses[i], deposits[i] - deposits[i] / inverse_profit_ratio)
|
||||
|
||||
if not halfway_passed and new_deposit_sum > total_deposit / 2:
|
||||
self.output = self.submissions[i].value
|
||||
halfway_passed = 1
|
||||
self.submissions[i].value = 0
|
||||
running_deposit_sum = new_deposit_sum
|
||||
i += 1
|
||||
self.epoch = block.number / 100
|
||||
self.hashes_submitted = 0
|
||||
|
||||
def submit_hash(h):
|
||||
if block.number % 100 < 50:
|
||||
cur = self.hashes_submitted
|
||||
pos = HASHES + cur * 3
|
||||
self.submissions[cur].hash = h
|
||||
self.submissions[cur].deposit = msg.value
|
||||
self.submissions[cur].address = msg.sender
|
||||
self.hashes_submitted = cur + 1
|
||||
return(cur)
|
||||
|
||||
def submit_value(index, v):
|
||||
if sha3([msg.sender, v], 2) == self.submissions[index].hash:
|
||||
self.submissions[index].value = v
|
||||
return(1)
|
||||
|
||||
def request_balance():
|
||||
return(contract.balance)
|
||||
|
||||
def request_output():
|
||||
return(self.output)
|
171
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/schellingcoin/schellingdollar.se
generated
vendored
Normal file
171
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/schellingcoin/schellingdollar.se
generated
vendored
Normal file
@ -0,0 +1,171 @@
|
||||
# Hedged zero-supply dollar implementation
|
||||
# Uses SchellingCoin as price-determining backend
|
||||
#
|
||||
# Stored variables:
|
||||
#
|
||||
# 0: Schelling coin contract
|
||||
# 1: Last epoch
|
||||
# 2: Genesis block of contract
|
||||
# 3: USD exposure
|
||||
# 4: ETH exposure
|
||||
# 5: Cached price
|
||||
# 6: Last interest rate
|
||||
# 2^160 + k: interest rate accumulator at k epochs
|
||||
# 2^161 + ADDR * 3: eth-balance of a particular address
|
||||
# 2^161 + ADDR * 3 + 1: usd-balance of a particular address
|
||||
# 2^161 + ADDR * 3 + 1: last accessed epoch of a particular address
|
||||
#
|
||||
# Transaction types:
|
||||
#
|
||||
# [1, to, val]: send ETH
|
||||
# [2, to, val]: send USD
|
||||
# [3, wei_amount]: convert ETH to USD
|
||||
# [4, usd_amount]: converts USD to ETH
|
||||
# [5]: deposit
|
||||
# [6, amount]: withdraw
|
||||
# [7]: my balance query
|
||||
# [7, acct]: balance query for any acct
|
||||
# [8]: global state query
|
||||
# [9]: liquidation test any account
|
||||
#
|
||||
# The purpose of the contract is to serve as a sort of cryptographic
|
||||
# bank account where users can store both ETH and USD. ETH must be
|
||||
# stored in zero or positive quantities, but USD balances can be
|
||||
# positive or negative. If the USD balance is negative, the invariant
|
||||
# usdbal * 10 >= ethbal * 9 must be satisfied; if any account falls
|
||||
# below this value, then that account's balances are zeroed. Note
|
||||
# that there is a 2% bounty to ping the app if an account does go
|
||||
# below zero; one weakness is that if no one does ping then it is
|
||||
# quite possible for accounts to go negative-net-worth, then zero
|
||||
# themselves out, draining the reserves of the "bank" and potentially
|
||||
# bankrupting it. A 0.1% fee on ETH <-> USD trade is charged to
|
||||
# minimize this risk. Additionally, the bank itself will inevitably
|
||||
# end up with positive or negative USD exposure; to mitigate this,
|
||||
# it automatically updates interest rates on USD to keep exposure
|
||||
# near zero.
|
||||
|
||||
data schelling_coin
|
||||
data last_epoch
|
||||
data starting_block
|
||||
data usd_exposure
|
||||
data eth_exposure
|
||||
data price
|
||||
data last_interest_rate
|
||||
data interest_rate_accum[2^50]
|
||||
data accounts[2^160](eth, usd, last_epoch)
|
||||
|
||||
extern sc: [submit_hash, submit_value, request_balance, request_output]
|
||||
|
||||
def init():
|
||||
self.schelling_coin = create('schellingcoin.se')
|
||||
self.price = self.schelling_coin.request_output()
|
||||
self.interest_rate_accum[0] = 10^18
|
||||
self.starting_block = block.number
|
||||
|
||||
def any():
|
||||
sender = msg.sender
|
||||
epoch = (block.number - self.starting_block) / 100
|
||||
last_epoch = self.last_epoch
|
||||
usdprice = self.price
|
||||
|
||||
# Update contract epochs
|
||||
if epoch > last_epoch:
|
||||
delta = epoch - last_epoch
|
||||
last_interest_rate = self.last_interest_rate
|
||||
usd_exposure - self.usd_exposure
|
||||
last_accum = self.interest_rate_accum[last_epoch]
|
||||
|
||||
if usd_exposure < 0:
|
||||
self.last_interest_rate = last_interest_rate - 10000 * delta
|
||||
elif usd_exposure > 0:
|
||||
self.last_interest_rate = last_interest_rate + 10000 * delta
|
||||
|
||||
self.interest_rate_accum[epoch] = last_accum + last_accum * last_interest_rate * delta / 10^9
|
||||
|
||||
# Proceeds go to support the SchellingCoin feeding it price data, ultimately providing the depositors
|
||||
# of the SchellingCoin an interest rate
|
||||
bal = max(self.balance - self.eth_exposure, 0) / 10000
|
||||
usdprice = self.schelling_coin.request_output()
|
||||
self.price = usdprice
|
||||
self.last_epoch = epoch
|
||||
|
||||
ethbal = self.accounts[msg.sender].eth
|
||||
usdbal = self.accounts[msg.sender].usd
|
||||
|
||||
# Apply interest rates to sender and liquidation-test self
|
||||
if msg.sender != self:
|
||||
self.ping(self)
|
||||
|
||||
def send_eth(to, value):
|
||||
if value > 0 and value <= ethbal and usdbal * usdprice * 2 + (ethbal - value) >= 0:
|
||||
self.accounts[msg.sender].eth = ethbal - value
|
||||
self.ping(to)
|
||||
self.accounts[to].eth += value
|
||||
return(1)
|
||||
|
||||
def send_usd(to, value):
|
||||
if value > 0 and value <= usdbal and (usdbal - value) * usdprice * 2 + ethbal >= 0:
|
||||
self.accounts[msg.sender].usd = usdbal - value
|
||||
self.ping(to)
|
||||
self.accounts[to].usd += value
|
||||
return(1)
|
||||
|
||||
def convert_to_eth(usdvalue):
|
||||
ethplus = usdvalue * usdprice * 999 / 1000
|
||||
if usdvalue > 0 and (usdbal - usdvalue) * usdprice * 2 + (ethbal + ethplus) >= 0:
|
||||
self.accounts[msg.sender].eth = ethbal + ethplus
|
||||
self.accounts[msg.sender].usd = usdbal - usdvalue
|
||||
self.eth_exposure += ethplus
|
||||
self.usd_exposure -= usdvalue
|
||||
return([ethbal + ethplus, usdbal - usdvalue], 2)
|
||||
|
||||
def convert_to_usd(ethvalue):
|
||||
usdplus = ethvalue / usdprice * 999 / 1000
|
||||
if ethvalue > 0 and (usdbal + usdplus) * usdprice * 2 + (ethbal - ethvalue) >= 0:
|
||||
self.accounts[msg.sender].eth = ethbal - ethvalue
|
||||
self.accounts[msg.sender].usd = usdbal + usdplus
|
||||
self.eth_exposure -= ethvalue
|
||||
self.usd_exposure += usdplus
|
||||
return([ethbal - ethvalue, usdbal + usdplus], 2)
|
||||
|
||||
def deposit():
|
||||
self.accounts[msg.sender].eth = ethbal + msg.value
|
||||
self.eth_exposure += msg.value
|
||||
return(ethbal + msg.value)
|
||||
|
||||
def withdraw(value):
|
||||
if value > 0 and value <= ethbal and usdbal * usdprice * 2 + (ethbal - value) >= 0:
|
||||
self.accounts[msg.sender].eth -= value
|
||||
self.eth_exposure -= value
|
||||
return(ethbal - value)
|
||||
|
||||
def balance(acct):
|
||||
self.ping(acct)
|
||||
return([self.accounts[acct].eth, self.accounts[acct].usd], 2)
|
||||
|
||||
def global_state_query(acct):
|
||||
interest = self.last_interest_rate
|
||||
usd_exposure = self.usd_exposure
|
||||
eth_exposure = self.eth_exposure
|
||||
eth_balance = self.balance
|
||||
return([epoch, usdprice, interest, usd_exposure, eth_exposure, eth_balance], 6)
|
||||
|
||||
def ping(acct):
|
||||
account_last_epoch = self.accounts[acct].last_epoch
|
||||
if account_last_epoch != epoch:
|
||||
cur_usd_balance = self.accounts[acct].usd
|
||||
new_usd_balance = cur_usd_balance * self.interest_rate_accum[epoch] / self.interest_rate_accum[account_last_epoch]
|
||||
self.accounts[acct].usd = new_usd_balance
|
||||
self.accounts[acct].last_epoch = epoch
|
||||
self.usd_exposure += new_usd_balance - cur_usd_balance
|
||||
|
||||
ethbal = self.accounts[acct].eth
|
||||
|
||||
if new_usd_balance * usdval * 10 + ethbal * 9 < 0:
|
||||
self.accounts[acct].eth = 0
|
||||
self.accounts[acct].usd = 0
|
||||
self.accounts[msg.sender].eth += ethbal / 50
|
||||
self.eth_exposure += -ethbal + ethbal / 50
|
||||
self.usd_exposure += new_usd_balance
|
||||
return(1)
|
||||
return(0)
|
1
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/schellinghelper.se
generated
vendored
Normal file
1
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/schellinghelper.se
generated
vendored
Normal file
@ -0,0 +1 @@
|
||||
return(sha3([msg.sender, msg.data[0]], 2))
|
3
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/short_namecoin.se
generated
vendored
Normal file
3
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/short_namecoin.se
generated
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
def register(k, v):
|
||||
if !self.storage[k]:
|
||||
self.storage[k] = v
|
11
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/subcurrency.se
generated
vendored
Normal file
11
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/examples/subcurrency.se
generated
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
def init():
|
||||
self.storage[msg.sender] = 1000000
|
||||
|
||||
def balance_query(k):
|
||||
return(self.storage[addr])
|
||||
|
||||
def send(to, value):
|
||||
fromvalue = self.storage[msg.sender]
|
||||
if fromvalue >= value:
|
||||
self.storage[from] = fromvalue - value
|
||||
self.storage[to] += value
|
35
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/funcs.cpp
generated
vendored
Normal file
35
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/funcs.cpp
generated
vendored
Normal file
@ -0,0 +1,35 @@
|
||||
#include <stdio.h>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include "funcs.h"
|
||||
#include "bignum.h"
|
||||
#include "util.h"
|
||||
#include "parser.h"
|
||||
#include "lllparser.h"
|
||||
#include "compiler.h"
|
||||
#include "rewriter.h"
|
||||
#include "tokenize.h"
|
||||
|
||||
Node compileToLLL(std::string input) {
|
||||
return rewrite(parseSerpent(input));
|
||||
}
|
||||
|
||||
Node compileChunkToLLL(std::string input) {
|
||||
return rewriteChunk(parseSerpent(input));
|
||||
}
|
||||
|
||||
std::string compile(std::string input) {
|
||||
return compileLLL(compileToLLL(input));
|
||||
}
|
||||
|
||||
std::vector<Node> prettyCompile(std::string input) {
|
||||
return prettyCompileLLL(compileToLLL(input));
|
||||
}
|
||||
|
||||
std::string compileChunk(std::string input) {
|
||||
return compileLLL(compileChunkToLLL(input));
|
||||
}
|
||||
|
||||
std::vector<Node> prettyCompileChunk(std::string input) {
|
||||
return prettyCompileLLL(compileChunkToLLL(input));
|
||||
}
|
35
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/funcs.h
generated
vendored
Normal file
35
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/funcs.h
generated
vendored
Normal file
@ -0,0 +1,35 @@
|
||||
#include <stdio.h>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include "bignum.h"
|
||||
#include "util.h"
|
||||
#include "parser.h"
|
||||
#include "lllparser.h"
|
||||
#include "compiler.h"
|
||||
#include "rewriter.h"
|
||||
#include "tokenize.h"
|
||||
|
||||
// Function listing:
|
||||
//
|
||||
// parseSerpent (serpent -> AST) std::string -> Node
|
||||
// parseLLL (LLL -> AST) std::string -> Node
|
||||
// rewrite (apply rewrite rules) Node -> Node
|
||||
// compileToLLL (serpent -> LLL) std::string -> Node
|
||||
// compileLLL (LLL -> EVMhex) Node -> std::string
|
||||
// prettyCompileLLL (LLL -> EVMasm) Node -> std::vector<Node>
|
||||
// prettyCompile (serpent -> EVMasm) std::string -> std::vector>Node>
|
||||
// compile (serpent -> EVMhex) std::string -> std::string
|
||||
// get_file_contents (filename -> file) std::string -> std::string
|
||||
// exists (does file exist?) std::string -> bool
|
||||
|
||||
Node compileToLLL(std::string input);
|
||||
|
||||
Node compileChunkToLLL(std::string input);
|
||||
|
||||
std::string compile(std::string input);
|
||||
|
||||
std::vector<Node> prettyCompile(std::string input);
|
||||
|
||||
std::string compileChunk(std::string input);
|
||||
|
||||
std::vector<Node> prettyCompileChunk(std::string input);
|
203
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/functions.cpp
generated
vendored
Normal file
203
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/functions.cpp
generated
vendored
Normal file
@ -0,0 +1,203 @@
|
||||
#include <stdio.h>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include "util.h"
|
||||
#include "lllparser.h"
|
||||
#include "bignum.h"
|
||||
#include "optimize.h"
|
||||
#include "rewriteutils.h"
|
||||
#include "preprocess.h"
|
||||
#include "functions.h"
|
||||
|
||||
std::string getSignature(std::vector<Node> args) {
|
||||
std::string o;
|
||||
for (unsigned i = 0; i < args.size(); i++) {
|
||||
if (args[i].val == ":" && args[i].args[1].val == "s")
|
||||
o += "s";
|
||||
else if (args[i].val == ":" && args[i].args[1].val == "a")
|
||||
o += "a";
|
||||
else
|
||||
o += "i";
|
||||
}
|
||||
return o;
|
||||
}
|
||||
|
||||
// Convert a list of arguments into a node containing a
|
||||
// < datastart, datasz > pair
|
||||
|
||||
Node packArguments(std::vector<Node> args, std::string sig,
|
||||
int funId, Metadata m) {
|
||||
// Plain old 32 byte arguments
|
||||
std::vector<Node> nargs;
|
||||
// Variable-sized arguments
|
||||
std::vector<Node> vargs;
|
||||
// Variable sizes
|
||||
std::vector<Node> sizes;
|
||||
// Is a variable an array?
|
||||
std::vector<bool> isArray;
|
||||
// Fill up above three argument lists
|
||||
int argCount = 0;
|
||||
for (unsigned i = 0; i < args.size(); i++) {
|
||||
Metadata m = args[i].metadata;
|
||||
if (args[i].val == "=") {
|
||||
// do nothing
|
||||
}
|
||||
else {
|
||||
// Determine the correct argument type
|
||||
char argType;
|
||||
if (sig.size() > 0) {
|
||||
if (argCount >= (signed)sig.size())
|
||||
err("Too many args", m);
|
||||
argType = sig[argCount];
|
||||
}
|
||||
else argType = 'i';
|
||||
// Integer (also usable for short strings)
|
||||
if (argType == 'i') {
|
||||
if (args[i].val == ":")
|
||||
err("Function asks for int, provided string or array", m);
|
||||
nargs.push_back(args[i]);
|
||||
}
|
||||
// Long string
|
||||
else if (argType == 's') {
|
||||
if (args[i].val != ":")
|
||||
err("Must specify string length", m);
|
||||
vargs.push_back(args[i].args[0]);
|
||||
sizes.push_back(args[i].args[1]);
|
||||
isArray.push_back(false);
|
||||
}
|
||||
// Array
|
||||
else if (argType == 'a') {
|
||||
if (args[i].val != ":")
|
||||
err("Must specify array length", m);
|
||||
vargs.push_back(args[i].args[0]);
|
||||
sizes.push_back(args[i].args[1]);
|
||||
isArray.push_back(true);
|
||||
}
|
||||
else err("Invalid arg type in signature", m);
|
||||
argCount++;
|
||||
}
|
||||
}
|
||||
int static_arg_size = 1 + (vargs.size() + nargs.size()) * 32;
|
||||
// Start off by saving the size variables and calculating the total
|
||||
msn kwargs;
|
||||
kwargs["funid"] = tkn(utd(funId), m);
|
||||
std::string pattern =
|
||||
"(with _sztot "+utd(static_arg_size)+" "
|
||||
" (with _sizes (alloc "+utd(sizes.size() * 32)+") "
|
||||
" (seq ";
|
||||
for (unsigned i = 0; i < sizes.size(); i++) {
|
||||
std::string sizeIncrement =
|
||||
isArray[i] ? "(mul 32 _x)" : "_x";
|
||||
pattern +=
|
||||
"(with _x $sz"+utd(i)+"(seq "
|
||||
" (mstore (add _sizes "+utd(i * 32)+") _x) "
|
||||
" (set _sztot (add _sztot "+sizeIncrement+" )))) ";
|
||||
kwargs["sz"+utd(i)] = sizes[i];
|
||||
}
|
||||
// Allocate memory, and set first data byte
|
||||
pattern +=
|
||||
"(with _datastart (alloc (add _sztot 32)) (seq "
|
||||
" (mstore8 _datastart $funid) ";
|
||||
// Copy over size variables
|
||||
for (unsigned i = 0; i < sizes.size(); i++) {
|
||||
int v = 1 + i * 32;
|
||||
pattern +=
|
||||
" (mstore "
|
||||
" (add _datastart "+utd(v)+") "
|
||||
" (mload (add _sizes "+utd(v-1)+"))) ";
|
||||
}
|
||||
// Store normal arguments
|
||||
for (unsigned i = 0; i < nargs.size(); i++) {
|
||||
int v = 1 + (i + sizes.size()) * 32;
|
||||
pattern +=
|
||||
" (mstore (add _datastart "+utd(v)+") $"+utd(i)+") ";
|
||||
kwargs[utd(i)] = nargs[i];
|
||||
}
|
||||
// Loop through variable-sized arguments, store them
|
||||
pattern +=
|
||||
" (with _pos (add _datastart "+utd(static_arg_size)+") (seq";
|
||||
for (unsigned i = 0; i < vargs.size(); i++) {
|
||||
std::string copySize =
|
||||
isArray[i] ? "(mul 32 (mload (add _sizes "+utd(i * 32)+")))"
|
||||
: "(mload (add _sizes "+utd(i * 32)+"))";
|
||||
pattern +=
|
||||
" (unsafe_mcopy _pos $vl"+utd(i)+" "+copySize+") "
|
||||
" (set _pos (add _pos "+copySize+")) ";
|
||||
kwargs["vl"+utd(i)] = vargs[i];
|
||||
}
|
||||
// Return a 2-item array containing the start and size
|
||||
pattern += " (array_lit _datastart _sztot))))))))";
|
||||
std::string prefix = "_temp_"+mkUniqueToken();
|
||||
// Fill in pattern, return triple
|
||||
return subst(parseLLL(pattern), kwargs, prefix, m);
|
||||
}
|
||||
|
||||
// Create a node for argument unpacking
|
||||
Node unpackArguments(std::vector<Node> vars, Metadata m) {
|
||||
std::vector<std::string> varNames;
|
||||
std::vector<std::string> longVarNames;
|
||||
std::vector<bool> longVarIsArray;
|
||||
// Fill in variable and long variable names, as well as which
|
||||
// long variables are arrays and which are strings
|
||||
for (unsigned i = 0; i < vars.size(); i++) {
|
||||
if (vars[i].val == ":") {
|
||||
if (vars[i].args.size() != 2)
|
||||
err("Malformed def!", m);
|
||||
longVarNames.push_back(vars[i].args[0].val);
|
||||
std::string tag = vars[i].args[1].val;
|
||||
if (tag == "s")
|
||||
longVarIsArray.push_back(false);
|
||||
else if (tag == "a")
|
||||
longVarIsArray.push_back(true);
|
||||
else
|
||||
err("Function value can only be string or array", m);
|
||||
}
|
||||
else {
|
||||
varNames.push_back(vars[i].val);
|
||||
}
|
||||
}
|
||||
std::vector<Node> sub;
|
||||
if (!varNames.size() && !longVarNames.size()) {
|
||||
// do nothing if we have no arguments
|
||||
}
|
||||
else {
|
||||
std::vector<Node> varNodes;
|
||||
for (unsigned i = 0; i < longVarNames.size(); i++)
|
||||
varNodes.push_back(token(longVarNames[i], m));
|
||||
for (unsigned i = 0; i < varNames.size(); i++)
|
||||
varNodes.push_back(token(varNames[i], m));
|
||||
// Copy over variable lengths and short variables
|
||||
for (unsigned i = 0; i < varNodes.size(); i++) {
|
||||
int pos = 1 + i * 32;
|
||||
std::string prefix = (i < longVarNames.size()) ? "_len_" : "";
|
||||
sub.push_back(asn("untyped", asn("set",
|
||||
token(prefix+varNodes[i].val, m),
|
||||
asn("calldataload", tkn(utd(pos), m), m),
|
||||
m)));
|
||||
}
|
||||
// Copy over long variables
|
||||
if (longVarNames.size() > 0) {
|
||||
std::vector<Node> sub2;
|
||||
int pos = varNodes.size() * 32 + 1;
|
||||
Node tot = tkn("_tot", m);
|
||||
for (unsigned i = 0; i < longVarNames.size(); i++) {
|
||||
Node var = tkn(longVarNames[i], m);
|
||||
Node varlen = longVarIsArray[i]
|
||||
? asn("mul", tkn("32", m), tkn("_len_"+longVarNames[i], m))
|
||||
: tkn("_len_"+longVarNames[i], m);
|
||||
sub2.push_back(asn("untyped",
|
||||
asn("set", var, asn("alloc", varlen))));
|
||||
sub2.push_back(asn("calldatacopy", var, tot, varlen));
|
||||
sub2.push_back(asn("set", tot, asn("add", tot, varlen)));
|
||||
}
|
||||
std::string prefix = "_temp_"+mkUniqueToken();
|
||||
sub.push_back(subst(
|
||||
astnode("with", tot, tkn(utd(pos), m), asn("seq", sub2)),
|
||||
msn(),
|
||||
prefix,
|
||||
m));
|
||||
}
|
||||
}
|
||||
return asn("seq", sub, m);
|
||||
}
|
39
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/functions.h
generated
vendored
Normal file
39
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/functions.h
generated
vendored
Normal file
@ -0,0 +1,39 @@
|
||||
#ifndef ETHSERP_FUNCTIONS
|
||||
#define ETHSERP_FUNCTIONS
|
||||
|
||||
#include <stdio.h>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include "util.h"
|
||||
#include "lllparser.h"
|
||||
#include "bignum.h"
|
||||
#include "optimize.h"
|
||||
#include "rewriteutils.h"
|
||||
#include "preprocess.h"
|
||||
|
||||
|
||||
class argPack {
|
||||
public:
|
||||
argPack(Node a, Node b, Node c) {
|
||||
pre = a;
|
||||
datastart = b;
|
||||
datasz = c;
|
||||
}
|
||||
Node pre;
|
||||
Node datastart;
|
||||
Node datasz;
|
||||
};
|
||||
|
||||
// Get a signature from a function
|
||||
std::string getSignature(std::vector<Node> args);
|
||||
|
||||
// Convert a list of arguments into a <pre, mstart, msize> node
|
||||
// triple, given the signature of a function
|
||||
Node packArguments(std::vector<Node> args, std::string sig,
|
||||
int funId, Metadata m);
|
||||
|
||||
// Create a node for argument unpacking
|
||||
Node unpackArguments(std::vector<Node> vars, Metadata m);
|
||||
|
||||
#endif
|
70
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/lllparser.cpp
generated
vendored
Normal file
70
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/lllparser.cpp
generated
vendored
Normal file
@ -0,0 +1,70 @@
|
||||
#include <stdio.h>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include "util.h"
|
||||
#include "lllparser.h"
|
||||
#include "tokenize.h"
|
||||
|
||||
struct _parseOutput {
|
||||
Node node;
|
||||
int newpos;
|
||||
};
|
||||
|
||||
// Helper, returns subtree and position of start of next node
|
||||
_parseOutput _parse(std::vector<Node> inp, int pos) {
|
||||
Metadata met = inp[pos].metadata;
|
||||
_parseOutput o;
|
||||
// Bracket: keep grabbing tokens until we get to the
|
||||
// corresponding closing bracket
|
||||
if (inp[pos].val == "(" || inp[pos].val == "[") {
|
||||
std::string fun, rbrack;
|
||||
std::vector<Node> args;
|
||||
pos += 1;
|
||||
if (inp[pos].val == "[") {
|
||||
fun = "access";
|
||||
rbrack = "]";
|
||||
}
|
||||
else rbrack = ")";
|
||||
// First argument is the function
|
||||
while (inp[pos].val != ")") {
|
||||
_parseOutput po = _parse(inp, pos);
|
||||
if (fun.length() == 0 && po.node.type == 1) {
|
||||
std::cerr << "Error: first arg must be function\n";
|
||||
fun = po.node.val;
|
||||
}
|
||||
else if (fun.length() == 0) {
|
||||
fun = po.node.val;
|
||||
}
|
||||
else {
|
||||
args.push_back(po.node);
|
||||
}
|
||||
pos = po.newpos;
|
||||
}
|
||||
o.newpos = pos + 1;
|
||||
o.node = astnode(fun, args, met);
|
||||
}
|
||||
// Normal token, return it and advance to next token
|
||||
else {
|
||||
o.newpos = pos + 1;
|
||||
o.node = token(inp[pos].val, met);
|
||||
}
|
||||
return o;
|
||||
}
|
||||
|
||||
// stream of tokens -> lisp parse tree
|
||||
Node parseLLLTokenStream(std::vector<Node> inp) {
|
||||
_parseOutput o = _parse(inp, 0);
|
||||
return o.node;
|
||||
}
|
||||
|
||||
// Parses LLL
|
||||
Node parseLLL(std::string s, bool allowFileRead) {
|
||||
std::string input = s;
|
||||
std::string file = "main";
|
||||
if (exists(s) && allowFileRead) {
|
||||
file = s;
|
||||
input = get_file_contents(s);
|
||||
}
|
||||
return parseLLLTokenStream(tokenize(s, Metadata(file, 0, 0), true));
|
||||
}
|
13
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/lllparser.h
generated
vendored
Normal file
13
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/lllparser.h
generated
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
#ifndef ETHSERP_LLLPARSER
|
||||
#define ETHSERP_LLLPARSER
|
||||
|
||||
#include <stdio.h>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include "util.h"
|
||||
|
||||
// LLL text -> parse tree
|
||||
Node parseLLL(std::string s, bool allowFileRead=false);
|
||||
|
||||
#endif
|
154
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/opcodes.cpp
generated
vendored
Normal file
154
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/opcodes.cpp
generated
vendored
Normal file
@ -0,0 +1,154 @@
|
||||
#include <stdio.h>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include "opcodes.h"
|
||||
#include "util.h"
|
||||
#include "bignum.h"
|
||||
|
||||
Mapping mapping[] = {
|
||||
Mapping("STOP", 0x00, 0, 0),
|
||||
Mapping("ADD", 0x01, 2, 1),
|
||||
Mapping("MUL", 0x02, 2, 1),
|
||||
Mapping("SUB", 0x03, 2, 1),
|
||||
Mapping("DIV", 0x04, 2, 1),
|
||||
Mapping("SDIV", 0x05, 2, 1),
|
||||
Mapping("MOD", 0x06, 2, 1),
|
||||
Mapping("SMOD", 0x07, 2, 1),
|
||||
Mapping("ADDMOD", 0x08, 3, 1),
|
||||
Mapping("MULMOD", 0x09, 3, 1),
|
||||
Mapping("EXP", 0x0a, 2, 1),
|
||||
Mapping("SIGNEXTEND", 0x0b, 2, 1),
|
||||
Mapping("LT", 0x10, 2, 1),
|
||||
Mapping("GT", 0x11, 2, 1),
|
||||
Mapping("SLT", 0x12, 2, 1),
|
||||
Mapping("SGT", 0x13, 2, 1),
|
||||
Mapping("EQ", 0x14, 2, 1),
|
||||
Mapping("ISZERO", 0x15, 1, 1),
|
||||
Mapping("AND", 0x16, 2, 1),
|
||||
Mapping("OR", 0x17, 2, 1),
|
||||
Mapping("XOR", 0x18, 2, 1),
|
||||
Mapping("NOT", 0x19, 1, 1),
|
||||
Mapping("BYTE", 0x1a, 2, 1),
|
||||
Mapping("SHA3", 0x20, 2, 1),
|
||||
Mapping("ADDRESS", 0x30, 0, 1),
|
||||
Mapping("BALANCE", 0x31, 1, 1),
|
||||
Mapping("ORIGIN", 0x32, 0, 1),
|
||||
Mapping("CALLER", 0x33, 0, 1),
|
||||
Mapping("CALLVALUE", 0x34, 0, 1),
|
||||
Mapping("CALLDATALOAD", 0x35, 1, 1),
|
||||
Mapping("CALLDATASIZE", 0x36, 0, 1),
|
||||
Mapping("CALLDATACOPY", 0x37, 3, 0),
|
||||
Mapping("CODESIZE", 0x38, 0, 1),
|
||||
Mapping("CODECOPY", 0x39, 3, 0),
|
||||
Mapping("GASPRICE", 0x3a, 0, 1),
|
||||
Mapping("EXTCODESIZE", 0x3b, 1, 1),
|
||||
Mapping("EXTCODECOPY", 0x3c, 4, 0),
|
||||
Mapping("PREVHASH", 0x40, 0, 1),
|
||||
Mapping("COINBASE", 0x41, 0, 1),
|
||||
Mapping("TIMESTAMP", 0x42, 0, 1),
|
||||
Mapping("NUMBER", 0x43, 0, 1),
|
||||
Mapping("DIFFICULTY", 0x44, 0, 1),
|
||||
Mapping("GASLIMIT", 0x45, 0, 1),
|
||||
Mapping("POP", 0x50, 1, 0),
|
||||
Mapping("MLOAD", 0x51, 1, 1),
|
||||
Mapping("MSTORE", 0x52, 2, 0),
|
||||
Mapping("MSTORE8", 0x53, 2, 0),
|
||||
Mapping("SLOAD", 0x54, 1, 1),
|
||||
Mapping("SSTORE", 0x55, 2, 0),
|
||||
Mapping("JUMP", 0x56, 1, 0),
|
||||
Mapping("JUMPI", 0x57, 2, 0),
|
||||
Mapping("PC", 0x58, 0, 1),
|
||||
Mapping("MSIZE", 0x59, 0, 1),
|
||||
Mapping("GAS", 0x5a, 0, 1),
|
||||
Mapping("JUMPDEST", 0x5b, 0, 0),
|
||||
Mapping("LOG0", 0xa0, 2, 0),
|
||||
Mapping("LOG1", 0xa1, 3, 0),
|
||||
Mapping("LOG2", 0xa2, 4, 0),
|
||||
Mapping("LOG3", 0xa3, 5, 0),
|
||||
Mapping("LOG4", 0xa4, 6, 0),
|
||||
Mapping("CREATE", 0xf0, 3, 1),
|
||||
Mapping("CALL", 0xf1, 7, 1),
|
||||
Mapping("CALLCODE", 0xf2, 7, 1),
|
||||
Mapping("RETURN", 0xf3, 2, 0),
|
||||
Mapping("SUICIDE", 0xff, 1, 0),
|
||||
Mapping("---END---", 0x00, 0, 0),
|
||||
};
|
||||
|
||||
std::map<std::string, std::vector<int> > opcodes;
|
||||
std::map<int, std::string> reverseOpcodes;
|
||||
|
||||
// Fetches everything EXCEPT PUSH1..32
|
||||
std::pair<std::string, std::vector<int> > _opdata(std::string ops, int opi) {
|
||||
if (!opcodes.size()) {
|
||||
int i = 0;
|
||||
while (mapping[i].op != "---END---") {
|
||||
Mapping mi = mapping[i];
|
||||
opcodes[mi.op] = triple(mi.opcode, mi.in, mi.out);
|
||||
i++;
|
||||
}
|
||||
for (i = 1; i <= 16; i++) {
|
||||
opcodes["DUP"+unsignedToDecimal(i)] = triple(0x7f + i, i, i+1);
|
||||
opcodes["SWAP"+unsignedToDecimal(i)] = triple(0x8f + i, i+1, i+1);
|
||||
}
|
||||
for (std::map<std::string, std::vector<int> >::iterator it=opcodes.begin();
|
||||
it != opcodes.end();
|
||||
it++) {
|
||||
reverseOpcodes[(*it).second[0]] = (*it).first;
|
||||
}
|
||||
}
|
||||
ops = upperCase(ops);
|
||||
std::string op;
|
||||
std::vector<int> opdata;
|
||||
op = reverseOpcodes.count(opi) ? reverseOpcodes[opi] : "";
|
||||
opdata = opcodes.count(ops) ? opcodes[ops] : triple(-1, -1, -1);
|
||||
return std::pair<std::string, std::vector<int> >(op, opdata);
|
||||
}
|
||||
|
||||
int opcode(std::string op) {
|
||||
return _opdata(op, -1).second[0];
|
||||
}
|
||||
|
||||
int opinputs(std::string op) {
|
||||
return _opdata(op, -1).second[1];
|
||||
}
|
||||
|
||||
int opoutputs(std::string op) {
|
||||
return _opdata(op, -1).second[2];
|
||||
}
|
||||
|
||||
std::string op(int opcode) {
|
||||
return _opdata("", opcode).first;
|
||||
}
|
||||
|
||||
std::string lllSpecials[][3] = {
|
||||
{ "ref", "1", "1" },
|
||||
{ "get", "1", "1" },
|
||||
{ "set", "2", "2" },
|
||||
{ "with", "3", "3" },
|
||||
{ "comment", "0", "2147483647" },
|
||||
{ "ops", "0", "2147483647" },
|
||||
{ "lll", "2", "2" },
|
||||
{ "seq", "0", "2147483647" },
|
||||
{ "if", "3", "3" },
|
||||
{ "unless", "2", "2" },
|
||||
{ "until", "2", "2" },
|
||||
{ "alloc", "1", "1" },
|
||||
{ "---END---", "0", "0" },
|
||||
};
|
||||
|
||||
std::map<std::string, std::pair<int, int> > lllMap;
|
||||
|
||||
// Is a function name one of the valid functions above?
|
||||
bool isValidLLLFunc(std::string f, int argc) {
|
||||
if (lllMap.size() == 0) {
|
||||
for (int i = 0; ; i++) {
|
||||
if (lllSpecials[i][0] == "---END---") break;
|
||||
lllMap[lllSpecials[i][0]] = std::pair<int, int>(
|
||||
dtu(lllSpecials[i][1]), dtu(lllSpecials[i][2]));
|
||||
}
|
||||
}
|
||||
return lllMap.count(f)
|
||||
&& argc >= lllMap[f].first
|
||||
&& argc <= lllMap[f].second;
|
||||
}
|
45
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/opcodes.h
generated
vendored
Normal file
45
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/opcodes.h
generated
vendored
Normal file
@ -0,0 +1,45 @@
|
||||
#ifndef ETHSERP_OPCODES
|
||||
#define ETHSERP_OPCODES
|
||||
|
||||
#include <stdio.h>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include "util.h"
|
||||
|
||||
class Mapping {
|
||||
public:
|
||||
Mapping(std::string Op, int Opcode, int In, int Out) {
|
||||
op = Op;
|
||||
opcode = Opcode;
|
||||
in = In;
|
||||
out = Out;
|
||||
}
|
||||
std::string op;
|
||||
int opcode;
|
||||
int in;
|
||||
int out;
|
||||
};
|
||||
|
||||
extern Mapping mapping[];
|
||||
|
||||
extern std::map<std::string, std::vector<int> > opcodes;
|
||||
extern std::map<int, std::string> reverseOpcodes;
|
||||
|
||||
std::pair<std::string, std::vector<int> > _opdata(std::string ops, int opi);
|
||||
|
||||
int opcode(std::string op);
|
||||
|
||||
int opinputs(std::string op);
|
||||
|
||||
int opoutputs(std::string op);
|
||||
|
||||
std::string op(int opcode);
|
||||
|
||||
extern std::string lllSpecials[][3];
|
||||
|
||||
extern std::map<std::string, std::pair<int, int> > lllMap;
|
||||
|
||||
bool isValidLLLFunc(std::string f, int argc);
|
||||
|
||||
#endif
|
98
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/optimize.cpp
generated
vendored
Normal file
98
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/optimize.cpp
generated
vendored
Normal file
@ -0,0 +1,98 @@
|
||||
#include <stdio.h>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include "util.h"
|
||||
#include "lllparser.h"
|
||||
#include "bignum.h"
|
||||
|
||||
// Compile-time arithmetic calculations
|
||||
Node optimize(Node inp) {
|
||||
if (inp.type == TOKEN) {
|
||||
Node o = tryNumberize(inp);
|
||||
if (decimalGt(o.val, tt256, true))
|
||||
err("Value too large (exceeds 32 bytes or 2^256)", inp.metadata);
|
||||
return o;
|
||||
}
|
||||
for (unsigned i = 0; i < inp.args.size(); i++) {
|
||||
inp.args[i] = optimize(inp.args[i]);
|
||||
}
|
||||
// Arithmetic-specific transform
|
||||
if (inp.val == "+") inp.val = "add";
|
||||
if (inp.val == "*") inp.val = "mul";
|
||||
if (inp.val == "-") inp.val = "sub";
|
||||
if (inp.val == "/") inp.val = "sdiv";
|
||||
if (inp.val == "^") inp.val = "exp";
|
||||
if (inp.val == "**") inp.val = "exp";
|
||||
if (inp.val == "%") inp.val = "smod";
|
||||
// Degenerate cases for add and mul
|
||||
if (inp.args.size() == 2) {
|
||||
if (inp.val == "add" && inp.args[0].type == TOKEN &&
|
||||
inp.args[0].val == "0") {
|
||||
Node x = inp.args[1];
|
||||
inp = x;
|
||||
}
|
||||
if (inp.val == "add" && inp.args[1].type == TOKEN &&
|
||||
inp.args[1].val == "0") {
|
||||
Node x = inp.args[0];
|
||||
inp = x;
|
||||
}
|
||||
if (inp.val == "mul" && inp.args[0].type == TOKEN &&
|
||||
inp.args[0].val == "1") {
|
||||
Node x = inp.args[1];
|
||||
inp = x;
|
||||
}
|
||||
if (inp.val == "mul" && inp.args[1].type == TOKEN &&
|
||||
inp.args[1].val == "1") {
|
||||
Node x = inp.args[0];
|
||||
inp = x;
|
||||
}
|
||||
}
|
||||
// Arithmetic computation
|
||||
if (inp.args.size() == 2
|
||||
&& inp.args[0].type == TOKEN
|
||||
&& inp.args[1].type == TOKEN) {
|
||||
std::string o;
|
||||
if (inp.val == "add") {
|
||||
o = decimalMod(decimalAdd(inp.args[0].val, inp.args[1].val), tt256);
|
||||
}
|
||||
else if (inp.val == "sub") {
|
||||
if (decimalGt(inp.args[0].val, inp.args[1].val, true))
|
||||
o = decimalSub(inp.args[0].val, inp.args[1].val);
|
||||
}
|
||||
else if (inp.val == "mul") {
|
||||
o = decimalMod(decimalMul(inp.args[0].val, inp.args[1].val), tt256);
|
||||
}
|
||||
else if (inp.val == "div" && inp.args[1].val != "0") {
|
||||
o = decimalDiv(inp.args[0].val, inp.args[1].val);
|
||||
}
|
||||
else if (inp.val == "sdiv" && inp.args[1].val != "0"
|
||||
&& decimalGt(tt255, inp.args[0].val)
|
||||
&& decimalGt(tt255, inp.args[1].val)) {
|
||||
o = decimalDiv(inp.args[0].val, inp.args[1].val);
|
||||
}
|
||||
else if (inp.val == "mod" && inp.args[1].val != "0") {
|
||||
o = decimalMod(inp.args[0].val, inp.args[1].val);
|
||||
}
|
||||
else if (inp.val == "smod" && inp.args[1].val != "0"
|
||||
&& decimalGt(tt255, inp.args[0].val)
|
||||
&& decimalGt(tt255, inp.args[1].val)) {
|
||||
o = decimalMod(inp.args[0].val, inp.args[1].val);
|
||||
}
|
||||
else if (inp.val == "exp") {
|
||||
o = decimalModExp(inp.args[0].val, inp.args[1].val, tt256);
|
||||
}
|
||||
if (o.length()) return token(o, inp.metadata);
|
||||
}
|
||||
return inp;
|
||||
}
|
||||
|
||||
// Is a node degenerate (ie. trivial to calculate) ?
|
||||
bool isDegenerate(Node n) {
|
||||
return optimize(n).type == TOKEN;
|
||||
}
|
||||
|
||||
// Is a node purely arithmetic?
|
||||
bool isPureArithmetic(Node n) {
|
||||
return isNumberLike(optimize(n));
|
||||
}
|
19
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/optimize.h
generated
vendored
Normal file
19
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/optimize.h
generated
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
#ifndef ETHSERP_OPTIMIZER
|
||||
#define ETHSERP_OPTIMIZER
|
||||
|
||||
#include <stdio.h>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include "util.h"
|
||||
|
||||
// Compile-time arithmetic calculations
|
||||
Node optimize(Node inp);
|
||||
|
||||
// Is a node degenerate (ie. trivial to calculate) ?
|
||||
bool isDegenerate(Node n);
|
||||
|
||||
// Is a node purely arithmetic?
|
||||
bool isPureArithmetic(Node n);
|
||||
|
||||
#endif
|
430
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/parser.cpp
generated
vendored
Normal file
430
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/parser.cpp
generated
vendored
Normal file
@ -0,0 +1,430 @@
|
||||
#include <stdio.h>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include "util.h"
|
||||
#include "parser.h"
|
||||
#include "tokenize.h"
|
||||
|
||||
// Extended BEDMAS precedence order
|
||||
int precedence(Node tok) {
|
||||
std::string v = tok.val;
|
||||
if (v == ".") return -1;
|
||||
else if (v == "!" || v == "not") return 1;
|
||||
else if (v=="^" || v == "**") return 2;
|
||||
else if (v=="*" || v=="/" || v=="%") return 3;
|
||||
else if (v=="+" || v=="-") return 4;
|
||||
else if (v=="<" || v==">" || v=="<=" || v==">=") return 5;
|
||||
else if (v=="&" || v=="|" || v=="xor" || v=="==" || v == "!=") return 6;
|
||||
else if (v=="&&" || v=="and") return 7;
|
||||
else if (v=="||" || v=="or") return 8;
|
||||
else if (v=="=") return 10;
|
||||
else if (v=="+=" || v=="-=" || v=="*=" || v=="/=" || v=="%=") return 10;
|
||||
else if (v==":" || v == "::") return 11;
|
||||
else return 0;
|
||||
}
|
||||
|
||||
// Token classification for shunting-yard purposes
|
||||
int toktype(Node tok) {
|
||||
if (tok.type == ASTNODE) return COMPOUND;
|
||||
std::string v = tok.val;
|
||||
if (v == "(" || v == "[" || v == "{") return LPAREN;
|
||||
else if (v == ")" || v == "]" || v == "}") return RPAREN;
|
||||
else if (v == ",") return COMMA;
|
||||
else if (v == "!" || v == "~" || v == "not") return UNARY_OP;
|
||||
else if (precedence(tok) > 0) return BINARY_OP;
|
||||
else if (precedence(tok) < 0) return TOKEN_SPLITTER;
|
||||
if (tok.val[0] != '"' && tok.val[0] != '\'') {
|
||||
for (unsigned i = 0; i < tok.val.length(); i++) {
|
||||
if (chartype(tok.val[i]) == SYMB) {
|
||||
err("Invalid symbol: "+tok.val, tok.metadata);
|
||||
}
|
||||
}
|
||||
}
|
||||
return ALPHANUM;
|
||||
}
|
||||
|
||||
|
||||
// Converts to reverse polish notation
|
||||
std::vector<Node> shuntingYard(std::vector<Node> tokens) {
|
||||
std::vector<Node> iq;
|
||||
for (int i = tokens.size() - 1; i >= 0; i--) {
|
||||
iq.push_back(tokens[i]);
|
||||
}
|
||||
std::vector<Node> oq;
|
||||
std::vector<Node> stack;
|
||||
Node prev, tok;
|
||||
int prevtyp = 0, toktyp = 0;
|
||||
|
||||
while (iq.size()) {
|
||||
prev = tok;
|
||||
prevtyp = toktyp;
|
||||
tok = iq.back();
|
||||
toktyp = toktype(tok);
|
||||
iq.pop_back();
|
||||
// Alphanumerics go straight to output queue
|
||||
if (toktyp == ALPHANUM) {
|
||||
oq.push_back(tok);
|
||||
}
|
||||
// Left parens go on stack and output queue
|
||||
else if (toktyp == LPAREN) {
|
||||
while (stack.size() && toktype(stack.back()) == TOKEN_SPLITTER) {
|
||||
oq.push_back(stack.back());
|
||||
stack.pop_back();
|
||||
}
|
||||
if (prevtyp != ALPHANUM && prevtyp != RPAREN) {
|
||||
oq.push_back(token("id", tok.metadata));
|
||||
}
|
||||
stack.push_back(tok);
|
||||
oq.push_back(tok);
|
||||
}
|
||||
// If rparen, keep moving from stack to output queue until lparen
|
||||
else if (toktyp == RPAREN) {
|
||||
while (stack.size() && toktype(stack.back()) != LPAREN) {
|
||||
oq.push_back(stack.back());
|
||||
stack.pop_back();
|
||||
}
|
||||
if (stack.size()) {
|
||||
stack.pop_back();
|
||||
}
|
||||
oq.push_back(tok);
|
||||
}
|
||||
else if (toktyp == UNARY_OP) {
|
||||
stack.push_back(tok);
|
||||
}
|
||||
// If token splitter, just push it to the stack
|
||||
else if (toktyp == TOKEN_SPLITTER) {
|
||||
while (stack.size() && toktype(stack.back()) == TOKEN_SPLITTER) {
|
||||
oq.push_back(stack.back());
|
||||
stack.pop_back();
|
||||
}
|
||||
stack.push_back(tok);
|
||||
}
|
||||
// If binary op, keep popping from stack while higher bedmas precedence
|
||||
else if (toktyp == BINARY_OP) {
|
||||
if (tok.val == "-" && prevtyp != ALPHANUM && prevtyp != RPAREN) {
|
||||
stack.push_back(tok);
|
||||
oq.push_back(token("0", tok.metadata));
|
||||
}
|
||||
else {
|
||||
int prec = precedence(tok);
|
||||
while (stack.size()
|
||||
&& (toktype(stack.back()) == BINARY_OP
|
||||
|| toktype(stack.back()) == UNARY_OP
|
||||
|| toktype(stack.back()) == TOKEN_SPLITTER)
|
||||
&& precedence(stack.back()) <= prec) {
|
||||
oq.push_back(stack.back());
|
||||
stack.pop_back();
|
||||
}
|
||||
stack.push_back(tok);
|
||||
}
|
||||
}
|
||||
// Comma means finish evaluating the argument
|
||||
else if (toktyp == COMMA) {
|
||||
while (stack.size() && toktype(stack.back()) != LPAREN) {
|
||||
oq.push_back(stack.back());
|
||||
stack.pop_back();
|
||||
}
|
||||
}
|
||||
}
|
||||
while (stack.size()) {
|
||||
oq.push_back(stack.back());
|
||||
stack.pop_back();
|
||||
}
|
||||
return oq;
|
||||
}
|
||||
|
||||
// Converts reverse polish notation into tree
|
||||
Node treefy(std::vector<Node> stream) {
|
||||
std::vector<Node> iq;
|
||||
for (int i = stream.size() -1; i >= 0; i--) {
|
||||
iq.push_back(stream[i]);
|
||||
}
|
||||
std::vector<Node> oq;
|
||||
while (iq.size()) {
|
||||
Node tok = iq.back();
|
||||
iq.pop_back();
|
||||
int typ = toktype(tok);
|
||||
// If unary, take node off end of oq and wrap it with the operator
|
||||
// If binary, do the same with two nodes
|
||||
if (typ == UNARY_OP || typ == BINARY_OP || typ == TOKEN_SPLITTER) {
|
||||
std::vector<Node> args;
|
||||
int rounds = (typ == UNARY_OP) ? 1 : 2;
|
||||
for (int i = 0; i < rounds; i++) {
|
||||
if (oq.size() == 0) {
|
||||
err("Line malformed, not enough args for "+tok.val,
|
||||
tok.metadata);
|
||||
}
|
||||
args.push_back(oq.back());
|
||||
oq.pop_back();
|
||||
}
|
||||
std::vector<Node> args2;
|
||||
while (args.size()) {
|
||||
args2.push_back(args.back());
|
||||
args.pop_back();
|
||||
}
|
||||
oq.push_back(astnode(tok.val, args2, tok.metadata));
|
||||
}
|
||||
// If rparen, keep grabbing until we get to an lparen
|
||||
else if (typ == RPAREN) {
|
||||
std::vector<Node> args;
|
||||
while (1) {
|
||||
if (toktype(oq.back()) == LPAREN) break;
|
||||
args.push_back(oq.back());
|
||||
oq.pop_back();
|
||||
if (!oq.size()) err("Bracket without matching", tok.metadata);
|
||||
}
|
||||
oq.pop_back();
|
||||
args.push_back(oq.back());
|
||||
oq.pop_back();
|
||||
// We represent a[b] as (access a b)
|
||||
if (tok.val == "]")
|
||||
args.push_back(token("access", tok.metadata));
|
||||
if (args.back().type == ASTNODE)
|
||||
args.push_back(token("fun", tok.metadata));
|
||||
std::string fun = args.back().val;
|
||||
args.pop_back();
|
||||
// We represent [1,2,3] as (array_lit 1 2 3)
|
||||
if (fun == "access" && args.size() && args.back().val == "id") {
|
||||
fun = "array_lit";
|
||||
args.pop_back();
|
||||
}
|
||||
std::vector<Node> args2;
|
||||
while (args.size()) {
|
||||
args2.push_back(args.back());
|
||||
args.pop_back();
|
||||
}
|
||||
// When evaluating 2 + (3 * 5), the shunting yard algo turns that
|
||||
// into 2 ( id 3 5 * ) +, effectively putting "id" as a dummy
|
||||
// function where the algo was expecting a function to call the
|
||||
// thing inside the brackets. This reverses that step
|
||||
if (fun == "id" && args2.size() == 1) {
|
||||
oq.push_back(args2[0]);
|
||||
}
|
||||
else {
|
||||
oq.push_back(astnode(fun, args2, tok.metadata));
|
||||
}
|
||||
}
|
||||
else oq.push_back(tok);
|
||||
// This is messy, but has to be done. Import/inset other files here
|
||||
std::string v = oq.back().val;
|
||||
if ((v == "inset" || v == "import" || v == "create")
|
||||
&& oq.back().args.size() == 1
|
||||
&& oq.back().args[0].type == TOKEN) {
|
||||
int lastSlashPos = tok.metadata.file.rfind("/");
|
||||
std::string root;
|
||||
if (lastSlashPos >= 0)
|
||||
root = tok.metadata.file.substr(0, lastSlashPos) + "/";
|
||||
else
|
||||
root = "";
|
||||
std::string filename = oq.back().args[0].val;
|
||||
filename = filename.substr(1, filename.length() - 2);
|
||||
if (!exists(root + filename))
|
||||
err("File does not exist: "+root + filename, tok.metadata);
|
||||
oq.back().args.pop_back();
|
||||
oq.back().args.push_back(parseSerpent(root + filename));
|
||||
}
|
||||
//Useful for debugging
|
||||
//for (int i = 0; i < oq.size(); i++) {
|
||||
// std::cerr << printSimple(oq[i]) << " ";
|
||||
//}
|
||||
//std::cerr << " <-\n";
|
||||
}
|
||||
// Output must have one argument
|
||||
if (oq.size() == 0) {
|
||||
err("Output blank", Metadata());
|
||||
}
|
||||
else if (oq.size() > 1) {
|
||||
return asn("multi", oq, oq[0].metadata);
|
||||
}
|
||||
|
||||
return oq[0];
|
||||
}
|
||||
|
||||
|
||||
// Parses one line of serpent
|
||||
Node parseSerpentTokenStream(std::vector<Node> s) {
|
||||
return treefy(shuntingYard(s));
|
||||
}
|
||||
|
||||
|
||||
// Count spaces at beginning of line
|
||||
int spaceCount(std::string s) {
|
||||
unsigned pos = 0;
|
||||
while (pos < s.length() && (s[pos] == ' ' || s[pos] == '\t'))
|
||||
pos++;
|
||||
return pos;
|
||||
}
|
||||
|
||||
// Is this a command that takes an argument on the same line?
|
||||
bool bodied(std::string tok) {
|
||||
return tok == "if" || tok == "elif" || tok == "while"
|
||||
|| tok == "with" || tok == "def" || tok == "extern"
|
||||
|| tok == "data" || tok == "assert" || tok == "return"
|
||||
|| tok == "fun" || tok == "scope" || tok == "macro"
|
||||
|| tok == "type";
|
||||
}
|
||||
|
||||
// Are the two commands meant to continue each other?
|
||||
bool bodiedContinued(std::string prev, std::string tok) {
|
||||
return (prev == "if" && tok == "elif")
|
||||
|| (prev == "elif" && tok == "else")
|
||||
|| (prev == "elif" && tok == "elif")
|
||||
|| (prev == "if" && tok == "else");
|
||||
}
|
||||
|
||||
// Is a line of code empty?
|
||||
bool isLineEmpty(std::string line) {
|
||||
std::vector<Node> tokens = tokenize(line);
|
||||
if (!tokens.size() || tokens[0].val == "#" || tokens[0].val == "//")
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Parse lines of serpent (helper function)
|
||||
Node parseLines(std::vector<std::string> lines, Metadata metadata, int sp) {
|
||||
std::vector<Node> o;
|
||||
int origLine = metadata.ln;
|
||||
unsigned i = 0;
|
||||
while (i < lines.size()) {
|
||||
metadata.ln = origLine + i;
|
||||
std::string main = lines[i];
|
||||
if (isLineEmpty(main)) {
|
||||
i += 1;
|
||||
continue;
|
||||
}
|
||||
int spaces = spaceCount(main);
|
||||
if (spaces != sp) {
|
||||
err("Indent mismatch", metadata);
|
||||
}
|
||||
// Tokenize current line
|
||||
std::vector<Node> tokens = tokenize(main.substr(sp), metadata);
|
||||
// Remove comments
|
||||
std::vector<Node> tokens2;
|
||||
for (unsigned j = 0; j < tokens.size(); j++) {
|
||||
if (tokens[j].val == "#" || tokens[j].val == "//") break;
|
||||
tokens2.push_back(tokens[j]);
|
||||
}
|
||||
bool expectingChildBlock = false;
|
||||
if (tokens2.size() > 0 && tokens2.back().val == ":") {
|
||||
tokens2.pop_back();
|
||||
expectingChildBlock = true;
|
||||
}
|
||||
// Parse current line
|
||||
Node out = parseSerpentTokenStream(tokens2);
|
||||
// Parse child block
|
||||
int childIndent = 999999;
|
||||
std::vector<std::string> childBlock;
|
||||
while (1) {
|
||||
i++;
|
||||
if (i >= lines.size())
|
||||
break;
|
||||
bool ile = isLineEmpty(lines[i]);
|
||||
if (!ile) {
|
||||
int spaces = spaceCount(lines[i]);
|
||||
if (spaces <= sp) break;
|
||||
childBlock.push_back(lines[i]);
|
||||
if (spaces < childIndent) childIndent = spaces;
|
||||
}
|
||||
else childBlock.push_back("");
|
||||
}
|
||||
// Child block empty?
|
||||
bool cbe = true;
|
||||
for (unsigned i = 0; i < childBlock.size(); i++) {
|
||||
if (childBlock[i].length() > 0) { cbe = false; break; }
|
||||
}
|
||||
// Add child block to AST
|
||||
if (expectingChildBlock) {
|
||||
if (cbe)
|
||||
err("Expected indented child block!", out.metadata);
|
||||
out.type = ASTNODE;
|
||||
metadata.ln += 1;
|
||||
out.args.push_back(parseLines(childBlock, metadata, childIndent));
|
||||
metadata.ln -= 1;
|
||||
}
|
||||
else if (!cbe)
|
||||
err("Did not expect indented child block!", out.metadata);
|
||||
else if (out.args.size() && out.args[out.args.size() - 1].val == ":") {
|
||||
Node n = out.args[out.args.size() - 1];
|
||||
out.args.pop_back();
|
||||
out.args.push_back(n.args[0]);
|
||||
out.args.push_back(n.args[1]);
|
||||
}
|
||||
// Bring back if / elif into AST
|
||||
if (bodied(tokens[0].val)) {
|
||||
if (out.val != "multi") {
|
||||
// token not being used in bodied form
|
||||
}
|
||||
else if (out.args[0].val == "id")
|
||||
out = astnode(tokens[0].val, out.args[1].args, out.metadata);
|
||||
else if (out.args[0].type == TOKEN) {
|
||||
std::vector<Node> out2;
|
||||
for (unsigned i = 1; i < out.args.size(); i++)
|
||||
out2.push_back(out.args[i]);
|
||||
out = astnode(tokens[0].val, out2, out.metadata);
|
||||
}
|
||||
else
|
||||
out = astnode("fun", out.args, out.metadata);
|
||||
}
|
||||
// Multi not supported
|
||||
if (out.val == "multi")
|
||||
err("Multiple expressions or unclosed bracket", out.metadata);
|
||||
// Convert top-level colon expressions into non-colon expressions;
|
||||
// makes if statements and the like equivalent indented or not
|
||||
//if (out.val == ":" && out.args[0].type == TOKEN)
|
||||
// out = asn(out.args[0].val, out.args[1], out.metadata);
|
||||
//if (bodied(tokens[0].val) && out.args[0].val == ":")
|
||||
// out = asn(tokens[0].val, out.args[0].args);
|
||||
if (o.size() == 0 || o.back().type == TOKEN) {
|
||||
o.push_back(out);
|
||||
continue;
|
||||
}
|
||||
// This is a little complicated. Basically, the idea here is to build
|
||||
// constructions like [if [< x 5] [a] [elif [< x 10] [b] [else [c]]]]
|
||||
std::vector<Node> u;
|
||||
u.push_back(o.back());
|
||||
if (bodiedContinued(o.back().val, out.val)) {
|
||||
while (1) {
|
||||
if (!bodiedContinued(u.back().val, out.val)) {
|
||||
u.pop_back();
|
||||
break;
|
||||
}
|
||||
if (!u.back().args.size()
|
||||
|| !bodiedContinued(u.back().val, u.back().args.back().val)) {
|
||||
break;
|
||||
}
|
||||
u.push_back(u.back().args.back());
|
||||
}
|
||||
u.back().args.push_back(out);
|
||||
while (u.size() > 1) {
|
||||
Node v = u.back();
|
||||
u.pop_back();
|
||||
u.back().args.pop_back();
|
||||
u.back().args.push_back(v);
|
||||
}
|
||||
o.pop_back();
|
||||
o.push_back(u[0]);
|
||||
}
|
||||
else o.push_back(out);
|
||||
}
|
||||
if (o.size() == 1)
|
||||
return o[0];
|
||||
else if (o.size())
|
||||
return astnode("seq", o, o[0].metadata);
|
||||
else
|
||||
return astnode("seq", o, Metadata());
|
||||
}
|
||||
|
||||
// Parses serpent code
|
||||
Node parseSerpent(std::string s) {
|
||||
std::string input = s;
|
||||
std::string file = "main";
|
||||
if (exists(s)) {
|
||||
file = s;
|
||||
input = get_file_contents(s);
|
||||
}
|
||||
return parseLines(splitLines(input), Metadata(file, 0, 0), 0);
|
||||
}
|
||||
|
||||
|
||||
using namespace std;
|
13
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/parser.h
generated
vendored
Normal file
13
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/parser.h
generated
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
#ifndef ETHSERP_PARSER
|
||||
#define ETHSERP_PARSER
|
||||
|
||||
#include <stdio.h>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include "util.h"
|
||||
|
||||
// Serpent text -> parse tree
|
||||
Node parseSerpent(std::string s);
|
||||
|
||||
#endif
|
299
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/preprocess.cpp
generated
vendored
Normal file
299
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/preprocess.cpp
generated
vendored
Normal file
@ -0,0 +1,299 @@
|
||||
#include <stdio.h>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include "util.h"
|
||||
#include "lllparser.h"
|
||||
#include "bignum.h"
|
||||
#include "rewriteutils.h"
|
||||
#include "optimize.h"
|
||||
#include "preprocess.h"
|
||||
#include "functions.h"
|
||||
#include "opcodes.h"
|
||||
|
||||
// Convert a function of the form (def (f x y z) (do stuff)) into
|
||||
// (if (first byte of ABI is correct) (seq (setup x y z) (do stuff)))
|
||||
Node convFunction(Node node, int functionCount) {
|
||||
std::string prefix = "_temp"+mkUniqueToken()+"_";
|
||||
Metadata m = node.metadata;
|
||||
|
||||
if (node.args.size() != 2)
|
||||
err("Malformed def!", m);
|
||||
// Collect the list of variable names and variable byte counts
|
||||
Node unpack = unpackArguments(node.args[0].args, m);
|
||||
// And the actual code
|
||||
Node body = node.args[1];
|
||||
// Main LLL-based function body
|
||||
return astnode("if",
|
||||
astnode("eq",
|
||||
astnode("get", token("__funid", m), m),
|
||||
token(unsignedToDecimal(functionCount), m),
|
||||
m),
|
||||
astnode("seq", unpack, body, m));
|
||||
}
|
||||
|
||||
// Populate an svObj with the arguments needed to determine
|
||||
// the storage position of a node
|
||||
svObj getStorageVars(svObj pre, Node node, std::string prefix,
|
||||
int index) {
|
||||
Metadata m = node.metadata;
|
||||
if (!pre.globalOffset.size()) pre.globalOffset = "0";
|
||||
std::vector<Node> h;
|
||||
std::vector<std::string> coefficients;
|
||||
// Array accesses or atoms
|
||||
if (node.val == "access" || node.type == TOKEN) {
|
||||
std::string tot = "1";
|
||||
h = listfyStorageAccess(node);
|
||||
coefficients.push_back("1");
|
||||
for (unsigned i = h.size() - 1; i >= 1; i--) {
|
||||
// Array sizes must be constant or at least arithmetically
|
||||
// evaluable at compile time
|
||||
if (!isPureArithmetic(h[i]))
|
||||
err("Array size must be fixed value", m);
|
||||
// Create a list of the coefficient associated with each
|
||||
// array index
|
||||
coefficients.push_back(decimalMul(coefficients.back(), h[i].val));
|
||||
}
|
||||
}
|
||||
// Tuples
|
||||
else {
|
||||
int startc;
|
||||
// Handle the (fun <fun_astnode> args...) case
|
||||
if (node.val == "fun") {
|
||||
startc = 1;
|
||||
h = listfyStorageAccess(node.args[0]);
|
||||
}
|
||||
// Handle the (<fun_name> args...) case, which
|
||||
// the serpent parser produces when the function
|
||||
// is a simple name and not a complex astnode
|
||||
else {
|
||||
startc = 0;
|
||||
h = listfyStorageAccess(token(node.val, m));
|
||||
}
|
||||
svObj sub = pre;
|
||||
sub.globalOffset = "0";
|
||||
// Evaluate tuple elements recursively
|
||||
for (unsigned i = startc; i < node.args.size(); i++) {
|
||||
sub = getStorageVars(sub,
|
||||
node.args[i],
|
||||
prefix+h[0].val.substr(2)+".",
|
||||
i-startc);
|
||||
}
|
||||
coefficients.push_back(sub.globalOffset);
|
||||
for (unsigned i = h.size() - 1; i >= 1; i--) {
|
||||
// Array sizes must be constant or at least arithmetically
|
||||
// evaluable at compile time
|
||||
if (!isPureArithmetic(h[i]))
|
||||
err("Array size must be fixed value", m);
|
||||
// Create a list of the coefficient associated with each
|
||||
// array index
|
||||
coefficients.push_back(decimalMul(coefficients.back(), h[i].val));
|
||||
}
|
||||
pre.offsets = sub.offsets;
|
||||
pre.coefficients = sub.coefficients;
|
||||
pre.nonfinal = sub.nonfinal;
|
||||
pre.nonfinal[prefix+h[0].val.substr(2)] = true;
|
||||
}
|
||||
pre.coefficients[prefix+h[0].val.substr(2)] = coefficients;
|
||||
pre.offsets[prefix+h[0].val.substr(2)] = pre.globalOffset;
|
||||
pre.indices[prefix+h[0].val.substr(2)] = index;
|
||||
if (decimalGt(tt176, coefficients.back()))
|
||||
pre.globalOffset = decimalAdd(pre.globalOffset, coefficients.back());
|
||||
return pre;
|
||||
}
|
||||
|
||||
// Preprocess input containing functions
|
||||
//
|
||||
// localExterns is a map of the form, eg,
|
||||
//
|
||||
// { x: { foo: 0, bar: 1, baz: 2 }, y: { qux: 0, foo: 1 } ... }
|
||||
//
|
||||
// localExternSigs is a map of the form, eg,
|
||||
//
|
||||
// { x : { foo: iii, bar: iis, baz: ia }, y: { qux: i, foo: as } ... }
|
||||
//
|
||||
// Signifying that x.foo = 0, x.baz = 2, y.foo = 1, etc
|
||||
// and that x.foo has three integers as arguments, x.bar has two
|
||||
// integers and a variable-length string, and baz has an integer
|
||||
// and an array
|
||||
//
|
||||
// globalExterns is a one-level map, eg from above
|
||||
//
|
||||
// { foo: 1, bar: 1, baz: 2, qux: 0 }
|
||||
//
|
||||
// globalExternSigs is a one-level map, eg from above
|
||||
//
|
||||
// { foo: as, bar: iis, baz: ia, qux: i}
|
||||
//
|
||||
// Note that globalExterns and globalExternSigs may be ambiguous
|
||||
// Also, a null signature implies an infinite tail of integers
|
||||
preprocessResult preprocessInit(Node inp) {
|
||||
Metadata m = inp.metadata;
|
||||
if (inp.val != "seq")
|
||||
inp = astnode("seq", inp, m);
|
||||
std::vector<Node> empty = std::vector<Node>();
|
||||
Node init = astnode("seq", empty, m);
|
||||
Node shared = astnode("seq", empty, m);
|
||||
std::vector<Node> any;
|
||||
std::vector<Node> functions;
|
||||
preprocessAux out = preprocessAux();
|
||||
out.localExterns["self"] = std::map<std::string, int>();
|
||||
int functionCount = 0;
|
||||
int storageDataCount = 0;
|
||||
for (unsigned i = 0; i < inp.args.size(); i++) {
|
||||
Node obj = inp.args[i];
|
||||
// Functions
|
||||
if (obj.val == "def") {
|
||||
if (obj.args.size() == 0)
|
||||
err("Empty def", m);
|
||||
std::string funName = obj.args[0].val;
|
||||
// Init, shared and any are special functions
|
||||
if (funName == "init" || funName == "shared" || funName == "any") {
|
||||
if (obj.args[0].args.size())
|
||||
err(funName+" cannot have arguments", m);
|
||||
}
|
||||
if (funName == "init") init = obj.args[1];
|
||||
else if (funName == "shared") shared = obj.args[1];
|
||||
else if (funName == "any") any.push_back(obj.args[1]);
|
||||
else {
|
||||
// Other functions
|
||||
functions.push_back(convFunction(obj, functionCount));
|
||||
out.localExterns["self"][obj.args[0].val] = functionCount;
|
||||
out.localExternSigs["self"][obj.args[0].val]
|
||||
= getSignature(obj.args[0].args);
|
||||
functionCount++;
|
||||
}
|
||||
}
|
||||
// Extern declarations
|
||||
else if (obj.val == "extern") {
|
||||
std::string externName = obj.args[0].val;
|
||||
Node al = obj.args[1];
|
||||
if (!out.localExterns.count(externName))
|
||||
out.localExterns[externName] = std::map<std::string, int>();
|
||||
for (unsigned i = 0; i < al.args.size(); i++) {
|
||||
if (al.args[i].val == ":") {
|
||||
std::string v = al.args[i].args[0].val;
|
||||
std::string sig = al.args[i].args[1].val;
|
||||
out.globalExterns[v] = i;
|
||||
out.globalExternSigs[v] = sig;
|
||||
out.localExterns[externName][v] = i;
|
||||
out.localExternSigs[externName][v] = sig;
|
||||
}
|
||||
else {
|
||||
std::string v = al.args[i].val;
|
||||
out.globalExterns[v] = i;
|
||||
out.globalExternSigs[v] = "";
|
||||
out.localExterns[externName][v] = i;
|
||||
out.localExternSigs[externName][v] = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
// Custom macros
|
||||
else if (obj.val == "macro") {
|
||||
// Rules for valid macros:
|
||||
//
|
||||
// There are only four categories of valid macros:
|
||||
//
|
||||
// 1. a macro where the outer function is something
|
||||
// which is NOT an existing valid function/extern/datum
|
||||
// 2. a macro of the form set(c(x), d) where c must NOT
|
||||
// be an existing valid function/extern/datum
|
||||
// 3. something of the form access(c(x)), where c must NOT
|
||||
// be an existing valid function/extern/datum
|
||||
// 4. something of the form set(access(c(x)), d) where c must
|
||||
// NOT be an existing valid function/extern/datum
|
||||
bool valid = false;
|
||||
Node pattern = obj.args[0];
|
||||
Node substitution = obj.args[1];
|
||||
if (opcode(pattern.val) < 0 && !isValidFunctionName(pattern.val))
|
||||
valid = true;
|
||||
if (pattern.val == "set" &&
|
||||
opcode(pattern.args[0].val) < 0 &&
|
||||
!isValidFunctionName(pattern.args[0].val))
|
||||
valid = true;
|
||||
if (pattern.val == "access" &&
|
||||
opcode(pattern.args[0].val) < 0 &&
|
||||
!isValidFunctionName(pattern.args[0].val))
|
||||
if (pattern.val == "set" &&
|
||||
pattern.args[0].val == "access" &&
|
||||
opcode(pattern.args[0].args[0].val) < 0 &&
|
||||
!isValidFunctionName(pattern.args[0].args[0].val))
|
||||
valid = true;
|
||||
if (valid) {
|
||||
out.customMacros.push_back(rewriteRule(pattern, substitution));
|
||||
}
|
||||
}
|
||||
// Variable types
|
||||
else if (obj.val == "type") {
|
||||
std::string typeName = obj.args[0].val;
|
||||
std::vector<Node> vars = obj.args[1].args;
|
||||
for (unsigned i = 0; i < vars.size(); i++)
|
||||
out.types[vars[i].val] = typeName;
|
||||
}
|
||||
// Storage variables/structures
|
||||
else if (obj.val == "data") {
|
||||
out.storageVars = getStorageVars(out.storageVars,
|
||||
obj.args[0],
|
||||
"",
|
||||
storageDataCount);
|
||||
storageDataCount += 1;
|
||||
}
|
||||
else any.push_back(obj);
|
||||
}
|
||||
std::vector<Node> main;
|
||||
if (shared.args.size()) main.push_back(shared);
|
||||
if (init.args.size()) main.push_back(init);
|
||||
|
||||
std::vector<Node> code;
|
||||
if (shared.args.size()) code.push_back(shared);
|
||||
for (unsigned i = 0; i < any.size(); i++)
|
||||
code.push_back(any[i]);
|
||||
for (unsigned i = 0; i < functions.size(); i++)
|
||||
code.push_back(functions[i]);
|
||||
Node codeNode;
|
||||
if (functions.size() > 0) {
|
||||
codeNode = astnode("with",
|
||||
token("__funid", m),
|
||||
astnode("byte",
|
||||
token("0", m),
|
||||
astnode("calldataload", token("0", m), m),
|
||||
m),
|
||||
astnode("seq", code, m),
|
||||
m);
|
||||
}
|
||||
else codeNode = astnode("seq", code, m);
|
||||
main.push_back(astnode("~return",
|
||||
token("0", m),
|
||||
astnode("lll",
|
||||
codeNode,
|
||||
token("0", m),
|
||||
m),
|
||||
m));
|
||||
|
||||
|
||||
Node result;
|
||||
if (main.size() == 1) result = main[0];
|
||||
else result = astnode("seq", main, inp.metadata);
|
||||
return preprocessResult(result, out);
|
||||
}
|
||||
|
||||
preprocessResult processTypes (preprocessResult pr) {
|
||||
preprocessAux aux = pr.second;
|
||||
Node node = pr.first;
|
||||
if (node.type == TOKEN && aux.types.count(node.val)) {
|
||||
node = asn(aux.types[node.val], node, node.metadata);
|
||||
}
|
||||
else if (node.val == "untyped")
|
||||
return preprocessResult(node.args[0], aux);
|
||||
else {
|
||||
for (unsigned i = 0; i < node.args.size(); i++) {
|
||||
node.args[i] =
|
||||
processTypes(preprocessResult(node.args[i], aux)).first;
|
||||
}
|
||||
}
|
||||
return preprocessResult(node, aux);
|
||||
}
|
||||
|
||||
preprocessResult preprocess(Node n) {
|
||||
return processTypes(preprocessInit(n));
|
||||
}
|
58
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/preprocess.h
generated
vendored
Normal file
58
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/preprocess.h
generated
vendored
Normal file
@ -0,0 +1,58 @@
|
||||
#ifndef ETHSERP_PREPROCESSOR
|
||||
#define ETHSERP_PREPROCESSOR
|
||||
|
||||
#include <stdio.h>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include "util.h"
|
||||
|
||||
// Storage variable index storing object
|
||||
struct svObj {
|
||||
std::map<std::string, std::string> offsets;
|
||||
std::map<std::string, int> indices;
|
||||
std::map<std::string, std::vector<std::string> > coefficients;
|
||||
std::map<std::string, bool> nonfinal;
|
||||
std::string globalOffset;
|
||||
};
|
||||
|
||||
class rewriteRule {
|
||||
public:
|
||||
rewriteRule(Node p, Node s) {
|
||||
pattern = p;
|
||||
substitution = s;
|
||||
}
|
||||
Node pattern;
|
||||
Node substitution;
|
||||
};
|
||||
|
||||
|
||||
// Preprocessing result storing object
|
||||
class preprocessAux {
|
||||
public:
|
||||
preprocessAux() {
|
||||
globalExterns = std::map<std::string, int>();
|
||||
localExterns = std::map<std::string, std::map<std::string, int> >();
|
||||
localExterns["self"] = std::map<std::string, int>();
|
||||
}
|
||||
std::map<std::string, int> globalExterns;
|
||||
std::map<std::string, std::string> globalExternSigs;
|
||||
std::map<std::string, std::map<std::string, int> > localExterns;
|
||||
std::map<std::string, std::map<std::string, std::string> > localExternSigs;
|
||||
std::vector<rewriteRule> customMacros;
|
||||
std::map<std::string, std::string> types;
|
||||
svObj storageVars;
|
||||
};
|
||||
|
||||
#define preprocessResult std::pair<Node, preprocessAux>
|
||||
|
||||
// Populate an svObj with the arguments needed to determine
|
||||
// the storage position of a node
|
||||
svObj getStorageVars(svObj pre, Node node, std::string prefix="",
|
||||
int index=0);
|
||||
|
||||
// Preprocess a function (see cpp for details)
|
||||
preprocessResult preprocess(Node inp);
|
||||
|
||||
|
||||
#endif
|
173
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/pyserpent.cpp
generated
vendored
Normal file
173
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/pyserpent.cpp
generated
vendored
Normal file
@ -0,0 +1,173 @@
|
||||
#include <Python.h>
|
||||
#include "structmember.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <iostream>
|
||||
#include "funcs.h"
|
||||
|
||||
#define PYMETHOD(name, FROM, method, TO) \
|
||||
static PyObject * name(PyObject *, PyObject *args) { \
|
||||
try { \
|
||||
FROM(med) \
|
||||
return TO(method(med)); \
|
||||
} \
|
||||
catch (std::string e) { \
|
||||
PyErr_SetString(PyExc_Exception, e.c_str()); \
|
||||
return NULL; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define FROMSTR(v) \
|
||||
const char *command; \
|
||||
int len; \
|
||||
if (!PyArg_ParseTuple(args, "s#", &command, &len)) \
|
||||
return NULL; \
|
||||
std::string v = std::string(command, len); \
|
||||
|
||||
#define FROMNODE(v) \
|
||||
PyObject *node; \
|
||||
if (!PyArg_ParseTuple(args, "O", &node)) \
|
||||
return NULL; \
|
||||
Node v = cppifyNode(node);
|
||||
|
||||
#define FROMLIST(v) \
|
||||
PyObject *node; \
|
||||
if (!PyArg_ParseTuple(args, "O", &node)) \
|
||||
return NULL; \
|
||||
std::vector<Node> v = cppifyNodeList(node);
|
||||
|
||||
// Convert metadata into python wrapper form [file, ln, ch]
|
||||
PyObject* pyifyMetadata(Metadata m) {
|
||||
PyObject* a = PyList_New(0);
|
||||
PyList_Append(a, Py_BuildValue("s#", m.file.c_str(), m.file.length()));
|
||||
PyList_Append(a, Py_BuildValue("i", m.ln));
|
||||
PyList_Append(a, Py_BuildValue("i", m.ch));
|
||||
return a;
|
||||
}
|
||||
|
||||
// Convert node into python wrapper form
|
||||
// [token=0/astnode=1, val, metadata, args]
|
||||
PyObject* pyifyNode(Node n) {
|
||||
PyObject* a = PyList_New(0);
|
||||
PyList_Append(a, Py_BuildValue("i", n.type == ASTNODE));
|
||||
PyList_Append(a, Py_BuildValue("s#", n.val.c_str(), n.val.length()));
|
||||
PyList_Append(a, pyifyMetadata(n.metadata));
|
||||
for (unsigned i = 0; i < n.args.size(); i++)
|
||||
PyList_Append(a, pyifyNode(n.args[i]));
|
||||
return a;
|
||||
}
|
||||
|
||||
// Convert string into python wrapper form
|
||||
PyObject* pyifyString(std::string s) {
|
||||
return Py_BuildValue("s#", s.c_str(), s.length());
|
||||
}
|
||||
|
||||
// Convert list of nodes into python wrapper form
|
||||
PyObject* pyifyNodeList(std::vector<Node> n) {
|
||||
PyObject* a = PyList_New(0);
|
||||
for (unsigned i = 0; i < n.size(); i++)
|
||||
PyList_Append(a, pyifyNode(n[i]));
|
||||
return a;
|
||||
}
|
||||
|
||||
// Convert pyobject int into normal form
|
||||
int cppifyInt(PyObject* o) {
|
||||
int out;
|
||||
if (!PyArg_Parse(o, "i", &out))
|
||||
err("Argument should be integer", Metadata());
|
||||
return out;
|
||||
}
|
||||
|
||||
// Convert pyobject string into normal form
|
||||
std::string cppifyString(PyObject* o) {
|
||||
const char *command;
|
||||
if (!PyArg_Parse(o, "s", &command))
|
||||
err("Argument should be string", Metadata());
|
||||
return std::string(command);
|
||||
}
|
||||
|
||||
// Convert metadata from python wrapper form
|
||||
Metadata cppifyMetadata(PyObject* o) {
|
||||
std::string file = cppifyString(PyList_GetItem(o, 0));
|
||||
int ln = cppifyInt(PyList_GetItem(o, 1));
|
||||
int ch = cppifyInt(PyList_GetItem(o, 2));
|
||||
return Metadata(file, ln, ch);
|
||||
}
|
||||
|
||||
// Convert node from python wrapper form
|
||||
Node cppifyNode(PyObject* o) {
|
||||
Node n;
|
||||
int isAstNode = cppifyInt(PyList_GetItem(o, 0));
|
||||
n.type = isAstNode ? ASTNODE : TOKEN;
|
||||
n.val = cppifyString(PyList_GetItem(o, 1));
|
||||
n.metadata = cppifyMetadata(PyList_GetItem(o, 2));
|
||||
std::vector<Node> args;
|
||||
for (int i = 3; i < PyList_Size(o); i++) {
|
||||
args.push_back(cppifyNode(PyList_GetItem(o, i)));
|
||||
}
|
||||
n.args = args;
|
||||
return n;
|
||||
}
|
||||
|
||||
//Convert list of nodes into normal form
|
||||
std::vector<Node> cppifyNodeList(PyObject* o) {
|
||||
std::vector<Node> out;
|
||||
for (int i = 0; i < PyList_Size(o); i++) {
|
||||
out.push_back(cppifyNode(PyList_GetItem(o,i)));
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
PYMETHOD(ps_compile, FROMSTR, compile, pyifyString)
|
||||
PYMETHOD(ps_compile_chunk, FROMSTR, compileChunk, pyifyString)
|
||||
PYMETHOD(ps_compile_to_lll, FROMSTR, compileToLLL, pyifyNode)
|
||||
PYMETHOD(ps_compile_chunk_to_lll, FROMSTR, compileChunkToLLL, pyifyNode)
|
||||
PYMETHOD(ps_compile_lll, FROMNODE, compileLLL, pyifyString)
|
||||
PYMETHOD(ps_parse, FROMSTR, parseSerpent, pyifyNode)
|
||||
PYMETHOD(ps_rewrite, FROMNODE, rewrite, pyifyNode)
|
||||
PYMETHOD(ps_rewrite_chunk, FROMNODE, rewriteChunk, pyifyNode)
|
||||
PYMETHOD(ps_pretty_compile, FROMSTR, prettyCompile, pyifyNodeList)
|
||||
PYMETHOD(ps_pretty_compile_chunk, FROMSTR, prettyCompileChunk, pyifyNodeList)
|
||||
PYMETHOD(ps_pretty_compile_lll, FROMNODE, prettyCompileLLL, pyifyNodeList)
|
||||
PYMETHOD(ps_serialize, FROMLIST, serialize, pyifyString)
|
||||
PYMETHOD(ps_deserialize, FROMSTR, deserialize, pyifyNodeList)
|
||||
PYMETHOD(ps_parse_lll, FROMSTR, parseLLL, pyifyNode)
|
||||
|
||||
|
||||
static PyMethodDef PyextMethods[] = {
|
||||
{"compile", ps_compile, METH_VARARGS,
|
||||
"Compile code."},
|
||||
{"compile_chunk", ps_compile_chunk, METH_VARARGS,
|
||||
"Compile code chunk (no wrappers)."},
|
||||
{"compile_to_lll", ps_compile_to_lll, METH_VARARGS,
|
||||
"Compile code to LLL."},
|
||||
{"compile_chunk_to_lll", ps_compile_chunk_to_lll, METH_VARARGS,
|
||||
"Compile code chunk to LLL (no wrappers)."},
|
||||
{"compile_lll", ps_compile_lll, METH_VARARGS,
|
||||
"Compile LLL to EVM."},
|
||||
{"parse", ps_parse, METH_VARARGS,
|
||||
"Parse serpent"},
|
||||
{"rewrite", ps_rewrite, METH_VARARGS,
|
||||
"Rewrite parsed serpent to LLL"},
|
||||
{"rewrite_chunk", ps_rewrite_chunk, METH_VARARGS,
|
||||
"Rewrite parsed serpent to LLL (no wrappers)"},
|
||||
{"pretty_compile", ps_pretty_compile, METH_VARARGS,
|
||||
"Compile to EVM opcodes"},
|
||||
{"pretty_compile_chunk", ps_pretty_compile_chunk, METH_VARARGS,
|
||||
"Compile chunk to EVM opcodes (no wrappers)"},
|
||||
{"pretty_compile_lll", ps_pretty_compile_lll, METH_VARARGS,
|
||||
"Compile LLL to EVM opcodes"},
|
||||
{"serialize", ps_serialize, METH_VARARGS,
|
||||
"Convert EVM opcodes to bin"},
|
||||
{"deserialize", ps_deserialize, METH_VARARGS,
|
||||
"Convert EVM bin to opcodes"},
|
||||
{"parse_lll", ps_parse_lll, METH_VARARGS,
|
||||
"Parse LLL"},
|
||||
{NULL, NULL, 0, NULL} /* Sentinel */
|
||||
};
|
||||
|
||||
PyMODINIT_FUNC initserpent_pyext(void)
|
||||
{
|
||||
Py_InitModule( "serpent_pyext", PyextMethods );
|
||||
}
|
1
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/pyserpent.py
generated
vendored
Normal file
1
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/pyserpent.py
generated
vendored
Normal file
@ -0,0 +1 @@
|
||||
from serpent import *
|
804
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/rewriter.cpp
generated
vendored
Normal file
804
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/rewriter.cpp
generated
vendored
Normal file
@ -0,0 +1,804 @@
|
||||
#include <stdio.h>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include "util.h"
|
||||
#include "lllparser.h"
|
||||
#include "bignum.h"
|
||||
#include "optimize.h"
|
||||
#include "rewriteutils.h"
|
||||
#include "preprocess.h"
|
||||
#include "functions.h"
|
||||
#include "opcodes.h"
|
||||
|
||||
// Rewrite rules
|
||||
std::string macros[][2] = {
|
||||
{
|
||||
"(seq $x)",
|
||||
"$x"
|
||||
},
|
||||
{
|
||||
"(seq (seq) $x)",
|
||||
"$x"
|
||||
},
|
||||
{
|
||||
"(+= $a $b)",
|
||||
"(set $a (+ $a $b))"
|
||||
},
|
||||
{
|
||||
"(*= $a $b)",
|
||||
"(set $a (* $a $b))"
|
||||
},
|
||||
{
|
||||
"(-= $a $b)",
|
||||
"(set $a (- $a $b))"
|
||||
},
|
||||
{
|
||||
"(/= $a $b)",
|
||||
"(set $a (/ $a $b))"
|
||||
},
|
||||
{
|
||||
"(%= $a $b)",
|
||||
"(set $a (% $a $b))"
|
||||
},
|
||||
{
|
||||
"(^= $a $b)",
|
||||
"(set $a (^ $a $b))"
|
||||
},
|
||||
{
|
||||
"(!= $a $b)",
|
||||
"(iszero (eq $a $b))"
|
||||
},
|
||||
{
|
||||
"(assert $x)",
|
||||
"(unless $x (stop))"
|
||||
},
|
||||
{
|
||||
"(min $a $b)",
|
||||
"(with $1 $a (with $2 $b (if (lt $1 $2) $1 $2)))"
|
||||
},
|
||||
{
|
||||
"(max $a $b)",
|
||||
"(with $1 $a (with $2 $b (if (lt $1 $2) $2 $1)))"
|
||||
},
|
||||
{
|
||||
"(smin $a $b)",
|
||||
"(with $1 $a (with $2 $b (if (slt $1 $2) $1 $2)))"
|
||||
},
|
||||
{
|
||||
"(smax $a $b)",
|
||||
"(with $1 $a (with $2 $b (if (slt $1 $2) $2 $1)))"
|
||||
},
|
||||
{
|
||||
"(if $cond $do (else $else))",
|
||||
"(if $cond $do $else)"
|
||||
},
|
||||
{
|
||||
"(code $code)",
|
||||
"$code"
|
||||
},
|
||||
{
|
||||
"(slice $arr $pos)",
|
||||
"(add $arr (mul 32 $pos))",
|
||||
},
|
||||
{
|
||||
"(array $len)",
|
||||
"(alloc (mul 32 $len))"
|
||||
},
|
||||
{
|
||||
"(while $cond $do)",
|
||||
"(until (iszero $cond) $do)",
|
||||
},
|
||||
{
|
||||
"(while (iszero $cond) $do)",
|
||||
"(until $cond $do)",
|
||||
},
|
||||
{
|
||||
"(if $cond $do)",
|
||||
"(unless (iszero $cond) $do)",
|
||||
},
|
||||
{
|
||||
"(if (iszero $cond) $do)",
|
||||
"(unless $cond $do)",
|
||||
},
|
||||
{
|
||||
"(access (. self storage) $ind)",
|
||||
"(sload $ind)"
|
||||
},
|
||||
{
|
||||
"(access $var $ind)",
|
||||
"(mload (add $var (mul 32 $ind)))"
|
||||
},
|
||||
{
|
||||
"(set (access (. self storage) $ind) $val)",
|
||||
"(sstore $ind $val)"
|
||||
},
|
||||
{
|
||||
"(set (access $var $ind) $val)",
|
||||
"(mstore (add $var (mul 32 $ind)) $val)"
|
||||
},
|
||||
{
|
||||
"(getch $var $ind)",
|
||||
"(mod (mload (sub (add $var $ind) 31)) 256)"
|
||||
},
|
||||
{
|
||||
"(setch $var $ind $val)",
|
||||
"(mstore8 (add $var $ind) $val)",
|
||||
},
|
||||
{
|
||||
"(send $to $value)",
|
||||
"(~call (sub (gas) 25) $to $value 0 0 0 0)"
|
||||
},
|
||||
{
|
||||
"(send $gas $to $value)",
|
||||
"(~call $gas $to $value 0 0 0 0)"
|
||||
},
|
||||
{
|
||||
"(sha3 $x)",
|
||||
"(seq (set $1 $x) (~sha3 (ref $1) 32))"
|
||||
},
|
||||
{
|
||||
"(sha3 $mstart (= chars $msize))",
|
||||
"(~sha3 $mstart $msize)"
|
||||
},
|
||||
{
|
||||
"(sha3 $mstart $msize)",
|
||||
"(~sha3 $mstart (mul 32 $msize))"
|
||||
},
|
||||
{
|
||||
"(id $0)",
|
||||
"$0"
|
||||
},
|
||||
{
|
||||
"(return $x)",
|
||||
"(seq (set $1 $x) (~return (ref $1) 32))"
|
||||
},
|
||||
{
|
||||
"(return $mstart (= chars $msize))",
|
||||
"(~return $mstart $msize)"
|
||||
},
|
||||
{
|
||||
"(return $start $len)",
|
||||
"(~return $start (mul 32 $len))"
|
||||
},
|
||||
{
|
||||
"(&& $x $y)",
|
||||
"(if $x $y 0)"
|
||||
},
|
||||
{
|
||||
"(|| $x $y)",
|
||||
"(with $1 $x (if $1 $1 $y))"
|
||||
},
|
||||
{
|
||||
"(>= $x $y)",
|
||||
"(iszero (slt $x $y))"
|
||||
},
|
||||
{
|
||||
"(<= $x $y)",
|
||||
"(iszero (sgt $x $y))"
|
||||
},
|
||||
{
|
||||
"(create $code)",
|
||||
"(create 0 $code)"
|
||||
},
|
||||
{
|
||||
"(create $endowment $code)",
|
||||
"(with $1 (msize) (create $endowment (get $1) (lll (outer $code) (msize))))"
|
||||
},
|
||||
{
|
||||
"(sha256 $x)",
|
||||
"(with $1 (alloc 64) (seq (mstore (add (get $1) 32) $x) (pop (~call 101 2 0 (add (get $1) 32) 32 (get $1) 32)) (mload (get $1))))"
|
||||
},
|
||||
{
|
||||
"(sha256 $arr (= chars $sz))",
|
||||
"(with $1 (alloc 32) (seq (pop (~call 101 2 0 $arr $sz (get $1) 32)) (mload (get $1))))"
|
||||
},
|
||||
{
|
||||
"(sha256 $arr $sz)",
|
||||
"(with $1 (alloc 32) (seq (pop (~call 101 2 0 $arr (mul 32 $sz) (get $1) 32)) (mload (get $1))))"
|
||||
},
|
||||
{
|
||||
"(ripemd160 $x)",
|
||||
"(with $1 (alloc 64) (seq (mstore (add (get $1) 32) $x) (pop (~call 101 3 0 (add (get $1) 32) 32 (get $1) 32)) (mload (get $1))))"
|
||||
},
|
||||
{
|
||||
"(ripemd160 $arr (= chars $sz))",
|
||||
"(with $1 (alloc 32) (seq (pop (~call 101 3 0 $arr $sz (mload $1) 32)) (mload (get $1))))"
|
||||
},
|
||||
{
|
||||
"(ripemd160 $arr $sz)",
|
||||
"(with $1 (alloc 32) (seq (pop (~call 101 3 0 $arr (mul 32 $sz) (get $1) 32)) (mload (get $1))))"
|
||||
},
|
||||
{
|
||||
"(ecrecover $h $v $r $s)",
|
||||
"(with $1 (alloc 160) (seq (mstore (get $1) $h) (mstore (add (get $1) 32) $v) (mstore (add (get $1) 64) $r) (mstore (add (get $1) 96) $s) (pop (~call 101 1 0 (get $1) 128 (add (get $1 128)) 32)) (mload (add (get $1) 128))))"
|
||||
},
|
||||
{
|
||||
"(inset $x)",
|
||||
"$x"
|
||||
},
|
||||
{
|
||||
"(create $x)",
|
||||
"(with $1 (msize) (create $val (get $1) (lll $code (get $1))))"
|
||||
},
|
||||
{
|
||||
"(with (= $var $val) $cond)",
|
||||
"(with $var $val $cond)"
|
||||
},
|
||||
{
|
||||
"(log $t1)",
|
||||
"(~log1 0 0 $t1)"
|
||||
},
|
||||
{
|
||||
"(log $t1 $t2)",
|
||||
"(~log2 0 0 $t1 $t2)"
|
||||
},
|
||||
{
|
||||
"(log $t1 $t2 $t3)",
|
||||
"(~log3 0 0 $t1 $t2 $t3)"
|
||||
},
|
||||
{
|
||||
"(log $t1 $t2 $t3 $t4)",
|
||||
"(~log4 0 0 $t1 $t2 $t3 $t4)"
|
||||
},
|
||||
{
|
||||
"(logarr $a $sz)",
|
||||
"(~log0 $a (mul 32 $sz))"
|
||||
},
|
||||
{
|
||||
"(logarr $a $sz $t1)",
|
||||
"(~log1 $a (mul 32 $sz) $t1)"
|
||||
},
|
||||
{
|
||||
"(logarr $a $sz $t1 $t2)",
|
||||
"(~log2 $a (mul 32 $sz) $t1 $t2)"
|
||||
},
|
||||
{
|
||||
"(logarr $a $sz $t1 $t2 $t3)",
|
||||
"(~log3 $a (mul 32 $sz) $t1 $t2 $t3)"
|
||||
},
|
||||
{
|
||||
"(logarr $a $sz $t1 $t2 $t3 $t4)",
|
||||
"(~log4 $a (mul 32 $sz) $t1 $t2 $t3 $t4)"
|
||||
},
|
||||
{
|
||||
"(save $loc $array (= chars $count))",
|
||||
"(with $location (ref $loc) (with $c $count (with $end (div $c 32) (with $i 0 (seq (while (slt $i $end) (seq (sstore (add $i $location) (access $array $i)) (set $i (add $i 1)))) (sstore (add $i $location) (~and (access $array $i) (sub 0 (exp 256 (sub 32 (mod $c 32)))))))))))"
|
||||
},
|
||||
{
|
||||
"(save $loc $array $count)",
|
||||
"(with $location (ref $loc) (with $end $count (with $i 0 (while (slt $i $end) (seq (sstore (add $i $location) (access $array $i)) (set $i (add $i 1)))))))"
|
||||
},
|
||||
{
|
||||
"(load $loc (= chars $count))",
|
||||
"(with $location (ref $loc) (with $c $count (with $a (alloc $c) (with $i 0 (seq (while (slt $i (div $c 32)) (seq (set (access $a $i) (sload (add $location $i))) (set $i (add $i 1)))) (set (access $a $i) (~and (sload (add $location $i)) (sub 0 (exp 256 (sub 32 (mod $c 32)))))) $a)))))"
|
||||
},
|
||||
{
|
||||
"(load $loc $count)",
|
||||
"(with $location (ref $loc) (with $c $count (with $a (alloc $c) (with $i 0 (seq (while (slt $i $c) (seq (set (access $a $i) (sload (add $location $i))) (set $i (add $i 1)))) $a)))))"
|
||||
},
|
||||
{
|
||||
"(unsafe_mcopy $to $from $sz)",
|
||||
"(with _sz $sz (with _from $from (with _to $to (seq (comment STARTING UNSAFE MCOPY) (with _i 0 (while (lt _i _sz) (seq (mstore (add $to _i) (mload (add _from _i))) (set _i (add _i 32)))))))))"
|
||||
},
|
||||
{
|
||||
"(mcopy $to $from $_sz)",
|
||||
"(with _to $to (with _from $from (with _sz $sz (seq (comment STARTING MCOPY (with _i 0 (seq (while (lt (add _i 31) _sz) (seq (mstore (add _to _i) (mload (add _from _i))) (set _i (add _i 32)))) (with _mask (exp 256 (sub 32 (mod _sz 32))) (mstore (add $to _i) (add (mod (mload (add $to _i)) _mask) (and (mload (add $from _i)) (sub 0 _mask))))))))))))"
|
||||
},
|
||||
{ "(. msg sender)", "(caller)" },
|
||||
{ "(. msg value)", "(callvalue)" },
|
||||
{ "(. tx gasprice)", "(gasprice)" },
|
||||
{ "(. tx origin)", "(origin)" },
|
||||
{ "(. tx gas)", "(gas)" },
|
||||
{ "(. $x balance)", "(balance $x)" },
|
||||
{ "self", "(address)" },
|
||||
{ "(. block prevhash)", "(prevhash)" },
|
||||
{ "(. block coinbase)", "(coinbase)" },
|
||||
{ "(. block timestamp)", "(timestamp)" },
|
||||
{ "(. block number)", "(number)" },
|
||||
{ "(. block difficulty)", "(difficulty)" },
|
||||
{ "(. block gaslimit)", "(gaslimit)" },
|
||||
{ "stop", "(stop)" },
|
||||
{ "---END---", "" } //Keep this line at the end of the list
|
||||
};
|
||||
|
||||
std::vector<rewriteRule> nodeMacros;
|
||||
|
||||
// Token synonyms
|
||||
std::string synonyms[][2] = {
|
||||
{ "or", "||" },
|
||||
{ "and", "&&" },
|
||||
{ "|", "~or" },
|
||||
{ "&", "~and" },
|
||||
{ "elif", "if" },
|
||||
{ "!", "iszero" },
|
||||
{ "~", "~not" },
|
||||
{ "not", "iszero" },
|
||||
{ "string", "alloc" },
|
||||
{ "+", "add" },
|
||||
{ "-", "sub" },
|
||||
{ "*", "mul" },
|
||||
{ "/", "sdiv" },
|
||||
{ "^", "exp" },
|
||||
{ "**", "exp" },
|
||||
{ "%", "smod" },
|
||||
{ "<", "slt" },
|
||||
{ ">", "sgt" },
|
||||
{ "=", "set" },
|
||||
{ "==", "eq" },
|
||||
{ ":", "kv" },
|
||||
{ "---END---", "" } //Keep this line at the end of the list
|
||||
};
|
||||
|
||||
// Custom setters (need to be registered separately
|
||||
// for use with managed storage)
|
||||
std::string setters[][2] = {
|
||||
{ "+=", "+" },
|
||||
{ "-=", "-" },
|
||||
{ "*=", "*" },
|
||||
{ "/=", "/" },
|
||||
{ "%=", "%" },
|
||||
{ "^=", "^" },
|
||||
{ "---END---", "" } //Keep this line at the end of the list
|
||||
};
|
||||
|
||||
// Processes mutable array literals
|
||||
Node array_lit_transform(Node node) {
|
||||
std::string prefix = "_temp"+mkUniqueToken() + "_";
|
||||
Metadata m = node.metadata;
|
||||
std::map<std::string, Node> d;
|
||||
std::string o = "(seq (set $arr (alloc "+utd(node.args.size()*32)+"))";
|
||||
for (unsigned i = 0; i < node.args.size(); i++) {
|
||||
o += " (mstore (add (get $arr) "+utd(i * 32)+") $"+utd(i)+")";
|
||||
d[utd(i)] = node.args[i];
|
||||
}
|
||||
o += " (get $arr))";
|
||||
return subst(parseLLL(o), d, prefix, m);
|
||||
}
|
||||
|
||||
|
||||
Node apply_rules(preprocessResult pr);
|
||||
|
||||
// Transform "<variable>.<fun>(args...)" into
|
||||
// a call
|
||||
Node dotTransform(Node node, preprocessAux aux) {
|
||||
Metadata m = node.metadata;
|
||||
// We're gonna make lots of temporary variables,
|
||||
// so set up a unique flag for them
|
||||
std::string prefix = "_temp"+mkUniqueToken()+"_";
|
||||
// Check that the function name is a token
|
||||
if (node.args[0].args[1].type == ASTNODE)
|
||||
err("Function name must be static", m);
|
||||
|
||||
Node dotOwner = node.args[0].args[0];
|
||||
std::string dotMember = node.args[0].args[1].val;
|
||||
// kwargs = map of special arguments
|
||||
std::map<std::string, Node> kwargs;
|
||||
kwargs["value"] = token("0", m);
|
||||
kwargs["gas"] = subst(parseLLL("(- (gas) 25)"), msn(), prefix, m);
|
||||
// Search for as=? and call=code keywords, and isolate the actual
|
||||
// function arguments
|
||||
std::vector<Node> fnargs;
|
||||
std::string as = "";
|
||||
std::string op = "call";
|
||||
for (unsigned i = 1; i < node.args.size(); i++) {
|
||||
fnargs.push_back(node.args[i]);
|
||||
Node arg = fnargs.back();
|
||||
if (arg.val == "=" || arg.val == "set") {
|
||||
if (arg.args[0].val == "as")
|
||||
as = arg.args[1].val;
|
||||
if (arg.args[0].val == "call" && arg.args[1].val == "code")
|
||||
op = "callcode";
|
||||
if (arg.args[0].val == "gas")
|
||||
kwargs["gas"] = arg.args[1];
|
||||
if (arg.args[0].val == "value")
|
||||
kwargs["value"] = arg.args[1];
|
||||
if (arg.args[0].val == "outsz")
|
||||
kwargs["outsz"] = arg.args[1];
|
||||
}
|
||||
}
|
||||
if (dotOwner.val == "self") {
|
||||
if (as.size()) err("Cannot use \"as\" when calling self!", m);
|
||||
as = dotOwner.val;
|
||||
}
|
||||
// Determine the funId and sig assuming the "as" keyword was used
|
||||
int funId = 0;
|
||||
std::string sig;
|
||||
if (as.size() > 0 && aux.localExterns.count(as)) {
|
||||
if (!aux.localExterns[as].count(dotMember))
|
||||
err("Invalid call: "+printSimple(dotOwner)+"."+dotMember, m);
|
||||
funId = aux.localExterns[as][dotMember];
|
||||
sig = aux.localExternSigs[as][dotMember];
|
||||
}
|
||||
// Determine the funId and sig otherwise
|
||||
else if (!as.size()) {
|
||||
if (!aux.globalExterns.count(dotMember))
|
||||
err("Invalid call: "+printSimple(dotOwner)+"."+dotMember, m);
|
||||
std::string key = unsignedToDecimal(aux.globalExterns[dotMember]);
|
||||
funId = aux.globalExterns[dotMember];
|
||||
sig = aux.globalExternSigs[dotMember];
|
||||
}
|
||||
else err("Invalid call: "+printSimple(dotOwner)+"."+dotMember, m);
|
||||
// Pack arguments
|
||||
kwargs["data"] = packArguments(fnargs, sig, funId, m);
|
||||
kwargs["to"] = dotOwner;
|
||||
Node main;
|
||||
// Pack output
|
||||
if (!kwargs.count("outsz")) {
|
||||
main = parseLLL(
|
||||
"(with _data $data (seq "
|
||||
"(pop (~"+op+" $gas $to $value (access _data 0) (access _data 1) (ref $dataout) 32))"
|
||||
"(get $dataout)))");
|
||||
}
|
||||
else {
|
||||
main = parseLLL(
|
||||
"(with _data $data (with _outsz (mul 32 $outsz) (with _out (alloc _outsz) (seq "
|
||||
"(pop (~"+op+" $gas $to $value (access _data 0) (access _data 1) _out _outsz))"
|
||||
"(get _out)))))");
|
||||
}
|
||||
// Set up main call
|
||||
|
||||
Node o = subst(main, kwargs, prefix, m);
|
||||
return o;
|
||||
}
|
||||
|
||||
// Transform an access of the form self.bob, self.users[5], etc into
|
||||
// a storage access
|
||||
//
|
||||
// There exist two types of objects: finite objects, and infinite
|
||||
// objects. Finite objects are packed optimally tightly into storage
|
||||
// accesses; for example:
|
||||
//
|
||||
// data obj[100](a, b[2][4], c)
|
||||
//
|
||||
// obj[0].a -> 0
|
||||
// obj[0].b[0][0] -> 1
|
||||
// obj[0].b[1][3] -> 8
|
||||
// obj[45].c -> 459
|
||||
//
|
||||
// Infinite objects are accessed by sha3([v1, v2, v3 ... ]), where
|
||||
// the values are a list of array indices and keyword indices, for
|
||||
// example:
|
||||
// data obj[](a, b[2][4], c)
|
||||
// data obj2[](a, b[][], c)
|
||||
//
|
||||
// obj[0].a -> sha3([0, 0, 0])
|
||||
// obj[5].b[1][3] -> sha3([0, 5, 1, 1, 3])
|
||||
// obj[45].c -> sha3([0, 45, 2])
|
||||
// obj2[0].a -> sha3([1, 0, 0])
|
||||
// obj2[5].b[1][3] -> sha3([1, 5, 1, 1, 3])
|
||||
// obj2[45].c -> sha3([1, 45, 2])
|
||||
Node storageTransform(Node node, preprocessAux aux,
|
||||
bool mapstyle=false, bool ref=false) {
|
||||
Metadata m = node.metadata;
|
||||
// Get a list of all of the "access parameters" used in order
|
||||
// eg. self.users[5].cow[4][m[2]][woof] ->
|
||||
// [--self, --users, 5, --cow, 4, m[2], woof]
|
||||
std::vector<Node> hlist = listfyStorageAccess(node);
|
||||
// For infinite arrays, the terms array will just provide a list
|
||||
// of indices. For finite arrays, it's a list of index*coefficient
|
||||
std::vector<Node> terms;
|
||||
std::string offset = "0";
|
||||
std::string prefix = "";
|
||||
std::string varPrefix = "_temp"+mkUniqueToken()+"_";
|
||||
int c = 0;
|
||||
std::vector<std::string> coefficients;
|
||||
coefficients.push_back("");
|
||||
for (unsigned i = 1; i < hlist.size(); i++) {
|
||||
// We pre-add the -- flag to parameter-like terms. For example,
|
||||
// self.users[m] -> [--self, --users, m]
|
||||
// self.users.m -> [--self, --users, --m]
|
||||
if (hlist[i].val.substr(0, 2) == "--") {
|
||||
prefix += hlist[i].val.substr(2) + ".";
|
||||
std::string tempPrefix = prefix.substr(0, prefix.size()-1);
|
||||
if (!aux.storageVars.offsets.count(tempPrefix))
|
||||
return node;
|
||||
if (c < (signed)coefficients.size() - 1)
|
||||
err("Too few array index lookups", m);
|
||||
if (c > (signed)coefficients.size() - 1)
|
||||
err("Too many array index lookups", m);
|
||||
coefficients = aux.storageVars.coefficients[tempPrefix];
|
||||
// If the size of an object exceeds 2^176, we make it an infinite
|
||||
// array
|
||||
if (decimalGt(coefficients.back(), tt176) && !mapstyle)
|
||||
return storageTransform(node, aux, true, ref);
|
||||
offset = decimalAdd(offset, aux.storageVars.offsets[tempPrefix]);
|
||||
c = 0;
|
||||
if (mapstyle)
|
||||
terms.push_back(token(unsignedToDecimal(
|
||||
aux.storageVars.indices[tempPrefix])));
|
||||
}
|
||||
else if (mapstyle) {
|
||||
terms.push_back(hlist[i]);
|
||||
c += 1;
|
||||
}
|
||||
else {
|
||||
if (c > (signed)coefficients.size() - 2)
|
||||
err("Too many array index lookups", m);
|
||||
terms.push_back(
|
||||
astnode("mul",
|
||||
hlist[i],
|
||||
token(coefficients[coefficients.size() - 2 - c], m),
|
||||
m));
|
||||
|
||||
c += 1;
|
||||
}
|
||||
}
|
||||
if (aux.storageVars.nonfinal.count(prefix.substr(0, prefix.size()-1)))
|
||||
err("Storage variable access not deep enough", m);
|
||||
if (c < (signed)coefficients.size() - 1) {
|
||||
err("Too few array index lookups", m);
|
||||
}
|
||||
if (c > (signed)coefficients.size() - 1) {
|
||||
err("Too many array index lookups", m);
|
||||
}
|
||||
Node o;
|
||||
if (mapstyle) {
|
||||
std::string t = "_temp_"+mkUniqueToken();
|
||||
std::vector<Node> sub;
|
||||
for (unsigned i = 0; i < terms.size(); i++)
|
||||
sub.push_back(asn("mstore",
|
||||
asn("add",
|
||||
tkn(utd(i * 32), m),
|
||||
asn("get", tkn(t+"pos", m), m),
|
||||
m),
|
||||
terms[i],
|
||||
m));
|
||||
sub.push_back(tkn(t+"pos", m));
|
||||
Node main = asn("with",
|
||||
tkn(t+"pos", m),
|
||||
asn("alloc", tkn(utd(terms.size() * 32), m), m),
|
||||
asn("seq", sub, m),
|
||||
m);
|
||||
Node sz = token(utd(terms.size() * 32), m);
|
||||
o = astnode("~sha3",
|
||||
main,
|
||||
sz,
|
||||
m);
|
||||
}
|
||||
else {
|
||||
// We add up all the index*coefficients
|
||||
Node out = token(offset, node.metadata);
|
||||
for (unsigned i = 0; i < terms.size(); i++) {
|
||||
std::vector<Node> temp;
|
||||
temp.push_back(out);
|
||||
temp.push_back(terms[i]);
|
||||
out = astnode("add", temp, node.metadata);
|
||||
}
|
||||
o = out;
|
||||
}
|
||||
if (ref) return o;
|
||||
else return astnode("sload", o, node.metadata);
|
||||
}
|
||||
|
||||
|
||||
// Recursively applies rewrite rules
|
||||
std::pair<Node, bool> apply_rules_iter(preprocessResult pr) {
|
||||
bool changed = false;
|
||||
Node node = pr.first;
|
||||
// If the rewrite rules have not yet been parsed, parse them
|
||||
if (!nodeMacros.size()) {
|
||||
for (int i = 0; i < 9999; i++) {
|
||||
std::vector<Node> o;
|
||||
if (macros[i][0] == "---END---") break;
|
||||
nodeMacros.push_back(rewriteRule(
|
||||
parseLLL(macros[i][0]),
|
||||
parseLLL(macros[i][1])
|
||||
));
|
||||
}
|
||||
}
|
||||
// Assignment transformations
|
||||
for (int i = 0; i < 9999; i++) {
|
||||
if (setters[i][0] == "---END---") break;
|
||||
if (node.val == setters[i][0]) {
|
||||
node = astnode("=",
|
||||
node.args[0],
|
||||
astnode(setters[i][1],
|
||||
node.args[0],
|
||||
node.args[1],
|
||||
node.metadata),
|
||||
node.metadata);
|
||||
}
|
||||
}
|
||||
// Do nothing to macros
|
||||
if (node.val == "macro") {
|
||||
return std::pair<Node, bool>(node, changed);
|
||||
}
|
||||
// Ignore comments
|
||||
if (node.val == "comment") {
|
||||
return std::pair<Node, bool>(node, changed);
|
||||
}
|
||||
// Special storage transformation
|
||||
if (isNodeStorageVariable(node)) {
|
||||
node = storageTransform(node, pr.second);
|
||||
changed = true;
|
||||
}
|
||||
if (node.val == "ref" && isNodeStorageVariable(node.args[0])) {
|
||||
node = storageTransform(node.args[0], pr.second, false, true);
|
||||
changed = true;
|
||||
}
|
||||
if (node.val == "=" && isNodeStorageVariable(node.args[0])) {
|
||||
Node t = storageTransform(node.args[0], pr.second);
|
||||
if (t.val == "sload") {
|
||||
std::vector<Node> o;
|
||||
o.push_back(t.args[0]);
|
||||
o.push_back(node.args[1]);
|
||||
node = astnode("sstore", o, node.metadata);
|
||||
}
|
||||
changed = true;
|
||||
}
|
||||
// Main code
|
||||
unsigned pos = 0;
|
||||
std::string prefix = "_temp"+mkUniqueToken()+"_";
|
||||
while(1) {
|
||||
if (synonyms[pos][0] == "---END---") {
|
||||
break;
|
||||
}
|
||||
else if (node.type == ASTNODE && node.val == synonyms[pos][0]) {
|
||||
node.val = synonyms[pos][1];
|
||||
changed = true;
|
||||
}
|
||||
pos++;
|
||||
}
|
||||
for (pos = 0; pos < nodeMacros.size() + pr.second.customMacros.size(); pos++) {
|
||||
rewriteRule macro = pos < nodeMacros.size()
|
||||
? nodeMacros[pos]
|
||||
: pr.second.customMacros[pos - nodeMacros.size()];
|
||||
matchResult mr = match(macro.pattern, node);
|
||||
if (mr.success) {
|
||||
node = subst(macro.substitution, mr.map, prefix, node.metadata);
|
||||
std::pair<Node, bool> o =
|
||||
apply_rules_iter(preprocessResult(node, pr.second));
|
||||
o.second = true;
|
||||
return o;
|
||||
}
|
||||
}
|
||||
// Special transformations
|
||||
if (node.val == "outer") {
|
||||
node = apply_rules(preprocess(node.args[0]));
|
||||
changed = true;
|
||||
}
|
||||
if (node.val == "array_lit") {
|
||||
node = array_lit_transform(node);
|
||||
changed = true;
|
||||
}
|
||||
if (node.val == "fun" && node.args[0].val == ".") {
|
||||
node = dotTransform(node, pr.second);
|
||||
changed = true;
|
||||
}
|
||||
if (node.type == ASTNODE) {
|
||||
unsigned i = 0;
|
||||
if (node.val == "set" || node.val == "ref"
|
||||
|| node.val == "get" || node.val == "with") {
|
||||
if (node.args[0].val.size() > 0 && node.args[0].val[0] != '\''
|
||||
&& node.args[0].type == TOKEN && node.args[0].val[0] != '$') {
|
||||
node.args[0].val = "'" + node.args[0].val;
|
||||
changed = true;
|
||||
}
|
||||
i = 1;
|
||||
}
|
||||
else if (node.val == "arglen") {
|
||||
node.val = "get";
|
||||
node.args[0].val = "'_len_" + node.args[0].val;
|
||||
i = 1;
|
||||
changed = true;
|
||||
}
|
||||
for (; i < node.args.size(); i++) {
|
||||
std::pair<Node, bool> r =
|
||||
apply_rules_iter(preprocessResult(node.args[i], pr.second));
|
||||
node.args[i] = r.first;
|
||||
changed = changed || r.second;
|
||||
}
|
||||
}
|
||||
else if (node.type == TOKEN && !isNumberLike(node)) {
|
||||
if (node.val.size() >= 2
|
||||
&& node.val[0] == '"'
|
||||
&& node.val[node.val.size() - 1] == '"') {
|
||||
std::string bin = node.val.substr(1, node.val.size() - 2);
|
||||
unsigned sz = bin.size();
|
||||
std::vector<Node> o;
|
||||
for (unsigned i = 0; i < sz; i += 32) {
|
||||
std::string t = binToNumeric(bin.substr(i, 32));
|
||||
if ((sz - i) < 32 && (sz - i) > 0) {
|
||||
while ((sz - i) < 32) {
|
||||
t = decimalMul(t, "256");
|
||||
i--;
|
||||
}
|
||||
i = sz;
|
||||
}
|
||||
o.push_back(token(t, node.metadata));
|
||||
}
|
||||
node = astnode("array_lit", o, node.metadata);
|
||||
std::pair<Node, bool> r =
|
||||
apply_rules_iter(preprocessResult(node, pr.second));
|
||||
node = r.first;
|
||||
changed = true;
|
||||
}
|
||||
else if (node.val.size() && node.val[0] != '\'' && node.val[0] != '$') {
|
||||
node.val = "'" + node.val;
|
||||
std::vector<Node> args;
|
||||
args.push_back(node);
|
||||
std::string v = node.val.substr(1);
|
||||
node = astnode("get", args, node.metadata);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
return std::pair<Node, bool>(node, changed);
|
||||
}
|
||||
|
||||
Node apply_rules(preprocessResult pr) {
|
||||
for (unsigned i = 0; i < pr.second.customMacros.size(); i++) {
|
||||
pr.second.customMacros[i].pattern =
|
||||
apply_rules(preprocessResult(pr.second.customMacros[i].pattern, preprocessAux()));
|
||||
}
|
||||
while (1) {
|
||||
//std::cerr << printAST(pr.first) <<
|
||||
// " " << pr.second.customMacros.size() << "\n";
|
||||
std::pair<Node, bool> r = apply_rules_iter(pr);
|
||||
if (!r.second) {
|
||||
return r.first;
|
||||
}
|
||||
pr.first = r.first;
|
||||
}
|
||||
}
|
||||
|
||||
Node validate(Node inp) {
|
||||
Metadata m = inp.metadata;
|
||||
if (inp.type == ASTNODE) {
|
||||
int i = 0;
|
||||
while(validFunctions[i][0] != "---END---") {
|
||||
if (inp.val == validFunctions[i][0]) {
|
||||
std::string sz = unsignedToDecimal(inp.args.size());
|
||||
if (decimalGt(validFunctions[i][1], sz)) {
|
||||
err("Too few arguments for "+inp.val, inp.metadata);
|
||||
}
|
||||
if (decimalGt(sz, validFunctions[i][2])) {
|
||||
err("Too many arguments for "+inp.val, inp.metadata);
|
||||
}
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
for (unsigned i = 0; i < inp.args.size(); i++) validate(inp.args[i]);
|
||||
return inp;
|
||||
}
|
||||
|
||||
Node postValidate(Node inp) {
|
||||
// This allows people to use ~x as a way of having functions with the same
|
||||
// name and arity as macros; the idea is that ~x is a "final" form, and
|
||||
// should not be remacroed, but it is converted back at the end
|
||||
if (inp.val.size() > 0 && inp.val[0] == '~') {
|
||||
inp.val = inp.val.substr(1);
|
||||
}
|
||||
if (inp.type == ASTNODE) {
|
||||
if (inp.val == ".")
|
||||
err("Invalid object member (ie. a foo.bar not mapped to anything)",
|
||||
inp.metadata);
|
||||
else if (opcode(inp.val) >= 0) {
|
||||
if ((signed)inp.args.size() < opinputs(inp.val))
|
||||
err("Too few arguments for "+inp.val, inp.metadata);
|
||||
if ((signed)inp.args.size() > opinputs(inp.val))
|
||||
err("Too many arguments for "+inp.val, inp.metadata);
|
||||
}
|
||||
else if (isValidLLLFunc(inp.val, inp.args.size())) {
|
||||
// do nothing
|
||||
}
|
||||
else err ("Invalid argument count or LLL function: "+inp.val, inp.metadata);
|
||||
for (unsigned i = 0; i < inp.args.size(); i++) {
|
||||
inp.args[i] = postValidate(inp.args[i]);
|
||||
}
|
||||
}
|
||||
return inp;
|
||||
}
|
||||
|
||||
Node rewrite(Node inp) {
|
||||
return postValidate(optimize(apply_rules(preprocess(inp))));
|
||||
}
|
||||
|
||||
Node rewriteChunk(Node inp) {
|
||||
return postValidate(optimize(apply_rules(
|
||||
preprocessResult(
|
||||
validate(inp), preprocessAux()))));
|
||||
}
|
||||
|
||||
using namespace std;
|
16
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/rewriter.h
generated
vendored
Normal file
16
Godeps/_workspace/src/github.com/ethereum/serpent-go/serpent/rewriter.h
generated
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
#ifndef ETHSERP_REWRITER
|
||||
#define ETHSERP_REWRITER
|
||||
|
||||
#include <stdio.h>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include "util.h"
|
||||
|
||||
// Applies rewrite rules
|
||||
Node rewrite(Node inp);
|
||||
|
||||
// Applies rewrite rules adding without wrapper
|
||||
Node rewriteChunk(Node inp);
|
||||
|
||||
#endif
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user