linera_core/environment/wallet/
memory.rs

1// Copyright (c) Zefchain Labs, Inc.
2// SPDX-License-Identifier: Apache-2.0
3
4use futures::{Stream, StreamExt as _};
5use linera_base::identifiers::ChainId;
6
7use super::{Chain, Wallet};
8
9/// A basic implementation of `Wallet` that doesn't persist anything and merely tracks the
10/// chains in memory.
11///
12/// This can be used as-is as an ephemeral wallet for testing or ephemeral clients, or as
13/// a building block for more complex wallets that layer persistence on top of it.
14#[derive(Default, Clone, serde::Serialize, serde::Deserialize)]
15pub struct Memory(papaya::HashMap<ChainId, Chain>);
16
17impl Memory {
18    pub fn get(&self, id: ChainId) -> Option<Chain> {
19        self.0.pin().get(&id).cloned()
20    }
21
22    pub fn insert(&self, id: ChainId, chain: Chain) -> Option<Chain> {
23        self.0.pin().insert(id, chain).cloned()
24    }
25
26    pub fn try_insert(&self, id: ChainId, chain: Chain) -> Option<Chain> {
27        match self.0.pin().try_insert(id, chain) {
28            Ok(_inserted) => None,
29            Err(error) => Some(error.not_inserted),
30        }
31    }
32
33    pub fn remove(&self, id: ChainId) -> Option<Chain> {
34        self.0.pin().remove(&id).cloned()
35    }
36
37    pub fn items(&self) -> Vec<(ChainId, Chain)> {
38        self.0
39            .pin()
40            .iter()
41            .map(|(id, chain)| (*id, chain.clone()))
42            .collect::<Vec<_>>()
43    }
44
45    pub fn chain_ids(&self) -> Vec<ChainId> {
46        self.0.pin().keys().copied().collect::<Vec<_>>()
47    }
48
49    pub fn owned_chain_ids(&self) -> Vec<ChainId> {
50        self.0
51            .pin()
52            .iter()
53            .filter_map(|(id, chain)| chain.owner.as_ref().map(|_| *id))
54            .collect::<Vec<_>>()
55    }
56
57    pub fn mutate<R>(
58        &self,
59        chain_id: ChainId,
60        mut mutate: impl FnMut(&mut Chain) -> R,
61    ) -> Option<R> {
62        use papaya::Operation::*;
63
64        let mut outcome = None;
65        self.0.pin().compute(chain_id, |chain| {
66            if let Some((_, chain)) = chain {
67                let mut chain = chain.clone();
68                outcome = Some(mutate(&mut chain));
69                Insert(chain)
70            } else {
71                Abort(())
72            }
73        });
74
75        outcome
76    }
77}
78
79impl Extend<(ChainId, Chain)> for Memory {
80    fn extend<It: IntoIterator<Item = (ChainId, Chain)>>(&mut self, chains: It) {
81        let map = self.0.pin();
82        for (id, chain) in chains {
83            let _ = map.insert(id, chain);
84        }
85    }
86}
87
88impl Wallet for Memory {
89    type Error = std::convert::Infallible;
90
91    async fn get(&self, id: ChainId) -> Result<Option<Chain>, Self::Error> {
92        Ok(self.get(id))
93    }
94
95    async fn insert(&self, id: ChainId, chain: Chain) -> Result<Option<Chain>, Self::Error> {
96        Ok(self.insert(id, chain))
97    }
98
99    async fn try_insert(&self, id: ChainId, chain: Chain) -> Result<Option<Chain>, Self::Error> {
100        Ok(self.try_insert(id, chain))
101    }
102
103    async fn remove(&self, id: ChainId) -> Result<Option<Chain>, Self::Error> {
104        Ok(self.remove(id))
105    }
106
107    fn items(&self) -> impl Stream<Item = Result<(ChainId, Chain), Self::Error>> {
108        futures::stream::iter(self.items()).map(Ok)
109    }
110
111    async fn modify(
112        &self,
113        id: ChainId,
114        f: impl FnMut(&mut Chain) + Send,
115    ) -> Result<Option<()>, Self::Error> {
116        Ok(self.mutate(id, f))
117    }
118}