Skip to content

Commit

Permalink
Add quote guard to change_endpoint extrinsic
Browse files Browse the repository at this point in the history
  • Loading branch information
HCastano committed Oct 21, 2024
1 parent 3e87482 commit fe47faa
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 8 deletions.
33 changes: 31 additions & 2 deletions pallets/staking/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -356,9 +356,22 @@ pub mod pallet {
impl<T: Config> Pallet<T> {
/// Allows a validator to change their endpoint so signers can find them when they are coms
/// manager `endpoint`: nodes's endpoint
///
/// # Expects TDX Quote
///
/// A valid TDX quote must be passed along in order to ensure that the validator is running
/// TDX hardware. In order for the chain to be aware that a quote is expected from the
/// validator `pallet_attestation::request_attestation()` must be called first.
///
/// The quote format is specified in:
/// https://download.01.org/intel-sgx/latest/dcap-latest/linux/docs/Intel_TDX_DCAP_Quoting_Library_API.pdf
#[pallet::call_index(0)]
#[pallet::weight(<T as Config>::WeightInfo::change_endpoint())]
pub fn change_endpoint(origin: OriginFor<T>, endpoint: Vec<u8>) -> DispatchResult {
pub fn change_endpoint(
origin: OriginFor<T>,
endpoint: Vec<u8>,
quote: Vec<u8>,
) -> DispatchResult {
let who = ensure_signed(origin)?;
ensure!(
endpoint.len() as u32 <= T::MaxEndpointLength::get(),
Expand All @@ -372,12 +385,26 @@ pub mod pallet {

ThresholdServers::<T>::try_mutate(&validator_id, |maybe_server_info| {
if let Some(server_info) = maybe_server_info {
// Before we modify the `server_info`, we want to check that the validator is
// still running TDX hardware.
ensure!(
<T::AttestationHandler as entropy_shared::AttestationHandler<_>>::verify_quote(
&server_info.tss_account.clone(),
server_info.x25519_public_key,
server_info.provisioning_certification_key.clone(),
quote
)
.is_ok(),
Error::<T>::FailedAttestationCheck
);

server_info.endpoint.clone_from(&endpoint);
Ok(())
} else {
Err(Error::<T>::NoBond)
}
})?;

Self::deposit_event(Event::EndpointChanged(who, endpoint));
Ok(())
}
Expand Down Expand Up @@ -498,9 +525,11 @@ pub mod pallet {
/// Wrap's Substrate's `staking_pallet::validate()` extrinsic, but enforces that
/// information about a validator's threshold server is provided.
///
/// # Expects TDX Quote
///
/// A valid TDX quote must be passed along in order to ensure that the validator candidate
/// is running TDX hardware. In order for the chain to be aware that a quote is expected
/// from the candidate, `pallet_attestation::request_attestation()` must be called first.
/// from the candidate `pallet_attestation::request_attestation()` must be called first.
///
/// The quote format is specified in:
/// https://download.01.org/intel-sgx/latest/dcap-latest/linux/docs/Intel_TDX_DCAP_Quoting_Library_API.pdf
Expand Down
2 changes: 1 addition & 1 deletion pallets/staking/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -385,7 +385,7 @@ impl pallet_parameters::Config for Test {
}

parameter_types! {
pub const MaxEndpointLength: u32 = 3;
pub const MaxEndpointLength: u32 = 25;
}

pub(crate) const VALID_QUOTE: [u8; 32] = [0; 32];
Expand Down
44 changes: 39 additions & 5 deletions pallets/staking/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ fn it_takes_in_an_endpoint() {
let server_info = ServerInfo {
tss_account: 3,
x25519_public_key: NULL_ARR,
endpoint: vec![20, 20, 20, 20],
endpoint: [20; (crate::tests::MaxEndpointLength::get() + 1) as usize].to_vec(),
provisioning_certification_key: BoundedVec::with_max_capacity(),
};
assert_noop!(
Expand Down Expand Up @@ -158,6 +158,8 @@ fn it_will_not_allow_validator_to_use_existing_tss_account() {
#[test]
fn it_changes_endpoint() {
new_test_ext().execute_with(|| {
let endpoint = b"http://localhost:3001".to_vec();

assert_ok!(FrameStaking::bond(
RuntimeOrigin::signed(1),
100u64,
Expand All @@ -167,7 +169,7 @@ fn it_changes_endpoint() {
let server_info = ServerInfo {
tss_account: 3,
x25519_public_key: NULL_ARR,
endpoint: vec![20],
endpoint: endpoint.clone(),
provisioning_certification_key: BoundedVec::with_max_capacity(),
};
assert_ok!(Staking::validate(
Expand All @@ -177,16 +179,48 @@ fn it_changes_endpoint() {
VALID_QUOTE.to_vec(),
));

assert_ok!(Staking::change_endpoint(RuntimeOrigin::signed(1), vec![30]));
assert_eq!(Staking::threshold_server(1).unwrap().endpoint, vec![30]);
assert_ok!(Staking::change_endpoint(RuntimeOrigin::signed(1), endpoint.clone(), VALID_QUOTE.to_vec()));
assert_eq!(Staking::threshold_server(1).unwrap().endpoint, endpoint);

assert_noop!(
Staking::change_endpoint(RuntimeOrigin::signed(3), vec![30]),
Staking::change_endpoint(RuntimeOrigin::signed(3), endpoint, VALID_QUOTE.to_vec()),
Error::<Test>::NoBond
);
});
}

#[test]
fn it_doesnt_change_endpoint_with_invalid_quote() {
new_test_ext().execute_with(|| {
let endpoint = b"http://localhost:3001".to_vec();

assert_ok!(FrameStaking::bond(
RuntimeOrigin::signed(1),
100u64,
pallet_staking::RewardDestination::Account(1),
));

let server_info = ServerInfo {
tss_account: 3,
x25519_public_key: NULL_ARR,
endpoint: endpoint.clone(),
provisioning_certification_key: BoundedVec::with_max_capacity(),
};

assert_ok!(Staking::validate(
RuntimeOrigin::signed(1),
pallet_staking::ValidatorPrefs::default(),
server_info.clone(),
VALID_QUOTE.to_vec(),
));

assert_noop!(
Staking::change_endpoint(RuntimeOrigin::signed(1), endpoint, INVALID_QUOTE.to_vec()),
Error::<Test>::FailedAttestationCheck
);
})
}

#[test]
fn it_changes_threshold_account() {
new_test_ext().execute_with(|| {
Expand Down

0 comments on commit fe47faa

Please sign in to comment.