hopr_api/chain/
accounts.rs

1use futures::{future::BoxFuture, stream::BoxStream};
2use hopr_crypto_types::prelude::{OffchainKeypair, OffchainPublicKey};
3pub use hopr_internal_types::prelude::AccountEntry;
4use hopr_primitive_types::prelude::Address;
5pub use hopr_primitive_types::prelude::{Balance, Currency};
6pub use multiaddr::Multiaddr;
7
8use crate::chain::ChainReceipt;
9
10/// Error that can occur when making a node announcement.
11///
12/// See [`ChainWriteAccountOperations::announce`]
13#[derive(Debug, strum::EnumIs, strum::EnumTryAs, thiserror::Error)]
14pub enum AnnouncementError<E> {
15    /// Special error when an account is already announced.
16    #[error("already announced")]
17    AlreadyAnnounced,
18    /// Error that can occur when processing an announcement.
19    #[error("account announcement error: {0}")]
20    ProcessingError(E),
21}
22
23impl<E> AnnouncementError<E> {
24    /// Constructs a [`AnnouncementError::ProcessingError`].
25    pub fn processing<F: Into<E>>(error: F) -> Self {
26        Self::ProcessingError(error.into())
27    }
28}
29
30/// Error that can occur when registering a node with a Safe.
31#[derive(Debug, strum::EnumIs, strum::EnumTryAs, thiserror::Error)]
32pub enum SafeRegistrationError<E> {
33    /// Special error when a Safe is already registered.
34    #[error("node is already registered with safe {0}")]
35    AlreadyRegistered(Address),
36    /// Error that can occur when processing a Safe registration.
37    #[error("safe registration error: {0}")]
38    ProcessingError(E),
39}
40
41impl<E> SafeRegistrationError<E> {
42    /// Constructs a [`SafeRegistrationError::ProcessingError`].
43    pub fn processing<F: Into<E>>(error: F) -> Self {
44        Self::ProcessingError(error.into())
45    }
46}
47
48/// On-chain write operations regarding on-chain node accounts.
49#[async_trait::async_trait]
50#[auto_impl::auto_impl(&, Box, Arc)]
51pub trait ChainWriteAccountOperations {
52    type Error: std::error::Error + Send + Sync + 'static;
53
54    /// Announces transport key and list of multi addresses.
55    async fn announce(
56        &self,
57        multiaddrs: &[Multiaddr],
58        key: &OffchainKeypair,
59    ) -> Result<BoxFuture<'life0, Result<ChainReceipt, Self::Error>>, AnnouncementError<Self::Error>>;
60
61    /// Withdraws native or token currency from the Safe or node account (depends on the used [`PayloadGenerator`]).
62    async fn withdraw<C: Currency + Send>(
63        &self,
64        balance: Balance<C>,
65        recipient: &Address,
66    ) -> Result<BoxFuture<'life0, Result<ChainReceipt, Self::Error>>, Self::Error>;
67
68    /// Registers Safe address with the current node.
69    async fn register_safe(
70        &self,
71        safe_address: &Address,
72    ) -> Result<BoxFuture<'life0, Result<ChainReceipt, Self::Error>>, SafeRegistrationError<Self::Error>>;
73}
74
75/// Selector for on-chain node accounts.
76///
77/// See [`ChainReadAccountOperations::stream_accounts`].
78#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
79pub struct AccountSelector {
80    /// Selects accounts that announced with publicly routable multi-addresses.
81    pub public_only: bool,
82    /// Selects accounts bound with the given chain key.
83    pub chain_key: Option<Address>,
84    /// Selects accounts bound with the given off-chain key.
85    pub offchain_key: Option<OffchainPublicKey>,
86}
87
88impl AccountSelector {
89    /// Selects only accounts that announced with publicly routable multi-addresses.
90    #[must_use]
91    pub fn with_public_only(mut self, public_only: bool) -> Self {
92        self.public_only = public_only;
93        self
94    }
95
96    /// Selects accounts bound with the given chain key.
97    #[must_use]
98    pub fn with_chain_key(mut self, chain_key: Address) -> Self {
99        self.chain_key = Some(chain_key);
100        self
101    }
102
103    /// Selects accounts bound with the given off-chain key.
104    #[must_use]
105    pub fn with_offchain_key(mut self, offchain_key: OffchainPublicKey) -> Self {
106        self.offchain_key = Some(offchain_key);
107        self
108    }
109
110    /// Checks if the given [`account`](AccountEntry) satisfies the selector.
111    pub fn satisfies(&self, account: &AccountEntry) -> bool {
112        if self.public_only && !account.has_announced_with_routing_info() {
113            return false;
114        }
115
116        if let Some(chain_key) = &self.chain_key {
117            if &account.chain_addr != chain_key {
118                return false;
119            }
120        }
121
122        if let Some(packet_key) = &self.offchain_key {
123            if &account.public_key != packet_key {
124                return false;
125            }
126        }
127
128        true
129    }
130}
131
132/// Chain operations that read on-chain node accounts.
133#[async_trait::async_trait]
134#[auto_impl::auto_impl(&, Box, Arc)]
135pub trait ChainReadAccountOperations {
136    type Error: std::error::Error + Send + Sync + 'static;
137
138    /// Returns on-chain node accounts with the given [`AccountSelector`].
139    async fn stream_accounts<'a>(
140        &'a self,
141        selector: AccountSelector,
142    ) -> Result<BoxStream<'a, AccountEntry>, Self::Error>;
143
144    /// Counts the accounts with the given [`AccountSelector`].
145    ///
146    /// This is potentially done more effectively than counting more elements of
147    /// the stream returned by [`ChainReadAccountOperations::stream_accounts`].
148    async fn count_accounts(&self, selector: AccountSelector) -> Result<usize, Self::Error>;
149
150    /// Waits for the account with the key-binding on the `offchain_key` to appear on-chain or the `timeout` expires.
151    async fn await_key_binding(
152        &self,
153        offchain_key: &OffchainPublicKey,
154        timeout: std::time::Duration,
155    ) -> Result<AccountEntry, Self::Error>;
156}