linera_core/environment/wallet/
mod.rs1use std::ops::Deref;
5
6use futures::{Stream, StreamExt as _, TryStreamExt as _};
7use linera_base::{
8 crypto::CryptoHash,
9 data_types::{BlockHeight, ChainDescription, Epoch, Timestamp},
10 identifiers::{AccountOwner, ChainId},
11};
12
13use crate::{client::PendingProposal, data_types::ChainInfo};
14
15mod memory;
16pub use memory::Memory;
17
18#[derive(Default, Clone, serde::Serialize, serde::Deserialize)]
20#[allow(missing_docs)]
21pub struct Chain {
22 pub owner: Option<AccountOwner>,
23 pub block_hash: Option<CryptoHash>,
24 pub next_block_height: BlockHeight,
25 pub timestamp: Timestamp,
26 pub pending_fast_proposal: Option<PendingProposal>,
27 pub epoch: Option<Epoch>,
28}
29
30impl From<&ChainInfo> for Chain {
31 fn from(info: &ChainInfo) -> Self {
32 Self {
33 owner: None,
34 block_hash: info.block_hash,
35 next_block_height: info.next_block_height,
36 timestamp: info.timestamp,
37 pending_fast_proposal: None,
38 epoch: Some(info.epoch),
39 }
40 }
41}
42
43impl From<ChainInfo> for Chain {
44 fn from(info: ChainInfo) -> Self {
45 Self::from(&info)
46 }
47}
48
49impl From<&ChainDescription> for Chain {
50 fn from(description: &ChainDescription) -> Self {
51 Self::new(None, description.config().epoch, description.timestamp())
52 }
53}
54
55impl From<ChainDescription> for Chain {
56 fn from(description: ChainDescription) -> Self {
57 (&description).into()
58 }
59}
60
61impl Chain {
62 pub fn new(owner: Option<AccountOwner>, current_epoch: Epoch, now: Timestamp) -> Self {
64 Self {
65 owner,
66 block_hash: None,
67 timestamp: now,
68 next_block_height: BlockHeight::ZERO,
69 pending_fast_proposal: None,
70 epoch: Some(current_epoch),
71 }
72 }
73
74 pub fn is_follow_only(&self) -> bool {
79 self.owner.is_none()
80 }
81}
82
83#[cfg_attr(not(web), trait_variant::make(Send))]
85pub trait Wallet {
86 type Error: std::error::Error + Send + Sync;
88 async fn get(&self, id: ChainId) -> Result<Option<Chain>, Self::Error>;
90 async fn remove(&self, id: ChainId) -> Result<Option<Chain>, Self::Error>;
92 fn items(&self) -> impl Stream<Item = Result<(ChainId, Chain), Self::Error>>;
94 async fn insert(&self, id: ChainId, chain: Chain) -> Result<Option<Chain>, Self::Error>;
96 async fn try_insert(&self, id: ChainId, chain: Chain) -> Result<Option<Chain>, Self::Error>;
98
99 fn chain_ids(&self) -> impl Stream<Item = Result<ChainId, Self::Error>> {
101 self.items().map(|result| result.map(|kv| kv.0))
102 }
103
104 fn owned_chain_ids(&self) -> impl Stream<Item = Result<ChainId, Self::Error>> {
106 self.items()
107 .try_filter_map(|(id, chain)| async move { Ok(chain.owner.map(|_| id)) })
108 }
109
110 async fn modify(
116 &self,
117 id: ChainId,
118 f: impl Fn(&mut Chain) + Send,
119 ) -> Result<Option<()>, Self::Error>;
120}
121
122impl<W: Deref<Target: Wallet> + linera_base::util::traits::AutoTraits> Wallet for W {
123 type Error = <W::Target as Wallet>::Error;
124
125 async fn get(&self, id: ChainId) -> Result<Option<Chain>, Self::Error> {
126 self.deref().get(id).await
127 }
128
129 async fn remove(&self, id: ChainId) -> Result<Option<Chain>, Self::Error> {
130 self.deref().remove(id).await
131 }
132
133 fn items(&self) -> impl Stream<Item = Result<(ChainId, Chain), Self::Error>> {
134 self.deref().items()
135 }
136
137 async fn insert(&self, id: ChainId, chain: Chain) -> Result<Option<Chain>, Self::Error> {
138 self.deref().insert(id, chain).await
139 }
140
141 async fn try_insert(&self, id: ChainId, chain: Chain) -> Result<Option<Chain>, Self::Error> {
142 self.deref().try_insert(id, chain).await
143 }
144
145 fn chain_ids(&self) -> impl Stream<Item = Result<ChainId, Self::Error>> {
146 self.deref().chain_ids()
147 }
148
149 fn owned_chain_ids(&self) -> impl Stream<Item = Result<ChainId, Self::Error>> {
150 self.deref().owned_chain_ids()
151 }
152
153 async fn modify(
154 &self,
155 id: ChainId,
156 f: impl Fn(&mut Chain) + Send,
157 ) -> Result<Option<()>, Self::Error> {
158 self.deref().modify(id, f).await
159 }
160}