Skip to content
Merged
10 changes: 10 additions & 0 deletions crates/hashi-guardian/src/enclave.rs
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,16 @@ impl EnclaveState {
guard.consume(seq, timestamp, amount_sats)?;
Ok(LimiterGuard::new(guard))
}

pub async fn limiter_state(&self) -> Option<LimiterState> {
let limiter = self.rate_limiter.get()?;
Some(*limiter.lock().await.state())
}

pub async fn limiter_config(&self) -> Option<hashi_types::guardian::LimiterConfig> {
let limiter = self.rate_limiter.get()?;
Some(*limiter.lock().await.config())
}
}

impl Enclave {
Expand Down
4 changes: 4 additions & 0 deletions crates/hashi-guardian/src/getters.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,14 @@ pub async fn get_guardian_info(enclave: Arc<Enclave>) -> GuardianResult<GetGuard

let signing_pub_key = enclave.signing_pubkey();
let attestation = get_attestation(&signing_pub_key)?;
let limiter_state = enclave.state.limiter_state().await;
let limiter_config = enclave.state.limiter_config().await;
Ok(GetGuardianInfoResponse {
attestation,
signing_pub_key,
signed_info: enclave.sign(enclave.info()),
limiter_state,
limiter_config,
})
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,12 @@ message GetGuardianInfoResponse {

// Signed guardian info (includes server version, encryption pubkey, and optional S3/bucket info).
SignedGuardianInfo signed_info = 3;

// Current rate limiter state (if initialized).
LimiterState limiter_state = 4;

// Immutable limiter configuration (if initialized).
LimiterConfig limiter_config = 5;
}

// Guardian-signed wrapper around `GuardianInfoData`.
Expand Down Expand Up @@ -200,6 +206,15 @@ message LimiterState {
optional uint64 next_seq = 3;
}

// Immutable limiter configuration.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't exactly immutable since the guardian can opt to change it

message LimiterConfig {
// Token refill rate in sats per second.
optional uint64 refill_rate_sats_per_sec = 1;

// Maximum bucket capacity in sats.
optional uint64 max_bucket_capacity_sats = 2;
}

message ProvisionerInitResponse {}

// ============================
Expand Down
4 changes: 4 additions & 0 deletions crates/hashi-types/src/guardian/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,10 @@ pub struct GetGuardianInfoResponse {
pub signing_pub_key: GuardianPubKey,
/// Signed guardian info
pub signed_info: GuardianSigned<GuardianInfo>,
/// Current rate limiter state (if initialized).
pub limiter_state: Option<LimiterState>,
/// Immutable limiter configuration (if initialized).
pub limiter_config: Option<LimiterConfig>,
}

/// TODO: Add network?
Expand Down
28 changes: 28 additions & 0 deletions crates/hashi-types/src/guardian/proto_conversions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ use super::GuardianSigned;
use super::HashiCommittee;
use super::HashiCommitteeMember;
use super::HashiSigned;
use super::LimiterConfig;
use super::LimiterState;
use super::OperatorInitRequest;
use super::ProvisionerInitRequest;
Expand Down Expand Up @@ -200,10 +201,15 @@ impl TryFrom<pb::GetGuardianInfoResponse> for GetGuardianInfoResponse {
let signed_info_pb = resp.signed_info.ok_or_else(|| missing("signed_info"))?;
let signed_info = pb_to_signed_guardian_info(signed_info_pb)?;

let limiter_state = resp.limiter_state.map(pb_to_limiter_state).transpose()?;
let limiter_config = resp.limiter_config.map(pb_to_limiter_config).transpose()?;

Ok(GetGuardianInfoResponse {
attestation: attestation.to_vec(),
signing_pub_key,
signed_info,
limiter_state,
limiter_config,
})
}
}
Expand Down Expand Up @@ -335,6 +341,8 @@ pub fn get_guardian_info_response_to_pb(r: GetGuardianInfoResponse) -> pb::GetGu
attestation: Some(r.attestation.into()),
signing_pub_key: Some(r.signing_pub_key.to_bytes().to_vec().into()),
signed_info: Some(signed_guardian_info_to_pb(r.signed_info)),
limiter_state: r.limiter_state.map(limiter_state_to_pb),
limiter_config: r.limiter_config.map(limiter_config_to_pb),
}
}

Expand Down Expand Up @@ -659,6 +667,26 @@ fn limiter_state_to_pb(state: LimiterState) -> pb::LimiterState {
}
}

fn pb_to_limiter_config(cfg: pb::LimiterConfig) -> GuardianResult<LimiterConfig> {
let refill_rate = cfg
.refill_rate_sats_per_sec
.ok_or_else(|| missing("refill_rate_sats_per_sec"))?;
let max_bucket_capacity = cfg
.max_bucket_capacity_sats
.ok_or_else(|| missing("max_bucket_capacity_sats"))?;
Ok(LimiterConfig {
refill_rate,
max_bucket_capacity,
})
}

fn limiter_config_to_pb(cfg: LimiterConfig) -> pb::LimiterConfig {
pb::LimiterConfig {
refill_rate_sats_per_sec: Some(cfg.refill_rate),
max_bucket_capacity_sats: Some(cfg.max_bucket_capacity),
}
}

fn pb_to_hashi_committee(c: pb::Committee) -> GuardianResult<HashiCommittee> {
let epoch = c.epoch.ok_or_else(|| missing("epoch"))?;

Expand Down
2 changes: 2 additions & 0 deletions crates/hashi-types/src/guardian/test_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ impl GetGuardianInfoResponse {
attestation: "abcd".as_bytes().to_vec(),
signing_pub_key,
signed_info: GuardianSigned::new(info, &signing_key, 1234),
limiter_state: None,
limiter_config: None,
}
}
}
Expand Down
Binary file modified crates/hashi-types/src/proto/generated/sui.hashi.v1alpha.fds.bin
Binary file not shown.
16 changes: 16 additions & 0 deletions crates/hashi-types/src/proto/generated/sui.hashi.v1alpha.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1008,6 +1008,12 @@ pub struct GetGuardianInfoResponse {
/// Signed guardian info (includes server version, encryption pubkey, and optional S3/bucket info).
#[prost(message, optional, tag = "3")]
pub signed_info: ::core::option::Option<SignedGuardianInfo>,
/// Current rate limiter state (if initialized).
#[prost(message, optional, tag = "4")]
pub limiter_state: ::core::option::Option<LimiterState>,
/// Immutable limiter configuration (if initialized).
#[prost(message, optional, tag = "5")]
pub limiter_config: ::core::option::Option<LimiterConfig>,
}
/// Guardian-signed wrapper around `GuardianInfoData`.
#[derive(Clone, PartialEq, ::prost::Message)]
Expand Down Expand Up @@ -1180,6 +1186,16 @@ pub struct LimiterState {
#[prost(uint64, optional, tag = "3")]
pub next_seq: ::core::option::Option<u64>,
}
/// Immutable limiter configuration.
#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)]
pub struct LimiterConfig {
/// Token refill rate in sats per second.
#[prost(uint64, optional, tag = "1")]
pub refill_rate_sats_per_sec: ::core::option::Option<u64>,
/// Maximum bucket capacity in sats.
#[prost(uint64, optional, tag = "2")]
pub max_bucket_capacity_sats: ::core::option::Option<u64>,
}
#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)]
pub struct ProvisionerInitResponse {}
/// Hashi-signed wrapper for the withdrawal request.
Expand Down
10 changes: 10 additions & 0 deletions crates/hashi/src/grpc/guardian_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,14 @@ impl GuardianClient {
pub fn guardian_service_client(&self) -> GuardianServiceClient<Channel> {
GuardianServiceClient::new(self.channel.clone())
}

pub async fn get_guardian_info(
&self,
) -> Result<hashi_types::proto::GetGuardianInfoResponse, tonic::Status> {
let response = self
.guardian_service_client()
.get_guardian_info(hashi_types::proto::GetGuardianInfoRequest {})
.await?;
Ok(response.into_inner())
}
}
Loading
Loading