linera_wallet_json/
wallet.rs1use std::{
5 iter::IntoIterator,
6 sync::{Arc, RwLock},
7};
8
9use futures::{stream, Stream};
10use linera_base::identifiers::{AccountOwner, ChainId};
11use linera_client::config::GenesisConfig;
12use linera_core::wallet::*;
13use linera_persistent::{self as persistent};
14
15#[derive(serde::Serialize, serde::Deserialize)]
16pub(crate) struct Data {
17 pub chains: Memory,
18 pub default: Arc<RwLock<Option<ChainId>>>,
19 pub genesis_config: GenesisConfig,
20}
21
22pub struct PersistentWallet(persistent::File<Data>);
23
24impl linera_core::Wallet for PersistentWallet {
28 type Error = persistent::file::Error;
29
30 async fn get(&self, id: ChainId) -> Result<Option<Chain>, Self::Error> {
31 Ok(self.get(id))
32 }
33
34 async fn remove(&self, id: ChainId) -> Result<Option<Chain>, Self::Error> {
35 self.remove(id)
36 }
37
38 fn items(&self) -> impl Stream<Item = Result<(ChainId, Chain), Self::Error>> {
39 stream::iter(self.items().into_iter().map(Ok))
40 }
41
42 async fn insert(&self, id: ChainId, chain: Chain) -> Result<Option<Chain>, Self::Error> {
43 self.insert(id, &chain)
44 }
45
46 async fn try_insert(&self, id: ChainId, chain: Chain) -> Result<Option<Chain>, Self::Error> {
47 let chain = self.try_insert(id, chain)?;
48 self.save()?;
49 Ok(chain)
50 }
51
52 async fn modify(
53 &self,
54 id: ChainId,
55 f: impl Fn(&mut Chain) + Send,
56 ) -> Result<Option<()>, Self::Error> {
57 self.mutate(id, f).transpose()
58 }
59}
60
61impl Extend<(ChainId, Chain)> for PersistentWallet {
62 fn extend<It: IntoIterator<Item = (ChainId, Chain)>>(&mut self, chains: It) {
63 for (id, chain) in chains {
64 if self.0.chains.try_insert(id, chain).is_none() {
65 self.try_set_default(id);
66 }
67 }
68 }
69}
70
71impl PersistentWallet {
72 pub fn get(&self, id: ChainId) -> Option<Chain> {
73 self.0.chains.get(id)
74 }
75
76 pub fn remove(&self, id: ChainId) -> Result<Option<Chain>, persistent::file::Error> {
77 let chain = self.0.chains.remove(id);
78 {
79 let mut default = self.0.default.write().unwrap();
80 if *default == Some(id) {
81 *default = None;
82 }
83 }
84 self.0.save()?;
85 Ok(chain)
86 }
87
88 pub fn items(&self) -> Vec<(ChainId, Chain)> {
89 self.0.chains.items()
90 }
91
92 fn try_set_default(&self, id: ChainId) {
93 let mut guard = self.0.default.write().unwrap();
94 if guard.is_none() {
95 *guard = Some(id);
96 }
97 }
98
99 pub fn insert(
100 &self,
101 id: ChainId,
102 chain: &Chain,
103 ) -> Result<Option<Chain>, persistent::file::Error> {
104 let has_owner = chain.owner.is_some();
105 let old_chain = self.0.chains.insert(id, chain.clone());
106 if has_owner {
107 self.try_set_default(id);
108 }
109 self.0.save()?;
110 Ok(old_chain)
111 }
112
113 pub fn try_insert(
114 &self,
115 id: ChainId,
116 chain: Chain,
117 ) -> Result<Option<Chain>, persistent::file::Error> {
118 let chain = self.0.chains.try_insert(id, chain);
119 if chain.is_none() {
120 self.try_set_default(id);
121 }
122 self.save()?;
123 Ok(chain)
124 }
125
126 pub fn create(
127 path: &std::path::Path,
128 genesis_config: GenesisConfig,
129 ) -> Result<Self, persistent::file::Error> {
130 Ok(Self(persistent::File::new(
131 path,
132 Data {
133 chains: Memory::default(),
134 default: Arc::new(RwLock::new(None)),
135 genesis_config,
136 },
137 )?))
138 }
139
140 pub fn read(path: &std::path::Path) -> Result<Self, persistent::file::Error> {
141 Ok(Self(persistent::File::read(path)?))
142 }
143
144 pub fn genesis_config(&self) -> &GenesisConfig {
145 &self.0.genesis_config
146 }
147
148 pub fn genesis_admin_chain_id(&self) -> ChainId {
149 self.0.genesis_config.admin_chain_id()
150 }
151
152 pub fn default_chain(&self) -> Option<ChainId> {
153 *self.0.default.read().unwrap()
154 }
155
156 pub fn set_default_chain(&mut self, id: ChainId) -> Result<(), persistent::file::Error> {
157 assert!(self.0.chains.get(id).is_some());
158 *self.0.default.write().unwrap() = Some(id);
159 self.0.save()
160 }
161
162 pub fn mutate<R>(
163 &self,
164 chain_id: ChainId,
165 mutate: impl Fn(&mut Chain) -> R,
166 ) -> Option<Result<R, persistent::file::Error>> {
167 self.0
168 .chains
169 .mutate(chain_id, mutate)
170 .map(|outcome| self.0.save().map(|()| outcome))
171 }
172
173 pub fn forget_keys(&self, chain_id: ChainId) -> anyhow::Result<AccountOwner> {
174 self.mutate(chain_id, |chain| chain.owner.take())
175 .ok_or_else(|| anyhow::anyhow!("nonexistent chain `{chain_id}`"))??
176 .ok_or_else(|| anyhow::anyhow!("keypair not found for chain `{chain_id}`"))
177 }
178
179 pub fn forget_chain(&self, chain_id: ChainId) -> anyhow::Result<Chain> {
180 let chain = self
181 .0
182 .chains
183 .remove(chain_id)
184 .ok_or_else(|| anyhow::anyhow!("nonexistent chain `{chain_id}`"))?;
185 self.0.save()?;
186 Ok(chain)
187 }
188
189 pub fn save(&self) -> Result<(), persistent::file::Error> {
190 self.0.save()
191 }
192
193 pub fn num_chains(&self) -> usize {
194 self.0.chains.items().len()
195 }
196
197 pub fn chain_ids(&self) -> Vec<ChainId> {
198 self.0.chains.chain_ids()
199 }
200
201 pub fn owned_chain_ids(&self) -> Vec<ChainId> {
203 self.0.chains.owned_chain_ids()
204 }
205
206 pub(crate) fn data(&self) -> &Data {
207 &self.0
208 }
209}