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