/
crowdfund.py
138 lines (100 loc) · 4.07 KB
/
crowdfund.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
import serpent
from pyethereum import transactions, blocks, processblock, utils
import ipdb
class NonceSingleton(object):
nonces = {}
@classmethod
def inc(cls, user):
nonce = -1
try:
nonce = cls.nonces[user]
except KeyError:
cls.nonces[user] = 0
nonce = cls.nonces[user]
cls.nonces[user] += 1
return nonce
class EthereumUser(object):
START_BALANCE = 10 ** 18
def __init__(self, name, genesis=None):
self.private_key = utils.sha3(name)
self.addr = utils.privtoaddr(self.private_key)
self.genesis = genesis or blocks.genesis({self.addr: self.START_BALANCE})
def apply_tx(self, tx):
return processblock.apply_tx(self.genesis, tx)
class Message(object):
DEFAULT_GASPRICE = 0
DEFAULT_STARTGAS = 10 ** 4
def __init__(self, to, donate_to, value=0):
self.to = to
self.value = value
self.donate_to = donate_to
self.data = serpent.encode_datalist([self._data_code(),
donate_to])
self.tx = lambda user: transactions.Transaction(NonceSingleton.inc(user),
self.DEFAULT_GASPRICE,
self.DEFAULT_STARTGAS,
to,
value,
self.data)
def _data_code(self):
raise NotImplementedError()
def execute(self, from_):
signed_tx = self.tx(from_).sign(from_.private_key)
return processblock.apply_transaction(from_.genesis, signed_tx)
class Campaign(Message):
def _data_code(self):
return 0
class Donation(Message):
def _data_code(self):
return 1
class Report(Message):
def _data_code(self):
return 2
class Crowdfund(object):
def __init__(self, root_user):
self.user = root_user
self.code = serpent.compile(open('./crowdfund.se').read())
tx = transactions.contract(NonceSingleton.inc(root_user),
Message.DEFAULT_GASPRICE,
Message.DEFAULT_STARTGAS,
0,
self.code).sign(root_user.private_key)
print "Made crowdfund tx: {}".format(tx)
self.contract = self._wrap_contract_response(
processblock.apply_transaction(root_user.genesis, tx))
def _wrap_contract_response(self, response):
ans, result = response
print "Successful? {}. Made: {}".format(ans, result)
return result
def campaign(self, donate_to, from_):
campaign = Campaign(self.contract, donate_to)
print "Made campaign: {}".format(campaign)
return self._wrap_contract_response(campaign.execute(from_))
def donation(self, donate_to, from_, value):
donation = Donation(self.contract, donate_to, value)
print "Made donation: {}".format(donation)
return self._wrap_contract_response(donation.execute(from_))
def report(self, donate_to, from_):
report = Report(self.contract, donate_to)
print "Made report: {}".format(report)
return self._wrap_contract_response(report.execute(from_))
def frombytes(b):
return 0 if len(b) == 0 else ord(b[-1]) + 256 * frombytes(b[:-1])
def print_report(report):
# ipdb.set_trace()
print "Decoded: {}".format(frombytes(report))
def main():
root = EthereumUser("helloworld")
alice = EthereumUser("alice", genesis=root.genesis)
bob = EthereumUser("bob", genesis=root.genesis)
fund = Crowdfund(root)
campaign = fund.campaign(100, alice)
print_report(fund.report(campaign, alice))
print_report(fund.report(campaign, bob))
fund.donation(campaign, root, 50)
print_report(fund.report(campaign, bob))
fund.donation(campaign, root, 100)
print_report(fund.report(campaign, bob))
print root.genesis.to_dict()
if __name__ == '__main__':
main()