6
6
7
7
import aiohttp
8
8
import click
9
- import milagro_bls_binding as bls
10
9
from aiohttp import ClientTimeout
11
10
from eth_typing import BLSPrivateKey , HexAddress
12
- from web3 import Web3
13
11
14
12
from src .common .credentials import Credential
15
- from src .common .execution import get_oracles
16
13
from src .common .logging import setup_logging
17
14
from src .common .password import get_or_create_password_file
18
15
from src .common .utils import log_verbose
19
16
from src .common .validators import validate_eth_address
20
17
from src .common .vault_config import VaultConfig
21
18
from src .config .settings import REMOTE_SIGNER_TIMEOUT , settings
22
19
from src .validators .keystores .local import LocalKeystore
23
- from src .validators .keystores .remote import RemoteSignerKeystore
24
- from src .validators .signing .key_shares import private_key_to_private_key_shares
25
20
26
21
27
22
@click .option (
39
34
required = True ,
40
35
help = 'The base URL of the remote signer, e.g. http://signer:9000' ,
41
36
)
42
- @click .option (
43
- '--remove-existing-keys' ,
44
- type = bool ,
45
- is_flag = True ,
46
- help = 'Whether to remove existing keys from the remote signer. Useful'
47
- ' when the oracle set changes and the previously generated key shares'
48
- ' are no longer going to be used.' ,
49
- )
50
37
@click .option (
51
38
'--data-dir' ,
52
39
default = str (Path .home () / '.stakewise' ),
80
67
def remote_signer_setup (
81
68
vault : HexAddress ,
82
69
remote_signer_url : str ,
83
- remove_existing_keys : bool ,
84
70
data_dir : str ,
85
71
keystores_dir : str | None ,
86
72
execution_endpoints : str ,
@@ -105,63 +91,39 @@ def remote_signer_setup(
105
91
asyncio .get_running_loop ()
106
92
# we need to create a separate thread so we can block before returning
107
93
with ThreadPoolExecutor (1 ) as pool :
108
- pool .submit (
109
- lambda : asyncio .run (main (remove_existing_keys = remove_existing_keys ))
110
- ).result ()
94
+ pool .submit (lambda : asyncio .run (main ())).result ()
111
95
except RuntimeError as e :
112
96
if 'no running event loop' == e .args [0 ]:
113
97
# no event loop running
114
- asyncio .run (main (remove_existing_keys = remove_existing_keys ))
98
+ asyncio .run (main ())
115
99
else :
116
100
raise e
117
101
except Exception as e :
118
102
log_verbose (e )
119
103
120
104
121
- # pylint: disable-next=too-many-locals
122
- async def main (remove_existing_keys : bool ) -> None :
105
+ async def main () -> None :
123
106
setup_logging ()
124
107
keystores = await LocalKeystore .load ()
125
108
if len (keystores ) == 0 :
126
109
raise click .ClickException ('Keystores not found.' )
127
110
128
111
# Check if remote signer's keymanager API is reachable before taking further steps
129
- async with aiohttp .ClientSession (
130
- timeout = ClientTimeout (connect = REMOTE_SIGNER_TIMEOUT )
131
- ) as session :
112
+ async with aiohttp .ClientSession (timeout = ClientTimeout (REMOTE_SIGNER_TIMEOUT )) as session :
132
113
resp = await session .get (f'{ settings .remote_signer_url } /eth/v1/keystores' )
133
114
if resp .status != 200 :
134
115
raise RuntimeError (f'Failed to connect to remote signer, returned { await resp .text ()} ' )
135
116
136
- oracles = await get_oracles ()
137
-
138
- try :
139
- remote_signer_keystore = RemoteSignerKeystore .load_from_file (
140
- settings .remote_signer_config_file
141
- )
142
- except FileNotFoundError :
143
- remote_signer_keystore = RemoteSignerKeystore ({})
144
-
145
117
credentials = []
146
118
for pubkey , private_key in keystores .keys .items (): # pylint: disable=no-member
147
- private_key_shares = private_key_to_private_key_shares (
148
- private_key = private_key ,
149
- threshold = oracles .exit_signature_recover_threshold ,
150
- total = len (oracles .public_keys ),
151
- )
152
-
153
- for idx , private_key_share in enumerate (private_key_shares ):
154
- credentials .append (
155
- Credential (
156
- private_key = BLSPrivateKey (int .from_bytes (private_key_share , 'big' )),
157
- path = f'share_{ pubkey } _{ idx } ' ,
158
- network = settings .network ,
159
- vault = settings .vault ,
160
- )
119
+ credentials .append (
120
+ Credential (
121
+ private_key = BLSPrivateKey (int .from_bytes (private_key , 'big' )),
122
+ path = f'{ pubkey } ' , # todo
123
+ network = settings .network ,
124
+ vault = settings .vault ,
161
125
)
162
- remote_signer_keystore .pubkeys_to_shares [pubkey ] = [
163
- Web3 .to_hex (bls .SkToPk (priv_key )) for priv_key in private_key_shares
164
- ]
126
+ )
165
127
166
128
click .echo (
167
129
f'Successfully generated { len (credentials )} key shares'
@@ -170,16 +132,14 @@ async def main(remove_existing_keys: bool) -> None:
170
132
171
133
# Import as keystores to remote signer
172
134
password = get_or_create_password_file (settings .keystores_password_file )
173
- key_share_keystores = []
135
+ encrypted_keystores = []
174
136
for credential in credentials :
175
- key_share_keystores .append (deepcopy (credential .encrypt_signing_keystore (password = password )))
137
+ encrypted_keystores .append (deepcopy (credential .encrypt_signing_keystore (password = password )))
176
138
177
- async with aiohttp .ClientSession (
178
- timeout = ClientTimeout (connect = REMOTE_SIGNER_TIMEOUT )
179
- ) as session :
139
+ async with aiohttp .ClientSession (timeout = ClientTimeout (REMOTE_SIGNER_TIMEOUT )) as session :
180
140
data = {
181
- 'keystores' : [ksk .as_json () for ksk in key_share_keystores ],
182
- 'passwords' : [password for _ in key_share_keystores ],
141
+ 'keystores' : [ks .as_json () for ks in encrypted_keystores ],
142
+ 'passwords' : [password for _ in encrypted_keystores ],
183
143
}
184
144
resp = await session .post (f'{ settings .remote_signer_url } /eth/v1/keystores' , json = data )
185
145
if resp .status != 200 :
@@ -189,7 +149,7 @@ async def main(remove_existing_keys: bool) -> None:
189
149
)
190
150
191
151
click .echo (
192
- f'Successfully imported { len (key_share_keystores )} key shares into remote signer.' ,
152
+ f'Successfully imported { len (encrypted_keystores )} keys into remote signer.' ,
193
153
)
194
154
195
155
# Remove local keystores - keys are loaded in remote signer and are not
@@ -199,40 +159,6 @@ async def main(remove_existing_keys: bool) -> None:
199
159
200
160
click .echo ('Removed keystores from local filesystem.' )
201
161
202
- # Remove outdated keystores from remote signer
203
- if remove_existing_keys :
204
- active_pubkey_shares = {
205
- pk for pk_list in remote_signer_keystore .pubkeys_to_shares .values () for pk in pk_list
206
- }
207
-
208
- async with aiohttp .ClientSession (
209
- timeout = ClientTimeout (connect = REMOTE_SIGNER_TIMEOUT )
210
- ) as session :
211
- resp = await session .get (f'{ settings .remote_signer_url } /eth/v1/keystores' )
212
- pubkeys_data = (await resp .json ())['data' ]
213
- pubkeys_remote_signer = {
214
- pubkey_dict .get ('validating_pubkey' ) for pubkey_dict in pubkeys_data
215
- }
216
-
217
- # Only remove pubkeys from signer that are no longer needed
218
- inactive_pubkeys = pubkeys_remote_signer - active_pubkey_shares
219
-
220
- resp = await session .delete (
221
- f'{ settings .remote_signer_url } /eth/v1/keystores' ,
222
- json = {'pubkeys' : list (inactive_pubkeys )},
223
- )
224
- if resp .status != 200 :
225
- raise RuntimeError (
226
- f'Error occurred while deleting existing keys from remote signer'
227
- f' - status code { resp .status } , body: { await resp .text ()} '
228
- )
229
-
230
- click .echo (
231
- f'Removed { len (inactive_pubkeys )} keys from remote signer' ,
232
- )
233
-
234
- remote_signer_keystore .save (settings .remote_signer_config_file )
235
-
236
162
click .echo (
237
163
f'Done.'
238
164
f' Successfully configured operator to use remote signer'
0 commit comments