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)]
19pub struct Chain {
20 pub owner: Option<AccountOwner>,
21 pub block_hash: Option<CryptoHash>,
22 pub next_block_height: BlockHeight,
23 pub timestamp: Timestamp,
24 pub pending_proposal: Option<PendingProposal>,
25 pub epoch: Option<Epoch>,
26}
27
28impl From<&ChainInfo> for Chain {
29 fn from(info: &ChainInfo) -> Self {
30 Self {
31 owner: None,
32 block_hash: info.block_hash,
33 next_block_height: info.next_block_height,
34 timestamp: info.timestamp,
35 pending_proposal: None,
36 epoch: Some(info.epoch),
37 }
38 }
39}
40
41impl From<ChainInfo> for Chain {
42 fn from(info: ChainInfo) -> Self {
43 Self::from(&info)
44 }
45}
46
47impl From<&ChainDescription> for Chain {
48 fn from(description: &ChainDescription) -> Self {
49 Self::new(None, description.config().epoch, description.timestamp())
50 }
51}
52
53impl From<ChainDescription> for Chain {
54 fn from(description: ChainDescription) -> Self {
55 (&description).into()
56 }
57}
58
59impl Chain {
60 pub fn new(owner: Option<AccountOwner>, current_epoch: Epoch, now: Timestamp) -> Self {
62 Self {
63 owner,
64 block_hash: None,
65 timestamp: now,
66 next_block_height: BlockHeight::ZERO,
67 pending_proposal: None,
68 epoch: Some(current_epoch),
69 }
70 }
71
72 pub fn is_follow_only(&self) -> bool {
77 self.owner.is_none()
78 }
79}
80
81#[cfg_attr(not(web), trait_variant::make(Send))]
83pub trait Wallet {
84 type Error: std::error::Error + Send + Sync;
85 async fn get(&self, id: ChainId) -> Result<Option<Chain>, Self::Error>;
86 async fn remove(&self, id: ChainId) -> Result<Option<Chain>, Self::Error>;
87 fn items(&self) -> impl Stream<Item = Result<(ChainId, Chain), Self::Error>>;
88 async fn insert(&self, id: ChainId, chain: Chain) -> Result<Option<Chain>, Self::Error>;
89 async fn try_insert(&self, id: ChainId, chain: Chain) -> Result<Option<Chain>, Self::Error>;
90
91 fn chain_ids(&self) -> impl Stream<Item = Result<ChainId, Self::Error>> {
92 self.items().map(|result| result.map(|kv| kv.0))
93 }
94
95 fn owned_chain_ids(&self) -> impl Stream<Item = Result<ChainId, Self::Error>> {
96 self.items()
97 .try_filter_map(|(id, chain)| async move { Ok(chain.owner.map(|_| id)) })
98 }
99
100 async fn modify(
102 &self,
103 id: ChainId,
104 f: impl FnMut(&mut Chain) + Send,
105 ) -> Result<Option<()>, Self::Error>;
106}
107
108impl<W: Deref<Target: Wallet> + linera_base::util::traits::AutoTraits> Wallet for W {
109 type Error = <W::Target as Wallet>::Error;
110
111 async fn get(&self, id: ChainId) -> Result<Option<Chain>, Self::Error> {
112 self.deref().get(id).await
113 }
114
115 async fn remove(&self, id: ChainId) -> Result<Option<Chain>, Self::Error> {
116 self.deref().remove(id).await
117 }
118
119 fn items(&self) -> impl Stream<Item = Result<(ChainId, Chain), Self::Error>> {
120 self.deref().items()
121 }
122
123 async fn insert(&self, id: ChainId, chain: Chain) -> Result<Option<Chain>, Self::Error> {
124 self.deref().insert(id, chain).await
125 }
126
127 async fn try_insert(&self, id: ChainId, chain: Chain) -> Result<Option<Chain>, Self::Error> {
128 self.deref().try_insert(id, chain).await
129 }
130
131 fn chain_ids(&self) -> impl Stream<Item = Result<ChainId, Self::Error>> {
132 self.deref().chain_ids()
133 }
134
135 fn owned_chain_ids(&self) -> impl Stream<Item = Result<ChainId, Self::Error>> {
136 self.deref().owned_chain_ids()
137 }
138
139 async fn modify(
140 &self,
141 id: ChainId,
142 f: impl FnMut(&mut Chain) + Send,
143 ) -> Result<Option<()>, Self::Error> {
144 self.deref().modify(id, f).await
145 }
146}