lighthouse-pulse/validator_client/slashing_protection/src/registration_tests.rs
Michael Sproul e961ff60b4 Implement standard keystore API (#2736)
## Issue Addressed

Implements the standard key manager API from https://ethereum.github.io/keymanager-APIs/, formerly https://github.com/ethereum/beacon-APIs/pull/151
Related to https://github.com/sigp/lighthouse/issues/2557

## Proposed Changes

- [x] Add all of the new endpoints from the standard API: GET, POST and DELETE.
- [x] Add a `validators.enabled` column to the slashing protection database to support atomic disable + export.
- [x] Add tests for all the common sequential accesses of the API
- [x] Add tests for interactions with remote signer validators
- [x] Add end-to-end tests for migration of validators from one VC to another
- [x] Implement the authentication scheme from the standard (token bearer auth)

## Additional Info

The `enabled` column in the validators SQL database is necessary to prevent a race condition when exporting slashing protection data. Without the slashing protection database having a way of knowing that a key has been disabled, a concurrent request to sign a message could insert a new record into the database. The `delete_concurrent_with_signing` test exercises this code path, and was indeed failing before the `enabled` column was added.

The validator client authentication has been modified from basic auth to bearer auth, with basic auth preserved for backwards compatibility.
2022-01-30 23:22:04 +00:00

75 lines
2.4 KiB
Rust

#![cfg(test)]
use crate::test_utils::*;
use crate::*;
use std::iter;
use tempfile::tempdir;
#[test]
fn double_register_validators() {
let dir = tempdir().unwrap();
let slashing_db_file = dir.path().join("slashing_protection.sqlite");
let slashing_db = SlashingDatabase::create(&slashing_db_file).unwrap();
let num_validators = 100u32;
let pubkeys = (0..num_validators as usize).map(pubkey).collect::<Vec<_>>();
let get_validator_ids = || {
pubkeys
.iter()
.map(|pk| slashing_db.get_validator_id(pk).unwrap())
.collect::<Vec<_>>()
};
assert_eq!(slashing_db.num_validator_rows().unwrap(), 0);
slashing_db.register_validators(pubkeys.iter()).unwrap();
assert_eq!(slashing_db.num_validator_rows().unwrap(), num_validators);
let validator_ids = get_validator_ids();
slashing_db.register_validators(pubkeys.iter()).unwrap();
assert_eq!(slashing_db.num_validator_rows().unwrap(), num_validators);
assert_eq!(validator_ids, get_validator_ids());
}
#[test]
fn reregister_validator() {
let dir = tempdir().unwrap();
let slashing_db_file = dir.path().join("slashing_protection.sqlite");
let slashing_db = SlashingDatabase::create(&slashing_db_file).unwrap();
let pk = pubkey(0);
// Register validator.
slashing_db.register_validator(pk).unwrap();
let id = slashing_db.get_validator_id(&pk).unwrap();
slashing_db
.with_transaction(|txn| {
// Disable.
slashing_db.update_validator_status(txn, id, false)?;
// Fetching the validator as "registered" should now fail.
assert_eq!(
slashing_db.get_validator_id_in_txn(txn, &pk).unwrap_err(),
NotSafe::DisabledValidator(pk)
);
// Fetching its status should return false.
let (fetched_id, enabled) =
slashing_db.get_validator_id_with_status(txn, &pk)?.unwrap();
assert_eq!(fetched_id, id);
assert!(!enabled);
// Re-registering the validator should preserve its ID while changing its status to
// enabled.
slashing_db.register_validators_in_txn(iter::once(&pk), txn)?;
let re_reg_id = slashing_db.get_validator_id_in_txn(txn, &pk)?;
assert_eq!(re_reg_id, id);
Ok::<_, NotSafe>(())
})
.unwrap();
}