|
1 |
| -import asyncio |
2 | 1 | import logging
|
3 |
| -import time |
4 | 2 | from typing import Sequence, cast
|
5 | 3 |
|
6 | 4 | from eth_typing import HexStr
|
|
18 | 16 | from src.common.harvest import get_harvest_params
|
19 | 17 | from src.common.metrics import metrics
|
20 | 18 | from src.common.tasks import BaseTask
|
21 |
| -from src.common.typings import HarvestParams |
22 |
| -from src.common.utils import get_current_timestamp |
| 19 | +from src.common.typings import HarvestParams, OraclesApproval |
| 20 | +from src.common.utils import RateLimiter, get_current_timestamp |
23 | 21 | from src.config.networks import GNOSIS_NETWORKS
|
24 | 22 | from src.config.settings import DEPOSIT_AMOUNT, settings
|
25 | 23 | from src.validators.database import NetworkValidatorCrud
|
@@ -85,7 +83,7 @@ async def process_block(self, interrupt_handler: InterruptHandler) -> None:
|
85 | 83 | )
|
86 | 84 |
|
87 | 85 |
|
88 |
| -# pylint: disable-next=too-many-locals,too-many-branches,too-many-return-statements,too-many-statements |
| 86 | +# pylint: disable-next=too-many-locals,too-many-return-statements |
89 | 87 | async def process_validators(
|
90 | 88 | keystore: BaseKeystore | None,
|
91 | 89 | deposit_data: DepositData | None,
|
@@ -173,74 +171,98 @@ async def process_validators(
|
173 | 171 |
|
174 | 172 | logger.info('Started registration of %d validator(s)', len(validators))
|
175 | 173 |
|
176 |
| - registry_root = None |
177 |
| - oracles_request = None |
| 174 | + oracles_request, oracles_approval = await poll_oracles_approval( |
| 175 | + keystore=keystore, |
| 176 | + validators=validators, |
| 177 | + multi_proof=multi_proof, |
| 178 | + validators_manager_signature=validators_manager_signature, |
| 179 | + ) |
| 180 | + validators_registry_root = Bytes32(Web3.to_bytes(hexstr=oracles_request.validators_root)) |
| 181 | + |
| 182 | + tx_hash = await register_validators( |
| 183 | + approval=oracles_approval, |
| 184 | + multi_proof=multi_proof, |
| 185 | + validators=validators, |
| 186 | + harvest_params=harvest_params, |
| 187 | + validators_registry_root=validators_registry_root, |
| 188 | + validators_manager_signature=validators_manager_signature, |
| 189 | + ) |
| 190 | + if tx_hash: |
| 191 | + pub_keys = ', '.join([val.public_key for val in validators]) |
| 192 | + logger.info('Successfully registered validator(s) with public key(s) %s', pub_keys) |
| 193 | + |
| 194 | + return tx_hash |
| 195 | + |
| 196 | + |
| 197 | +async def get_validators_count_from_vault_assets(harvest_params: HarvestParams | None) -> int: |
| 198 | + vault_balance = await get_withdrawable_assets(harvest_params) |
| 199 | + if settings.network in GNOSIS_NETWORKS: |
| 200 | + # apply GNO -> mGNO exchange rate |
| 201 | + vault_balance = convert_to_mgno(vault_balance) |
| 202 | + |
| 203 | + metrics.stakeable_assets.set(int(vault_balance)) |
| 204 | + |
| 205 | + # calculate number of validators that can be registered |
| 206 | + validators_count = vault_balance // DEPOSIT_AMOUNT |
| 207 | + return validators_count |
| 208 | + |
| 209 | + |
| 210 | +async def poll_oracles_approval( |
| 211 | + keystore: BaseKeystore | None, |
| 212 | + validators: Sequence[Validator], |
| 213 | + multi_proof: MultiProof[tuple[bytes, int]] | None = None, |
| 214 | + validators_manager_signature: HexStr | None = None, |
| 215 | +) -> tuple[ApprovalRequest, OraclesApproval]: |
| 216 | + """ |
| 217 | + Polls oracles for approval of validator registration |
| 218 | + """ |
| 219 | + previous_registry_root: Bytes32 | None = None |
| 220 | + oracles_request: ApprovalRequest | None = None |
178 | 221 | protocol_config = await get_protocol_config()
|
179 |
| - deadline = get_current_timestamp() + protocol_config.signature_validity_period |
| 222 | + deadline: int | None = None |
| 223 | + |
180 | 224 | approvals_min_interval = 1
|
| 225 | + rate_limiter = RateLimiter(approvals_min_interval) |
181 | 226 |
|
182 | 227 | while True:
|
183 |
| - approval_start_time = time.time() |
| 228 | + # Keep min interval between requests |
| 229 | + await rate_limiter.ensure_interval() |
| 230 | + |
| 231 | + # Create new approvals request or reuse the previous one |
| 232 | + current_registry_root = await validators_registry_contract.get_registry_root() |
| 233 | + logger.debug('Fetched validators registry root: %s', Web3.to_hex(current_registry_root)) |
184 | 234 |
|
185 |
| - latest_registry_root = await validators_registry_contract.get_registry_root() |
186 | 235 | current_timestamp = get_current_timestamp()
|
187 | 236 | if (
|
188 |
| - not registry_root |
189 |
| - or registry_root != latest_registry_root |
| 237 | + oracles_request is None |
| 238 | + or previous_registry_root is None |
| 239 | + or previous_registry_root != current_registry_root |
| 240 | + or deadline is None |
190 | 241 | or deadline <= current_timestamp
|
191 | 242 | ):
|
192 |
| - registry_root = latest_registry_root |
193 | 243 | deadline = current_timestamp + protocol_config.signature_validity_period
|
194 |
| - logger.debug('Fetched latest validators registry root: %s', Web3.to_hex(registry_root)) |
195 | 244 |
|
196 | 245 | oracles_request = await create_approval_request(
|
197 | 246 | protocol_config=protocol_config,
|
198 | 247 | keystore=keystore,
|
199 | 248 | validators=validators,
|
200 |
| - registry_root=registry_root, |
| 249 | + registry_root=current_registry_root, |
201 | 250 | multi_proof=multi_proof,
|
202 | 251 | deadline=deadline,
|
203 | 252 | validators_manager_signature=validators_manager_signature,
|
204 | 253 | )
|
| 254 | + previous_registry_root = current_registry_root |
205 | 255 |
|
| 256 | + # Send approval requests |
206 | 257 | try:
|
207 | 258 | oracles_approval = await send_approval_requests(protocol_config, oracles_request)
|
208 |
| - break |
| 259 | + return oracles_request, oracles_approval |
209 | 260 | except NotEnoughOracleApprovalsError as e:
|
210 | 261 | logger.error(
|
211 | 262 | 'Not enough oracle approvals for validator registration: %d. Threshold is %d.',
|
212 | 263 | e.num_votes,
|
213 | 264 | e.threshold,
|
214 | 265 | )
|
215 |
| - approvals_time = time.time() - approval_start_time |
216 |
| - await asyncio.sleep(approvals_min_interval - approvals_time) |
217 |
| - |
218 |
| - tx_hash = await register_validators( |
219 |
| - approval=oracles_approval, |
220 |
| - multi_proof=multi_proof, |
221 |
| - validators=validators, |
222 |
| - harvest_params=harvest_params, |
223 |
| - validators_registry_root=registry_root, |
224 |
| - validators_manager_signature=validators_manager_signature, |
225 |
| - ) |
226 |
| - if tx_hash: |
227 |
| - pub_keys = ', '.join([val.public_key for val in validators]) |
228 |
| - logger.info('Successfully registered validator(s) with public key(s) %s', pub_keys) |
229 |
| - |
230 |
| - return tx_hash |
231 |
| - |
232 |
| - |
233 |
| -async def get_validators_count_from_vault_assets(harvest_params: HarvestParams | None) -> int: |
234 |
| - vault_balance = await get_withdrawable_assets(harvest_params) |
235 |
| - if settings.network in GNOSIS_NETWORKS: |
236 |
| - # apply GNO -> mGNO exchange rate |
237 |
| - vault_balance = convert_to_mgno(vault_balance) |
238 |
| - |
239 |
| - metrics.stakeable_assets.set(int(vault_balance)) |
240 |
| - |
241 |
| - # calculate number of validators that can be registered |
242 |
| - validators_count = vault_balance // DEPOSIT_AMOUNT |
243 |
| - return validators_count |
244 | 266 |
|
245 | 267 |
|
246 | 268 | # pylint: disable-next=too-many-arguments,too-many-locals
|
|
0 commit comments