-
Notifications
You must be signed in to change notification settings - Fork 0
/
participant.py
executable file
·147 lines (118 loc) · 6.32 KB
/
participant.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
from merkle_tree import merkle_root, merkle_tree, merkle_chain
from player import PaymentChannelPlayer, state_to_bytes_unpack
from ethereum import utils
from crypto import sign, verify_signature, hash_array
class PaymentSubnetParticipant:
def __init__(self, roles = list()):
self.player_roles = roles
self.contract_player = dict([(player.contract.address, player) for player in roles])
self.private_key = roles[0].sk
self.public_address = utils.privtoaddr(self.private_key)
self.wants_rebalance = True # TODO This should be set as a preference at some point.
self.frozen_channels = set()
self.rebalance_transactions = None
self.rebalance_participants = None
self.rebalance_signatures = None
def add_payment_channel_role(self, role, PaymentChannelPlayer):
self.player_roles.append(role)
def send_rebalance_request(self, leader):
self.wants_rebalance = True
return {'leader': leader, 'participant': self}
def receive_initiation_request(self, req):
assert(req['participant'] == self)
def send_participation_confirmation(self, leader):
resp = {'leader': leader, 'participant': self, 'contracts': []}
if self.wants_rebalance:
resp['contracts'] = [player.contract.address for player in self.player_roles]
return resp
def receive_channel_freeze_request(self, req):
# Freeze each channel such that no further off-state updates take place
assert(req['participant'] == self)
for contract in req['contracts']:
self.frozen_channels.add(contract)
pass
def send_frozen_channel_info(self, leader):
resp = {'leader': leader, 'participant': self, 'balances': {}}
for player in self.player_roles:
contract = player.contract.address
if contract not in self.frozen_channels:
continue
resp['balances'][contract] = (player.addrs,
player.contract.deposits(0),
player.contract.deposits(1),
player.lastCommit[1:],
player.lastRound)
return resp
def receive_rebalance_transactions(self, req):
assert(req['participant'] == self)
self.rebalance_transactions = req['transactions']
channel_contracts = [player.contract.address for player in self.player_roles]
for contract, round, creditsL, creditsR, withdrawnL, withdrawnR in self.rebalance_transactions:
if contract not in channel_contracts:
continue
# TODO Assert transaction validity
player = self.contract_player[contract]
player.lastProposed = (creditsL, creditsR, withdrawnL, withdrawnR)
self.transactions_merkle_tree = merkle_tree([state_to_bytes_unpack(trans) for trans in self.rebalance_transactions],
utils.sha3)
self.transactions_merkle_root = self.transactions_merkle_tree.build()
self.rebalance_participants = sorted(list(set(req['participants'])))
self.participants_hash = hash_array(self.rebalance_participants)
self.instance_hash = utils.sha3(self.participants_hash + self.transactions_merkle_root)
def send_signed_rebalance_set(self, leader):
return {'leader': leader, 'participant': self, 'signature': sign(self.instance_hash, self.private_key)}
def receive_set_signatures(self, req):
assert(req['participant'] == self)
signatures = req['signatures']
assert(set(self.rebalance_participants).issubset(signatures.keys()))
for public_address in signatures:
assert(verify_signature(public_address, self.instance_hash, signatures[public_address]))
self.rebalance_signatures = req['signatures']
for transaction in self.rebalance_transactions:
if transaction[0] not in self.contract_player:
continue
player = self.contract_player[transaction[0]]
player.lastCommit = [], transaction[2:]
player.lastRound += 1
def update_after_rebalance(self, contract):
player = self.contract_player[contract]
V, R, S = [], [], []
for public_address in self.rebalance_participants:
v, r, s = self.rebalance_signatures[public_address]
V.append(v)
R.append(r.to_bytes(32, byteorder='big'))
S.append(s.to_bytes(32, byteorder='big'))
assert(verify_signature(public_address, self.instance_hash, (v,r,s)))
idx = next(i for i, v in enumerate(self.rebalance_transactions) if v[0] == contract)
chain, sides = merkle_chain(
self.transactions_merkle_tree,
idx)
player.update_after_rebalance(V, R, S, self.rebalance_participants, chain, sides)
def issue_challenge(self, contract, wei):
player = self.contract_player[contract]
idx = next(i for i, v in enumerate(self.rebalance_transactions) if v[0] == contract)
chain, _ = merkle_chain(
self.transactions_merkle_tree,
idx)
player.issue_challenge(self.rebalance_participants, chain[-1], wei)
def respond_to_challenge(self, contract):
player = self.contract_player[contract]
V, R, S = [], [], []
for public_address in self.rebalance_participants:
v, r, s = self.rebalance_signatures[public_address]
V.append(v)
R.append(r.to_bytes(32, byteorder='big'))
S.append(s.to_bytes(32, byteorder='big'))
assert(verify_signature(public_address, self.instance_hash, (v,r,s)))
idx = next(i for i, v in enumerate(self.rebalance_transactions) if v[0] == contract)
chain, sides = merkle_chain(
self.transactions_merkle_tree,
idx)
player.respond_to_challenge(V, R, S, self.rebalance_participants, chain[-1])
def update_after_rebalance_verified(self, contract):
player = self.contract_player[contract]
idx = next(i for i, v in enumerate(self.rebalance_transactions) if v[0] == contract)
chain, sides = merkle_chain(
self.transactions_merkle_tree,
idx)
player.update_after_rebalance_verified(self.rebalance_participants, chain, sides)