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 #[serde(default)]
30 pub follow_only: bool,
31}
32
33impl From<&ChainInfo> for Chain {
34 fn from(info: &ChainInfo) -> Self {
35 Self {
36 owner: None,
37 block_hash: info.block_hash,
38 next_block_height: info.next_block_height,
39 timestamp: info.timestamp,
40 pending_proposal: None,
41 epoch: Some(info.epoch),
42 follow_only: false,
43 }
44 }
45}
46
47impl From<ChainInfo> for Chain {
48 fn from(info: ChainInfo) -> Self {
49 Self::from(&info)
50 }
51}
52
53impl From<&ChainDescription> for Chain {
54 fn from(description: &ChainDescription) -> Self {
55 Self::new(None, description.config().epoch, description.timestamp())
56 }
57}
58
59impl From<ChainDescription> for Chain {
60 fn from(description: ChainDescription) -> Self {
61 (&description).into()
62 }
63}
64
65impl Chain {
66 pub fn new(owner: Option<AccountOwner>, current_epoch: Epoch, now: Timestamp) -> Self {
68 Self {
69 owner,
70 block_hash: None,
71 timestamp: now,
72 next_block_height: BlockHeight::ZERO,
73 pending_proposal: None,
74 epoch: Some(current_epoch),
75 follow_only: false,
76 }
77 }
78}
79
80#[cfg_attr(not(web), trait_variant::make(Send))]
82pub trait Wallet {
83 type Error: std::error::Error + Send + Sync;
84 async fn get(&self, id: ChainId) -> Result<Option<Chain>, Self::Error>;
85 async fn remove(&self, id: ChainId) -> Result<Option<Chain>, Self::Error>;
86 fn items(&self) -> impl Stream<Item = Result<(ChainId, Chain), Self::Error>>;
87 async fn insert(&self, id: ChainId, chain: Chain) -> Result<Option<Chain>, Self::Error>;
88 async fn try_insert(&self, id: ChainId, chain: Chain) -> Result<Option<Chain>, 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 async fn modify(
101 &self,
102 id: ChainId,
103 f: impl FnMut(&mut Chain) + Send,
104 ) -> Result<Option<()>, Self::Error>;
105}
106
107impl<W: Deref<Target: Wallet> + linera_base::util::traits::AutoTraits> Wallet for W {
108 type Error = <W::Target as Wallet>::Error;
109
110 async fn get(&self, id: ChainId) -> Result<Option<Chain>, Self::Error> {
111 self.deref().get(id).await
112 }
113
114 async fn remove(&self, id: ChainId) -> Result<Option<Chain>, Self::Error> {
115 self.deref().remove(id).await
116 }
117
118 fn items(&self) -> impl Stream<Item = Result<(ChainId, Chain), Self::Error>> {
119 self.deref().items()
120 }
121
122 async fn insert(&self, id: ChainId, chain: Chain) -> Result<Option<Chain>, Self::Error> {
123 self.deref().insert(id, chain).await
124 }
125
126 async fn try_insert(&self, id: ChainId, chain: Chain) -> Result<Option<Chain>, Self::Error> {
127 self.deref().try_insert(id, chain).await
128 }
129
130 fn chain_ids(&self) -> impl Stream<Item = Result<ChainId, Self::Error>> {
131 self.deref().chain_ids()
132 }
133
134 fn owned_chain_ids(&self) -> impl Stream<Item = Result<ChainId, Self::Error>> {
135 self.deref().owned_chain_ids()
136 }
137
138 async fn modify(
139 &self,
140 id: ChainId,
141 f: impl FnMut(&mut Chain) + Send,
142 ) -> Result<Option<()>, Self::Error> {
143 self.deref().modify(id, f).await
144 }
145}