-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathcases.py
239 lines (199 loc) · 7.51 KB
/
cases.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
# Copyright (C) 10-11-2014 Jasper den Ouden.
#
# This is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
import pyethereum
from random import randrange
t = pyethereum.tester
OnePerID = 0x00
OnePerIDSet = 0x20
TopicI = 0x40
Puppeteer = 0x60
# 224 == 32*7, it is a lot, in the future likely 32, and magnet/swarm/contract links.
TopicSz = 224
TopicStartI = 0x80
# TODO.. all these convenience definitions are not well named and
# not well located.
def i(str):
s,f = 0, 1
for i in range(len(str)):
s += f*ord(str[len(str)-i-1])
f *= 256
for i in range(32 - len(str)): # Right pad instead of left.
s *= 256;
return s
def stri(i):
s=""
while i > 0:
s += chr(i%256)
i /=256
return "".join(reversed(s))
s = t.state()
c = None #s.contract('bitvote.se', t.k0)
c2 = None #s.contract('any_per_id.se', t.k0) # TODO test of that alone.
echo = None
def ae(a, b, cond=None, what="N/A"):
if (a !=b if cond == None else not cond):
print(a,b)
print('-', map(stri,a), "vs", map(stri,b), ":", what)
print(map(hex,a), "vs", map(hex,b), ":", what)
assert False
def store(index, contract=None):
global c
if contract == None: # How the optional arguments worked bit me.
contract = c # (they work badly in Python)
result = int(s.block.get_storage_data(contract, index))
if contract == c:
ae(s.send(t.k9, contract, 0, [i("account"), index]), [result],
None, what="store mismatch")
return result
def i_store(index, contract=None):
return int(store(index, contract))
def str_store(index, contract=None):
return stri(store(index, contract))
def addr_store(index, contract=None):
return hex(store(index, contract))[2:-1]
LARGE = 1152921504606846976
HALFWAY = 340282366920938463463374607431768211456
def non_exist_vote_count(j=None):
if not j:
j = (i_store(TopicI) - TopicStartI)/TopicSz
ae(s.send(t.k9, c, 0, [i("vote_count"), j]),
[i("topic doesnt exist yet.")],
"getting vote count nonexistance failed.")
def non_exist_vote(j=None):
if not j:
j = (i_store(TopicI) - TopicStartI)/TopicSz
ae(s.send(t.k9, c, 0, [i("vote"), j, randrange(0,10)]),
[i("topic doesnt exist yet(vote)")])
def expect_topic_count(n, zeros=True):
ae([i_store(TopicI)], [TopicStartI + TopicSz*n])
ae(s.send(t.k9, c, 0, [i("topic_count")]), [n])
non_exist_vote(randrange(n, n+3))
non_exist_vote_count(randrange(n, n+3))
if n > 0:
ae(s.send(t.k9, c, 0, [i("vote_count"), 0]), [0],
what="Not zero votes on it/wrong message.")
def too_long_topic():
ae(s.send(t.k9, c, 0, map(lambda i : i, range(224 + randrange(1,10)))),
[i("too long topic string")])
def check(): # TODO this would be better with 'stateless call'
s.mine()
# Smaller than large.
ae(i_store(TopicI), LARGE, i_store(TopicI) < LARGE, "topic index unrealistic")
# Thing that can happen in any case.
non_exist_vote(store(TopicI))
non_exist_vote_count(store(TopicI))
too_long_topic()
ae(s.send(t.k9, c, 0, [1, 2]), [i("anyone bad 1")])
ae(s.send(t.k9, c, 0, [1, 2, 3]), [i("anyone bad 2")])
ae(s.send(t.k9, c, 0, []), [i("anyone bad 3")])
ae(s.send(t.k9, c, 0, [4]), [i("anyone bad 4")])
# Ways you cannot set the one per ID.
ae(s.send(t.k0, c, 0, []), [i("OnePerIDSet bad")])
ae(s.send(t.k0, c, 0, [randrange(LARGE)]), [i("OnePerIDSet bad")])
if i_store(Puppeteer) != 0:
assert i_store(Puppeteer) == int(t.a4, 16)
r = randrange(2**64) # Talk to echo-1.se via puppeteer, see if it works.
ae(s.send(t.k4, c, 0, [echo, r]), [r])
def no_topics_yet():
non_exist_vote_count(0)
non_exist_vote(0)
expect_topic_count(0)
run_i = 0
def scenario_start():
s.mine() # Otherwise a series of tests could hit the block gas limit.
global c, c2, run_i, echo
c = s.contract('bitvote.se', t.k0)
c2 = s.contract('any_per_id.se', t.k0)
echo = s.contract('other/echo-1.se', t.k0)
run_i = run_i + 1
print("Run " + str(run_i) + " bitvote: " + c + " anyperid: " + c2)
check()
ae(i_store(OnePerID), 0)
assert addr_store(OnePerIDSet) == t.a0
ae(i_store(TopicI), TopicStartI)
no_topics_yet()
def initialize(have_topics=False):
# TODO check that it responds with "not initialized" when registering.
assert addr_store(0, c2) == t.a0
# Gives himself full power, the bastard.
ae(s.send(t.k0, c, 0, [c2, t.a0, t.a4]), [i("changed!")])
ae([store(OnePerID)], [int(c2,16)])
assert addr_store(OnePerIDSet) == t.a0
check()
for x in [[1,2], []]:
ae(s.send(t.k0, c2, 0, x), [i("initializer bad")])
ae(s.send(t.k0, c2, 0, [c]), [i("initialized")])
assert i_store(0, c2) == 0
if not have_topics:
no_topics_yet()
def add_topic(string=None):
if string == None:
string = ""
for j in range(randrange(20)):
string += ["herp", "derp", "blurb", "bla"][randrange(4)]
args = []
while string != "":
args.append(i(string[:32]))
string = string[32:]
while len(args) <= 3:
args.append(i(""))
j = i_store(TopicI)
if len(args) > 6:
ae(s.send(t.k2, c, 0, args), [i("too long topic string")])
assert i_store(TopicI) == j # Cant have added it anyway.
elif len(args) > 3:
ae(s.send(t.k2, c, 0, args), [i("topic set")])
assert i_store(TopicI) == j + TopicSz # Must have indeed moved forward.
assert i_store(j) == 0 # Must start with zero votes.
for k in range(len(args)): # Check message.
assert i_store(j + 0x20 + k*0x20) == args[k]
else:
print("na", len(args))
check()
def scenario_create_topics(init_first=False):
scenario_start()
init_first = randrange(2)==1 if init_first == None else init_first
if init_first:
initialize()
n = randrange(1,5)
for j in range(n):
expect_topic_count(j)
add_topic()
if not init_first:
initialize(True)
expect_topic_count(n)
return n
def register(k):
ae(s.send(t.keys[k], c2, 0, []), [i("registered")])
# Check that timestamp set right.
tm = s.block.timestamp
assert tm + HALFWAY*tm == store(int(t.accounts[k],16))
# TODO check timestamp on the account.
check()
return tm
def scenario_vote():
n = scenario_create_topics()
tm = register(2)
j = randrange(n)
ae(s.send(t.k2, c, 0, [i("vote"), j, 60]), [i("cannot spend more than you have")])
assert tm + HALFWAY*tm == store(int(t.a2,16))
s.mine(100) # Get some time. TODO test not independent on block time right now.
use_tm = randrange(60,600)
ae(s.send(t.k2, c, 0, [i("vote"), j, use_tm]), [i("voted")])
#print(tm, tm + use_tm, store(int(t.a2,16))/HALFWAY, store(int(t.a2,16))%HALFWAY)
# Check that vote counter indeed advanced.
assert tm + HALFWAY*(tm + use_tm) == store(int(t.a2,16))
# Check that topic received said votes.
ae(s.send(t.k9, c, 0, [i("vote_count"), j]), [use_tm])
tm2 = register(3) # Register and check again.
use_tm2 = randrange(60,600)
s.mine(100)
ae(s.send(t.k3, c, 0, [i("vote"), j, use_tm2]), [i("voted")])
assert tm2 + HALFWAY*(tm2 + use_tm2) == store(int(t.a3,16))
ae(s.send(t.k9, c, 0, [i("vote_count"), j]), [use_tm + use_tm2])
for k in range(8):
scenario_vote()