Skip to content

Commit

Permalink
feat(val-1404): naming, docs, etc after review
Browse files Browse the repository at this point in the history
feat(val-1404): naming, docs, etc after review
  • Loading branch information
dputko committed Dec 23, 2024
1 parent f8c7d92 commit 73e1ac6
Show file tree
Hide file tree
Showing 11 changed files with 62 additions and 59 deletions.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,10 @@ Currently it supports:
`ALERTMANAGER_REQUEST_SLEEP_BEFORE_RETRY_IN_SECONDS` - Alertmanager request retry timeout in seconds
* **Required:** false
* **Default:** 1
---
`VALID_WITHDRAWAL_ADDRESSES` - A comma-separated list of addresses. Triggers a critical alert if a monitored execution_request contains a source_address matching any of these addresses
* **Required:** false
* **Default:** []

## Application metrics

Expand Down
12 changes: 6 additions & 6 deletions src/handlers/consolidation.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,15 @@ def handle(self, watcher, head: FullBlockInfo):
slot = head.message.slot
for consolidation in head.message.body.execution_requests.consolidations:
alert, summary = None, ""
if consolidation.source_address in watcher.suspicious_addresses:
alert = CommonAlert(name="HeadWatcherConsolidationSuspiciousSourceAddress", severity="critical")
summary = "πŸ”—πŸ€— Validator consolidation was requested from Withdrawal Vault source address"
if consolidation.source_address in watcher.valid_withdrawal_addresses:
alert = CommonAlert(name="HeadWatcherConsolidationSourceWithdrawalAddress", severity="critical")
summary = "‼️⛔️Validator consolidation was requested from Withdrawal Vault source address"
elif consolidation.source_pubkey in watcher.user_keys:
alert = CommonAlert(name="HeadWatcherConsolidationSourceLido", severity="moderate")
summary = "πŸ”—πŸ€— Consolidation was requested for our validators"
alert = CommonAlert(name="HeadWatcherConsolidationUserSourcePubkey", severity="info")
summary = "⚠️Consolidation was requested for our validators"
elif consolidation.target_pubkey in watcher.user_keys:
alert = CommonAlert(name="HeadWatcherConsolidationUserTargetPubkey", severity="info")
summary = "πŸ”—πŸ€— Someone attempts to consolidate their validators to our validators"
summary = "⚠️Someone attempts to consolidate their validators to our validators"
# in the future we should check the type of validator WC:
# if it is 0x02 and source_address == WCs of source validator - It's donation!

Expand Down
2 changes: 1 addition & 1 deletion src/handlers/el_triggered_exit.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ def handle(self, watcher, head: FullBlockInfo):
slot = head.message.slot
for withdrawal in head.message.body.execution_requests.withdrawals:
alert, summary = None, ""
if withdrawal.source_address in watcher.suspicious_addresses:
if withdrawal.source_address in watcher.valid_withdrawal_addresses:
alert = CommonAlert(name="HeadWatcherELWithdrawalFromUserWithdrawalAddress", severity="critical")
summary = "πŸ”—β€πŸƒπŸšͺOur validator triggered withdrawal was requested from our Withdrawal Vault address"
elif withdrawal.validator_pubkey in watcher.user_keys:
Expand Down
2 changes: 1 addition & 1 deletion src/variables.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@

LIDO_LOCATOR_ADDRESS = os.getenv('LIDO_LOCATOR_ADDRESS', '')

SUSPICIOUS_ADDRESSES = os.getenv('SUSPICIOUS_ADDRESSES', '').split(',')
VALID_WITHDRAWAL_ADDRESSES = os.getenv('VALID_WITHDRAWAL_ADDRESSES', '').split(',')

# - Metrics -
PROMETHEUS_PORT = int(os.getenv('PROMETHEUS_PORT', 9000))
Expand Down
6 changes: 3 additions & 3 deletions src/watcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,9 @@ def __init__(self, handlers: list[WatcherHandler], keys_source: BaseSource, web3
self.indexed_validators_keys: dict[str, str] = {}
self.chain_reorgs: dict[str, ChainReorgEvent] = {}
self.handled_headers: list[BlockHeaderResponseData] = []
self.suspicious_addresses = variables.SUSPICIOUS_ADDRESSES
if not self.suspicious_addresses and self.execution:
self.suspicious_addresses = {
self.valid_withdrawal_addresses = variables.VALID_WITHDRAWAL_ADDRESSES
if not self.valid_withdrawal_addresses and self.execution:
self.valid_withdrawal_addresses = {
self.execution.lido_contracts.lido_locator.functions.withdrawalVault().call()
}

Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import pytest

from src.keys_source.base_source import NamedKey
from tests.eip7251.helpers import gen_random_address
from tests.eip7251.stubs import TestValidator, WatcherStub
from tests.execution_requests.helpers import gen_random_address
from tests.execution_requests.stubs import TestValidator, WatcherStub


@pytest.fixture
Expand All @@ -16,11 +16,11 @@ def validator():


@pytest.fixture
def lido_validator(user_keys):
def user_validator(user_keys):
random_validator = TestValidator.random()
user_keys[random_validator.pubkey] = NamedKey(
key=random_validator.pubkey,
operatorName='Dimon operator',
operatorName='Test operator',
operatorIndex='1',
moduleIndex='1'
)
Expand All @@ -35,7 +35,7 @@ def watcher(user_keys) -> WatcherStub:


@pytest.fixture
def lido_withdrawal_vault(watcher: WatcherStub) -> str:
def withdrawal_address(watcher: WatcherStub) -> str:
address = gen_random_address()
watcher.suspicious_addresses.add(address)
watcher.valid_withdrawal_addresses.add(address)
return address
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

from src.keys_source.base_source import NamedKey
from src.providers.alertmanager.typings import AlertBody
from tests.eip7251.helpers import gen_random_address, gen_random_pubkey
from tests.execution_requests.helpers import gen_random_address, gen_random_pubkey


@dataclass
Expand Down Expand Up @@ -30,11 +30,11 @@ class WatcherStub:
alertmanager: AlertmanagerStub
user_keys: dict[str, NamedKey]
indexed_validators_keys: dict[str, str]
suspicious_addresses: set[str]
valid_withdrawal_addresses: set[str]

def __init__(self, user_keys: dict[str, NamedKey] = None, indexed_validators_keys: dict[str, str] = None,
suspicious_source_addresses: set[str] = None):
valid_withdrawal_addresses: set[str] = None):
self.alertmanager = AlertmanagerStub()
self.user_keys = user_keys or dict()
self.indexed_validators_keys = indexed_validators_keys or dict()
self.suspicious_addresses = suspicious_source_addresses or set()
self.valid_withdrawal_addresses = valid_withdrawal_addresses or set()
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
from src.handlers.consolidation import ConsolidationHandler
from src.providers.consensus.typings import ConsolidationRequest
from tests.eip7251.helpers import gen_random_pubkey, create_sample_block, gen_random_address
from tests.execution_requests.helpers import gen_random_pubkey, create_sample_block, gen_random_address

from tests.eip7251.stubs import TestValidator, WatcherStub
from tests.execution_requests.stubs import TestValidator, WatcherStub


def test_source_address_is_lido_withdrawal_vault(lido_withdrawal_vault: str, watcher: WatcherStub):
def test_source_is_valid_withdrawal_address(withdrawal_address: str, watcher: WatcherStub):
random_source_pubkey = gen_random_pubkey()
random_target_pubkey = gen_random_pubkey()

block = create_sample_block(consolidations=[
ConsolidationRequest(
source_address=lido_withdrawal_vault,
source_address=withdrawal_address,
source_pubkey=random_source_pubkey,
target_pubkey=random_target_pubkey
)
Expand All @@ -23,23 +23,23 @@ def test_source_address_is_lido_withdrawal_vault(lido_withdrawal_vault: str, wat

assert len(watcher.alertmanager.sent_alerts) == 1
alert = watcher.alertmanager.sent_alerts[0]
assert alert.labels.alertname.startswith('HeadWatcherConsolidationSuspiciousSourceAddress')
assert alert.labels.alertname.startswith('HeadWatcherConsolidationSourceWithdrawalAddress')
assert alert.labels.severity == 'critical'
assert alert.annotations.summary == "πŸ”—πŸ€— Highly suspicious source address"
assert alert.annotations.summary == "‼️⛔️Validator consolidation was requested from Withdrawal Vault source address"
assert random_source_pubkey in alert.annotations.description
assert random_target_pubkey in alert.annotations.description
assert lido_withdrawal_vault in alert.annotations.description
assert withdrawal_address in alert.annotations.description
assert block.message.slot in alert.annotations.description


def test_consolidate_lido(lido_validator: TestValidator, watcher: WatcherStub):
def test_consolidate_user_validator(user_validator: TestValidator, watcher: WatcherStub):
random_source_address = gen_random_address()
random_target_pubkey = gen_random_pubkey()

block = create_sample_block(consolidations=[
ConsolidationRequest(
source_address=random_source_address,
source_pubkey=lido_validator.pubkey,
source_pubkey=user_validator.pubkey,
target_pubkey=random_target_pubkey
)
])
Expand All @@ -50,25 +50,24 @@ def test_consolidate_lido(lido_validator: TestValidator, watcher: WatcherStub):

assert len(watcher.alertmanager.sent_alerts) == 1
alert = watcher.alertmanager.sent_alerts[0]
assert alert.labels.alertname.startswith('HeadWatcherConsolidationSourceLido')
assert alert.labels.severity == 'moderate'
assert alert.annotations.summary == "πŸ”—πŸ€— Attempt to consolidate Lido validator"
assert alert.labels.alertname.startswith('HeadWatcherConsolidationUserSourcePubkey')
assert alert.labels.severity == 'info'
assert alert.annotations.summary == "⚠️Consolidation was requested for our validators"
assert random_source_address in alert.annotations.description
assert random_target_pubkey in alert.annotations.description
assert lido_validator.pubkey in alert.annotations.description
assert user_validator.pubkey in alert.annotations.description
assert block.message.slot in alert.annotations.description


def test_donation_to_lido(lido_validator: TestValidator, watcher: WatcherStub):
def test_donation(user_validator: TestValidator, watcher: WatcherStub):
random_source_address = gen_random_address()
random_target_pubkey = gen_random_pubkey()
random_source_pubkey = gen_random_pubkey()

block = create_sample_block(consolidations=[
ConsolidationRequest(
source_address=random_source_address,
source_pubkey=random_source_pubkey,
target_pubkey=lido_validator.pubkey
target_pubkey=user_validator.pubkey
)
])
handler = ConsolidationHandler()
Expand All @@ -78,16 +77,16 @@ def test_donation_to_lido(lido_validator: TestValidator, watcher: WatcherStub):

assert len(watcher.alertmanager.sent_alerts) == 1
alert = watcher.alertmanager.sent_alerts[0]
assert alert.labels.alertname.startswith('HeadWatcherConsolidationPossibleDonation')
assert alert.labels.severity == 'moderate'
assert alert.annotations.summary == "πŸ”—πŸ€— Someone wants to donate to Lido"
assert alert.labels.alertname.startswith('HeadWatcherConsolidationUserTargetPubkey')
assert alert.labels.severity == 'info'
assert alert.annotations.summary == "⚠️Someone attempts to consolidate their validators to our validators"
assert random_source_address in alert.annotations.description
assert random_source_pubkey in alert.annotations.description
assert lido_validator.pubkey in alert.annotations.description
assert user_validator.pubkey in alert.annotations.description
assert block.message.slot in alert.annotations.description


def test_non_lido(watcher: WatcherStub):
def test_absence_of_alerts_on_foreign_validators(watcher: WatcherStub):
random_source_address = gen_random_address()
random_target_pubkey = gen_random_pubkey()
random_source_pubkey = gen_random_pubkey()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
from src.handlers.el_triggered_exit import ElTriggeredExitHandler
from src.keys_source.base_source import NamedKey
from src.providers.consensus.typings import WithdrawalRequest
from tests.eip7251.helpers import create_sample_block, gen_random_address
from tests.eip7251.stubs import WatcherStub, TestValidator
from tests.execution_requests.helpers import create_sample_block, gen_random_address
from tests.execution_requests.stubs import WatcherStub, TestValidator


def test_lido_validator_pubkey(lido_validator: TestValidator, watcher: WatcherStub):
def tedt_user_validator(user_validator: TestValidator, watcher: WatcherStub):
random_address = gen_random_address()
block = create_sample_block(withdrawals=[
WithdrawalRequest(
source_address=random_address,
validator_pubkey=lido_validator.pubkey,
validator_pubkey=user_validator.pubkey,
amount='32'
)
])
Expand All @@ -21,16 +21,16 @@ def test_lido_validator_pubkey(lido_validator: TestValidator, watcher: WatcherSt

assert len(watcher.alertmanager.sent_alerts) == 1
alert = watcher.alertmanager.sent_alerts[0]
assert alert.labels.alertname.startswith('HeadWatcherElWithdrawalUnexpected')
assert alert.labels.severity == 'moderate'
assert alert.annotations.summary == "πŸ”—β€πŸƒπŸšͺUnexpected EL withdrawal request found"
assert lido_validator.pubkey in alert.annotations.description
assert alert.labels.alertname.startswith('HeadWatcherUserELWithdrawal')
assert alert.labels.severity == 'info'
assert alert.annotations.summary == "πŸ”—β€πŸƒπŸšͺOur validator triggered withdrawal was requested"
assert user_validator.pubkey in alert.annotations.description
assert random_address in alert.annotations.description
assert '32' in alert.annotations.description
assert block.message.slot in alert.annotations.description


def test_non_lido_validator(validator: TestValidator, watcher: WatcherStub):
def test_absence_of_alerts_for_foreign_validator(validator: TestValidator, watcher: WatcherStub):
block = create_sample_block(withdrawals=[
WithdrawalRequest(
source_address=gen_random_address(),
Expand All @@ -46,10 +46,10 @@ def test_non_lido_validator(validator: TestValidator, watcher: WatcherStub):
assert len(watcher.alertmanager.sent_alerts) == 0


def test_lido_wv_address(validator: TestValidator, lido_withdrawal_vault: str, watcher: WatcherStub):
def test_from_user_withdrawal_address(validator: TestValidator, withdrawal_address: str, watcher: WatcherStub):
block = create_sample_block(withdrawals=[
WithdrawalRequest(
source_address=lido_withdrawal_vault,
source_address=withdrawal_address,
validator_pubkey=validator.pubkey,
amount='32'
)
Expand All @@ -61,16 +61,16 @@ def test_lido_wv_address(validator: TestValidator, lido_withdrawal_vault: str, w

assert len(watcher.alertmanager.sent_alerts) == 1
alert = watcher.alertmanager.sent_alerts[0]
assert alert.labels.alertname.startswith('HeadWatcherElWithdrawalVault')
assert alert.labels.alertname.startswith('HeadWatcherELWithdrawalFromUserWithdrawalAddress')
assert alert.labels.severity == 'critical'
assert alert.annotations.summary == "πŸ”—β€πŸƒπŸšͺHighly suspicious source address"
assert alert.annotations.summary == "πŸ”—β€πŸƒπŸšͺOur validator triggered withdrawal was requested from our Withdrawal Vault address"
assert validator.pubkey in alert.annotations.description
assert lido_withdrawal_vault in alert.annotations.description
assert withdrawal_address in alert.annotations.description
assert '32' in alert.annotations.description
assert block.message.slot in alert.annotations.description


def test_pre_pectra(watcher: WatcherStub):
def test_works_on_dencun(watcher: WatcherStub):
handler = ElTriggeredExitHandler()
block = create_sample_block()

Expand All @@ -80,14 +80,14 @@ def test_pre_pectra(watcher: WatcherStub):
assert len(watcher.alertmanager.sent_alerts) == 0


def test_not_our_keys():
def test_absense_of_alerts_for_foreign_validator():
validator_pubkey = '0x84a687ffdf21a0ad754d0164d1e2c03035613ab76359e7f5cf51ea4a425a6ee026725ec0a0dbd336f7dab759596f0bf8'
amount = "32"
watcher = WatcherStub(
user_keys={
validator_pubkey: NamedKey(
key=validator_pubkey,
operatorName='Dimon operator',
operatorName='Test operator',
operatorIndex='1',
moduleIndex='1'
)
Expand Down

0 comments on commit 73e1ac6

Please sign in to comment.