Skip to content

Commit

Permalink
Merge pull request #185 from lidofinance/vote_2023_09_12
Browse files Browse the repository at this point in the history
Vote 2023-09-12
  • Loading branch information
BATMAH69 authored Sep 15, 2023
2 parents df15c6a + 772ff89 commit 5bedb87
Show file tree
Hide file tree
Showing 8 changed files with 392 additions and 105 deletions.
90 changes: 90 additions & 0 deletions archive/scripts/vote_2023_09_12.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
"""
Voting 164 12/09/2023
Vote REJECTED
"""

import time

from typing import Dict

from brownie.network.transaction import TransactionReceipt
from brownie import web3, interface # type: ignore
from utils.agent import agent_forward

from utils.voting import bake_vote_items, confirm_vote_script, create_vote

from utils.config import (
get_deployer_account,
get_is_live,
get_priority_fee,
contracts,
)

from utils.ipfs import upload_vote_ipfs_description, calculate_vote_ipfs_description

description = """
The proposal is to support **Jump Crypto voluntarily exits from the validator set** by setting `targetValidatorsCount` to 0.
Algorithm would prioritise exiting Jump Crypto validators in order to fulfil users' withdrawals requests.
Jump Crypto request on [forum](https://research.lido.fi/t/lido-dao-proposal-to-set-targetvalidatorscount-for-jump-crypto-operator-to-0-to-wind-down-the-jump-crypto-legacy-set/5259).
"""


def start_vote(tx_params: Dict[str, str], silent: bool) -> bool | list[int | TransactionReceipt | None]:
"""Prepare and run voting."""

# contracts.node_operators_registry.getNodeOperator(1, True)
JUMP_CRYPTO_ID = 1
# web3.keccak(text="STAKING_MODULE_MANAGE_ROLE")
STAKING_MODULE_MANAGE_ROLE = "0x3105bcbf19d4417b73ae0e58d508a65ecf75665e46c2622d8521732de6080c48"

call_script_items = [
# 1. Support **Jump Crypto voluntarily exits from the validator set** by setting `targetValidatorsCount` to 0.
## 1) Grant STAKING_MODULE_MANAGE_ROLE to Lido Agent
agent_forward(
[
(
contracts.staking_router.address,
contracts.staking_router.grantRole.encode_input(
STAKING_MODULE_MANAGE_ROLE, contracts.agent.address
),
)
]
),
## 2) Set Jump Crypto targetValidatorsCount to 0
agent_forward(
[
(
contracts.staking_router.address,
contracts.staking_router.updateTargetValidatorsLimits.encode_input(1, JUMP_CRYPTO_ID, True, 0),
)
]
),
]

vote_desc_items = [
f"1) Grant STAKING_MODULE_MANAGE_ROLE to Lido Agent",
f"2) Set Jump Crypto targetValidatorsLimits to 0",
]

vote_items = bake_vote_items(vote_desc_items, call_script_items)

if silent:
desc_ipfs = calculate_vote_ipfs_description(description)
else:
desc_ipfs = upload_vote_ipfs_description(description)

return confirm_vote_script(vote_items, silent, desc_ipfs) and list(
create_vote(vote_items, tx_params, desc_ipfs=desc_ipfs)
)


def main():
tx_params = {"from": get_deployer_account()}
if get_is_live():
tx_params["priority_fee"] = get_priority_fee()

vote_id, _ = start_vote(tx_params=tx_params, silent=False)

vote_id >= 0 and print(f"Vote created: {vote_id}.")

time.sleep(5) # hack for waiting thread #2.
93 changes: 93 additions & 0 deletions archive/tests/test_2023_09_12.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
"""
Tests for voting 12/09/2023
"""
from archive.scripts.vote_2023_09_12 import start_vote

from utils.config import (
network_name,
contracts,
LDO_HOLDER_ADDRESS_FOR_TESTS,
)
from utils.voting import find_metadata_by_vote_id
from utils.ipfs import get_lido_vote_cid_from_str
from utils.test.tx_tracing_helpers import *

from utils.test.event_validators.node_operators_registry import (
validate_target_validators_count_changed_event,
TargetValidatorsCountChanged,
)
from utils.test.event_validators.permission import validate_grant_role_event


def test_vote(
helpers,
bypass_events_decoding,
vote_ids_from_env,
accounts,
):
# params
agent = contracts.agent
nor = contracts.node_operators_registry
staking_router = contracts.staking_router
target_NO_id = 1
target_validators_count_change_request = TargetValidatorsCountChanged(
nodeOperatorId=target_NO_id, targetValidatorsCount=0
)

# web3.keccak(text="STAKING_MODULE_MANAGE_ROLE")
STAKING_MODULE_MANAGE_ROLE = "0x3105bcbf19d4417b73ae0e58d508a65ecf75665e46c2622d8521732de6080c48"

# 1)
assert staking_router.hasRole(STAKING_MODULE_MANAGE_ROLE, agent.address) == False

# 2)
NO_summary_before = nor.getNodeOperatorSummary(target_NO_id)
assert NO_summary_before[0] == False
assert NO_summary_before[1] == 0
assert NO_summary_before[2] == 0
assert NO_summary_before[3] == 0
assert NO_summary_before[4] == 0
assert NO_summary_before[5] == 0
assert NO_summary_before[6] == 1000
assert NO_summary_before[7] == 0

# START VOTE
if len(vote_ids_from_env) > 0:
(vote_id,) = vote_ids_from_env
else:
tx_params = {"from": LDO_HOLDER_ADDRESS_FOR_TESTS}
vote_id, _ = start_vote(tx_params, silent=True)

vote_tx = helpers.execute_vote(accounts, vote_id, contracts.voting)

print(f"voteId = {vote_id}, gasUsed = {vote_tx.gas_used}")

# validate vote events
assert count_vote_items_by_events(vote_tx, contracts.voting) == 2, "Incorrect voting items count"

metadata = find_metadata_by_vote_id(vote_id)

assert get_lido_vote_cid_from_str(metadata) == "bafkreiapvuobyrudww3oqhfopbs2fdmtebi6jnvpeb3plxkajnhafw25im"
# 1)
assert staking_router.hasRole(STAKING_MODULE_MANAGE_ROLE, agent.address) == True

# 2)
NO_summary_after = nor.getNodeOperatorSummary(target_NO_id)
assert NO_summary_after[0] == True
assert NO_summary_after[1] == 0
assert NO_summary_after[2] == 0
assert NO_summary_after[3] == 0
assert NO_summary_after[4] == 0
assert NO_summary_after[5] == 0
assert NO_summary_after[6] == 1000
assert NO_summary_after[7] == 0

if bypass_events_decoding or network_name() in ("goerli", "goerli-fork"):
return

evs = group_voting_events(vote_tx)

validate_grant_role_event(evs[0], STAKING_MODULE_MANAGE_ROLE, agent.address, agent.address)

validate_target_validators_count_changed_event(evs[1], target_validators_count_change_request)
26 changes: 25 additions & 1 deletion tests/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ expected changes.

Snapshot tests work as follows:

1) Go over some protocol use scenario (e. g. stake by use + oracle report)
1) Go over some protocol use scenario (e.g. stake by use + oracle report)
2) Store the snapshot along the steps
3) Revert the chain changes
4) Execute the vote
Expand All @@ -61,3 +61,27 @@ the voting without modification of the common test files
## Internal tests

Internal tests are used to test the tooling itself.

## For test debugging
How to run one test?
You need to add file name:
```shell
poetry run brownie test tests/<dir>/test_<name>.py -s
```

How not to raise the network every time you launch test?
You could to run network in separate terminal window, tests will connect to it:
```shell
poetry run brownie console --network mainnet-fork
```

How to decode unreadable error messages (like 0xb...)?
1) You need to clone `lido-cli` repo.
```shell
git clone https://github.com/lidofinance/lido-cli
```
2) install following docs - https://github.com/lidofinance/lido-cli
3) run
```shell
./run.sh tx parse-error <error-messages>
```
46 changes: 32 additions & 14 deletions tests/acceptance/test_node_operators_registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,14 +106,21 @@ def test_nor_state(contract):
assert node_operator["totalVettedValidators"] > 0

assert node_operator["totalVettedValidators"] <= node_operator["totalAddedValidators"]
if id == 22:
assert node_operator["totalExitedValidators"] == 11
# counts could inc but not dec
if id == 2:
assert node_operator["totalExitedValidators"] == 252
elif id == 4:
assert node_operator["totalExitedValidators"] == 174
elif id == 5:
assert node_operator["totalExitedValidators"] == 36
elif id == 12:
assert node_operator["totalExitedValidators"] >= 134
assert node_operator["totalExitedValidators"] == 2300
elif id == 21:
assert node_operator["totalExitedValidators"] >= 125
assert node_operator["totalExitedValidators"] == 125
elif id == 22:
assert node_operator["totalExitedValidators"] == 11
else:
assert node_operator["totalExitedValidators"] == 0
assert node_operator["totalExitedValidators"] == 0, f"totalExitedValidators is positive for node {id}"

assert node_operator["totalAddedValidators"] > 0

Expand All @@ -122,23 +129,34 @@ def test_nor_state(contract):
assert node_operator["totalDepositedValidators"] <= node_operator["totalAddedValidators"]

node_operator_summary = contract.getNodeOperatorSummary(id)
if id != 12:
assert node_operator_summary["isTargetLimitActive"] is False
exited_node_operators = [12] # vote 23-05-23
if id in exited_node_operators:
assert (
node_operator_summary["isTargetLimitActive"] is True
), f"isTargetLimitActive is inactive for node {id}"
else:
assert node_operator_summary["isTargetLimitActive"] is True
assert node_operator_summary["isTargetLimitActive"] is False, f"isTargetLimitActive is active for node {id}"
assert node_operator_summary["targetValidatorsCount"] == 0
assert node_operator_summary["stuckValidatorsCount"] == 0
assert node_operator_summary["refundedValidatorsCount"] == 0
assert node_operator_summary["stuckPenaltyEndTimestamp"] == 0

if id == 22:
assert node_operator_summary["totalExitedValidators"] == 11
# counts could inc but not dec
if id == 2:
assert node_operator_summary["totalExitedValidators"] == 252
elif id == 4:
assert node_operator_summary["totalExitedValidators"] == 174
elif id == 5:
assert node_operator_summary["totalExitedValidators"] == 36
elif id == 12:
assert node_operator_summary["totalExitedValidators"] >= 134
assert node_operator_summary["totalExitedValidators"] == 2300
elif id == 21:
assert node_operator_summary["totalExitedValidators"] >= 125
assert node_operator_summary["totalExitedValidators"] == 125
elif id == 22:
assert node_operator_summary["totalExitedValidators"] == 11
else:
assert node_operator_summary["totalExitedValidators"] == 0
assert (
node_operator_summary["totalExitedValidators"] == 0
), f"totalExitedValidators is positive for node {id}"

assert node_operator_summary["totalDepositedValidators"] > 0
assert node_operator_summary["depositableValidatorsCount"] is not None
Expand Down
15 changes: 14 additions & 1 deletion tests/regression/test_accounting_oracle_extra_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,32 @@
from utils.test.oracle_report_helpers import oracle_report

from utils.config import MAX_ACCOUNTING_EXTRA_DATA_LIST_ITEMS_COUNT, MAX_NODE_OPERATORS_PER_EXTRA_DATA_ITEM_COUNT
from utils.config import contracts


@pytest.fixture()
def extra_data_service():
return ExtraDataService()


def get_exited_count(node_operator_id):
counts = {2: 252, 4: 174, 5: 36}
if node_operator_id in counts.keys():
return counts[node_operator_id]
else:
return 0


def test_accounting_oracle_too_node_ops_per_extra_data_item(extra_data_service):
nos_per_item_count = 10
item_count = MAX_ACCOUNTING_EXTRA_DATA_LIST_ITEMS_COUNT
for i in range(nos_per_item_count):
no = contracts.node_operators_registry.getNodeOperator(i, True)
print(f'{i}-{no["totalExitedValidators"]}')

extra_data = extra_data_service.collect(
{(1, i): i for i in range(nos_per_item_count)},
{(1, i): i for i in range(nos_per_item_count)},
{(1, i): get_exited_count(i) for i in range(nos_per_item_count)},
item_count,
nos_per_item_count,
)
Expand Down
13 changes: 6 additions & 7 deletions tests/regression/test_all_round_happy_path.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,11 @@ def test_all_round_happy_path(accounts, stranger, steth_holder, eth_whale):
curated_module_id = 1

""" report """
while (
contracts.withdrawal_queue.getLastRequestId()
!= contracts.withdrawal_queue.getLastFinalizedRequestId()
):
while contracts.withdrawal_queue.getLastRequestId() != contracts.withdrawal_queue.getLastFinalizedRequestId():
# finalize all current requests first
report_tx = oracle_report()[0]
# stake new ether to increase buffer
contracts.lido.submit(ZERO_ADDRESS, { 'from': eth_whale.address, 'value': ETH(10000) })
contracts.lido.submit(ZERO_ADDRESS, {"from": eth_whale.address, "value": ETH(10000)})

contracts.lido.approve(contracts.withdrawal_queue.address, 1000, {"from": steth_holder})
contracts.withdrawal_queue.requestWithdrawals([1000], steth_holder, {"from": steth_holder})
Expand Down Expand Up @@ -114,7 +111,7 @@ def test_all_round_happy_path(accounts, stranger, steth_holder, eth_whale):
nor_operators_count = contracts.node_operators_registry.getNodeOperatorsCount()
for i in range(nor_operators_count):
no = contracts.node_operators_registry.getNodeOperator(i, True)
if (not no["totalDepositedValidators"]):
if not no["totalDepositedValidators"] or no["totalDepositedValidators"] == no["totalExitedValidators"]:
nor_operators_count = nor_operators_count - 1
treasury_balance_before_rebase = contracts.lido.sharesOf(treasury)

Expand All @@ -126,7 +123,9 @@ def test_all_round_happy_path(accounts, stranger, steth_holder, eth_whale):
token_rebased_event = report_tx.events["TokenRebased"]
transfer_event = report_tx.events["Transfer"]

assert extra_tx.events.count("Transfer") == nor_operators_count
assert (
extra_tx.events.count("Transfer") == nor_operators_count
), "extra_tx.events should have Transfer to all active operators, check activity condition above"
assert report_tx.events.count("TokenRebased") == 1
assert report_tx.events.count("WithdrawalsFinalized") == 1
assert report_tx.events.count("StETHBurnt") == 1
Expand Down
Loading

0 comments on commit 5bedb87

Please sign in to comment.