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
73#[cfg_attr(not(web), trait_variant::make(Send))]
75pub trait Wallet {
76 type Error: std::error::Error + Send + Sync;
77 async fn get(&self, id: ChainId) -> Result<Option<Chain>, Self::Error>;
78 async fn remove(&self, id: ChainId) -> Result<Option<Chain>, Self::Error>;
79 fn items(&self) -> impl Stream<Item = Result<(ChainId, Chain), Self::Error>>;
80 async fn insert(&self, id: ChainId, chain: Chain) -> Result<Option<Chain>, Self::Error>;
81 async fn try_insert(&self, id: ChainId, chain: Chain) -> Result<Option<Chain>, Self::Error>;
82
83 async fn modify(
85 &self,
86 id: ChainId,
87 f: impl FnMut(&mut Chain) + Send,
88 ) -> Result<Option<()>, Self::Error>;
89
90 fn chain_ids(&self) -> impl Stream<Item = Result<ChainId, Self::Error>> {
91 self.items().map(|result| result.map(|kv| kv.0))
92 }
93
94 fn owned_chain_ids(&self) -> impl Stream<Item = Result<ChainId, Self::Error>> {
95 self.items()
96 .try_filter_map(|(id, chain)| async move { Ok(chain.owner.map(|_| id)) })
97 }
98}
99
100impl<W: Deref<Target: Wallet> + linera_base::util::traits::AutoTraits> Wallet for W {
101 type Error = <W::Target as Wallet>::Error;
102
103 async fn get(&self, id: ChainId) -> Result<Option<Chain>, Self::Error> {
104 self.deref().get(id).await
105 }
106
107 async fn remove(&self, id: ChainId) -> Result<Option<Chain>, Self::Error> {
108 self.deref().remove(id).await
109 }
110
111 fn items(&self) -> impl Stream<Item = Result<(ChainId, Chain), Self::Error>> {
112 self.deref().items()
113 }
114
115 async fn insert(&self, id: ChainId, chain: Chain) -> Result<Option<Chain>, Self::Error> {
116 self.deref().insert(id, chain).await
117 }
118
119 async fn try_insert(&self, id: ChainId, chain: Chain) -> Result<Option<Chain>, Self::Error> {
120 self.deref().try_insert(id, chain).await
121 }
122
123 fn chain_ids(&self) -> impl Stream<Item = Result<ChainId, Self::Error>> {
124 self.deref().chain_ids()
125 }
126
127 fn owned_chain_ids(&self) -> impl Stream<Item = Result<ChainId, Self::Error>> {
128 self.deref().owned_chain_ids()
129 }
130
131 async fn modify(
132 &self,
133 id: ChainId,
134 f: impl FnMut(&mut Chain) + Send,
135 ) -> Result<Option<()>, Self::Error> {
136 self.deref().modify(id, f).await
137 }
138}