miden_node_rpc/server/
admission.rs1use std::sync::Arc;
2
3use miden_node_store::DatabaseError;
4use miden_node_store::allowlist::AccountAllowlist;
5use miden_node_tracing::{error, miden_instrument};
6use miden_protocol::account::{AccountId, AccountUpdateDetails};
7use miden_protocol::transaction::TxAccountUpdate;
8use miden_standards::account::auth::NetworkAccount;
9use tonic::Status;
10
11use crate::{COMPONENT, FundingClient, LOG_TARGET};
12
13#[derive(Clone)]
15pub struct AccountAdmission {
16 pub(crate) allowlist: Arc<AccountAllowlist>,
17 pub(crate) funding: Option<FundingClient>,
18 disabled: bool,
19}
20
21impl AccountAdmission {
22 pub fn enabled(allowlist: Arc<AccountAllowlist>) -> Self {
23 Self {
24 allowlist,
25 funding: None,
26 disabled: false,
27 }
28 }
29
30 pub fn disabled(allowlist: Arc<AccountAllowlist>) -> Self {
31 Self { allowlist, funding: None, disabled: true }
32 }
33
34 pub(crate) fn is_disabled(&self) -> bool {
35 self.disabled
36 }
37
38 #[must_use]
39 pub fn with_funding_client(mut self, client: Option<FundingClient>) -> Self {
40 self.funding = client;
41 self
42 }
43
44 pub(crate) async fn is_account_allowed(
46 &self,
47 account_id: AccountId,
48 ) -> Result<bool, DatabaseError> {
49 if self.disabled {
50 return Ok(true);
51 }
52 self.allowlist.contains_account(account_id).await
53 }
54
55 #[miden_instrument(
57 target = COMPONENT,
58 name = "account_admission.check",
59 fields(account.id = update.account_id()),
60 err,
61 )]
62 pub(crate) async fn check(&self, update: &TxAccountUpdate) -> tonic::Result<()> {
63 if self.disabled || !update.initial_state_commitment().is_empty() {
64 return Ok(());
65 }
66
67 if let AccountUpdateDetails::Public(patch) = update.details() {
70 let account = patch
71 .try_to_new_account()
72 .map_err(|error| Status::invalid_argument(error.to_string()))?;
73 if NetworkAccount::new(account).is_ok() {
74 return Ok(());
75 }
76 }
77
78 let account_id = update.account_id();
79 let allowed = self.is_account_allowed(account_id).await.map_err(|err| {
80 error!(err, target: LOG_TARGET, "Account allowlist lookup failed");
81 Status::internal("account allowlist lookup failed")
82 })?;
83 if !allowed {
84 return Err(Status::permission_denied(format!(
85 "account {account_id} is not registered"
86 )));
87 }
88
89 Ok(())
90 }
91}