Skip to content
This repository was archived by the owner on Feb 3, 2025. It is now read-only.

Commit 46b0194

Browse files
Windowless sleep (#757)
* windowless sleep * web-sys is just for dev now * Remove local storage * Use crates release * Use utils from mutiny-core --------- Co-authored-by: benthecarman <benthecarman@live.com>
1 parent 71fbc97 commit 46b0194

8 files changed

Lines changed: 140 additions & 384 deletions

File tree

Cargo.lock

Lines changed: 114 additions & 117 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

mutiny-core/Cargo.toml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,11 +69,14 @@ test-utils = []
6969
[target.'cfg(target_arch = "wasm32")'.dependencies]
7070
wasm-bindgen = "0.2.84"
7171
wasm-bindgen-futures = { version = "0.4.33" }
72-
web-sys = { version = "0.3.60", features = ["console"] }
7372
js-sys = { version = "0.3.60" }
7473
gloo-net = { version = "0.2.4" }
7574
instant = { version = "0.1", features = ["wasm-bindgen"] }
7675
getrandom = { version = "0.2", features = ["js"] }
76+
windowless_sleep = "0.1.1"
77+
78+
[target.'cfg(target_arch = "wasm32")'.dev-dependencies]
79+
web-sys = { version = "0.3.60", features = ["console"] }
7780

7881
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
7982
tokio = { version = "1", features = ["rt"] }

mutiny-core/src/utils.rs

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -24,21 +24,13 @@ pub(crate) fn min_lightning_amount(network: Network) -> u64 {
2424
pub async fn sleep(millis: i32) {
2525
#[cfg(target_arch = "wasm32")]
2626
{
27-
let mut cb = |resolve: js_sys::Function, _reject: js_sys::Function| {
28-
web_sys::window()
29-
.unwrap()
30-
.set_timeout_with_callback_and_timeout_and_arguments_0(&resolve, millis)
31-
.unwrap();
32-
};
33-
let p = js_sys::Promise::new(&mut cb);
34-
wasm_bindgen_futures::JsFuture::from(p).await.unwrap();
27+
windowless_sleep::sleep(millis).await;
3528
}
3629
#[cfg(not(target_arch = "wasm32"))]
3730
{
3831
tokio::time::sleep(Duration::from_millis(millis.try_into().unwrap())).await;
3932
}
4033
}
41-
4234
pub fn now() -> Duration {
4335
#[cfg(target_arch = "wasm32")]
4436
return instant::SystemTime::now()

mutiny-wasm/Cargo.toml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,14 +34,13 @@ wasm-logger = "0.2.0"
3434
log = "0.4.17"
3535
rexie = "0.4"
3636
js-sys = "0.3.60"
37-
gloo-storage = "0.2.2"
3837
gloo-utils = { version = "0.1.6", features = ["serde"] }
39-
web-sys = { version = "0.3.60", features = ["console"] }
4038
bip39 = { version = "2.0.0" }
4139
getrandom = { version = "0.2", features = ["js"] }
4240
futures = "0.3.25"
4341
urlencoding = "2.1.2"
4442
once_cell = "1.18.0"
43+
windowless_sleep = "0.1.1"
4544

4645
# The `console_error_panic_hook` crate provides better debugging of panics by
4746
# logging them with `console.error`. This is great for development, but requires
@@ -52,9 +51,10 @@ console_error_panic_hook = { version = "0.1.6", optional = true }
5251
[dev-dependencies]
5352
mutiny-core = { path = "../mutiny-core", features = ["test-utils"] }
5453
wasm-bindgen-test = "0.3.33"
54+
web-sys = { version = "0.3.60", features = ["console"] }
5555

5656
[features]
57-
default = [ ]
57+
default = []
5858

5959
[package.metadata.wasm-pack.profile.release]
6060
wasm-opt = true

mutiny-wasm/src/indexed_db.rs

Lines changed: 8 additions & 225 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
use anyhow::anyhow;
22
use bip39::Mnemonic;
3-
use gloo_storage::{LocalStorage, Storage};
43
use gloo_utils::format::JsValueSerdeExt;
54
use lightning::util::logger::Logger;
65
use lightning::{log_debug, log_error};
@@ -265,26 +264,6 @@ impl IndexedDbStorage {
265264
map.set(key, json)?;
266265
}
267266

268-
// get the local storage data, this should take priority if it is being used
269-
log_debug!(logger, "Reading from local storage");
270-
let local_storage = LocalStorage::raw();
271-
let length = LocalStorage::length();
272-
for index in 0..length {
273-
let key_opt: Option<String> = local_storage.key(index).unwrap();
274-
275-
if let Some(key) = key_opt {
276-
// only add to the map if it is a key we expect
277-
// this is to prevent any unexpected data from being added to the map
278-
// from either malicious 3rd party or a previous version of the wallet
279-
if write_to_local_storage(&key) {
280-
// compare versions between local storage and indexed db storage
281-
if let Some((key, value)) = Self::handle_local_storage_key(key, &map, logger)? {
282-
map.set_data(key, value, None)?;
283-
}
284-
}
285-
}
286-
}
287-
288267
match vss {
289268
None => {
290269
let final_map = map.memory.read().unwrap();
@@ -309,76 +288,6 @@ impl IndexedDbStorage {
309288
}
310289
}
311290

312-
fn handle_local_storage_key(
313-
key: String,
314-
current: &MemoryStorage,
315-
logger: &MutinyLogger,
316-
) -> Result<Option<(String, Value)>, MutinyError> {
317-
if key.starts_with(MONITORS_PREFIX_KEY) {
318-
// we can get versions from monitors, so we should compare
319-
match current.get::<Vec<u8>>(&key)? {
320-
Some(bytes) => {
321-
// check first byte is 1, then take u64 from next 8 bytes
322-
let current_version = utils::get_monitor_version(&bytes);
323-
324-
let obj: Value = LocalStorage::get(&key).unwrap();
325-
let value = decrypt_value(&key, obj, current.password())?;
326-
if let Ok(local_bytes) = serde_json::from_value::<Vec<u8>>(value.clone()) {
327-
let local_version = utils::get_monitor_version(&local_bytes);
328-
329-
// if the current version is less than the version from local storage
330-
// then we want to use the local storage version
331-
if current_version < local_version {
332-
log_debug!(
333-
logger,
334-
"Using local storage key {key} with version {}",
335-
local_version
336-
);
337-
return Ok(Some((key, value)));
338-
}
339-
}
340-
}
341-
None => {
342-
let value: Value = LocalStorage::get(&key).unwrap();
343-
return Ok(Some((key, value)));
344-
}
345-
}
346-
} else if key.starts_with(CHANNEL_MANAGER_KEY) {
347-
// we can get versions from channel manager, so we should compare
348-
match current.get_data::<VersionedValue>(&key) {
349-
Ok(Some(local)) => {
350-
let obj: Value = LocalStorage::get(&key).unwrap();
351-
let value = decrypt_value(&key, obj, current.password())?;
352-
353-
// if the current version is less than the version from local storage
354-
// then we want to use the local storage version
355-
if let Ok(v) = serde_json::from_value::<VersionedValue>(value.clone()) {
356-
if v.version > local.version {
357-
log_debug!(
358-
logger,
359-
"Using local storage key {key} with version {}",
360-
v.version
361-
);
362-
return Ok(Some((key, value)));
363-
}
364-
}
365-
}
366-
Ok(None) => {
367-
let obj: Value = LocalStorage::get(&key).unwrap();
368-
let value = decrypt_value(&key, obj, current.password())?;
369-
if serde_json::from_value::<VersionedValue>(value.clone()).is_ok() {
370-
return Ok(Some((key, value)));
371-
}
372-
}
373-
Err(_) => return Err(MutinyError::IncorrectPassword),
374-
}
375-
}
376-
377-
log_debug!(logger, "Skipping local storage key {key}");
378-
379-
Ok(None)
380-
}
381-
382291
async fn handle_vss_key(
383292
kv: KeyVersion,
384293
vss: &MutinyVssClient,
@@ -544,18 +453,6 @@ fn used_once(key: &str) -> bool {
544453
}
545454
}
546455

547-
/// To help prevent force closes we save to local storage as well as indexed db.
548-
/// This is because indexed db is not always reliable.
549-
///
550-
/// We need to do this for the channel manager and channel monitors.
551-
fn write_to_local_storage(key: &str) -> bool {
552-
match key {
553-
str if str.starts_with(CHANNEL_MANAGER_KEY) => true,
554-
str if str.starts_with(MONITORS_PREFIX_KEY) => true,
555-
_ => false,
556-
}
557-
}
558-
559456
impl MutinyStorage for IndexedDbStorage {
560457
fn password(&self) -> Option<&str> {
561458
self.password.as_deref()
@@ -588,15 +485,6 @@ impl MutinyStorage for IndexedDbStorage {
588485
};
589486
});
590487

591-
// Some values we want to write to local storage as well as indexed db
592-
if write_to_local_storage(&key) {
593-
LocalStorage::set(&key, &data).map_err(|e| {
594-
MutinyError::write_err(MutinyStorageError::Other(anyhow!(
595-
"Failed to write to local storage: {e}"
596-
)))
597-
})?;
598-
}
599-
600488
// some values only are read once, so we don't need to write them to memory,
601489
// just need them in indexed db for next time
602490
if !used_once(key.as_ref()) {
@@ -621,15 +509,6 @@ impl MutinyStorage for IndexedDbStorage {
621509

622510
Self::save_to_indexed_db(&self.indexed_db, &key, &data).await?;
623511

624-
// Some values we want to write to local storage as well as indexed db
625-
if write_to_local_storage(&key) {
626-
LocalStorage::set(&key, &data).map_err(|e| {
627-
MutinyError::write_err(MutinyStorageError::Other(anyhow!(
628-
"Failed to write to local storage: {e}"
629-
)))
630-
})?;
631-
}
632-
633512
// some values only are read once, so we don't need to write them to memory,
634513
// just need them in indexed db for next time
635514
if !used_once(key.as_ref()) {
@@ -695,11 +574,6 @@ impl MutinyStorage for IndexedDbStorage {
695574
.map_err(|e| MutinyError::write_err(e.into()))?;
696575

697576
for key in keys {
698-
// Some values we want to write to local storage as well as indexed db
699-
// we should delete them from local storage as well
700-
if write_to_local_storage(&key) {
701-
LocalStorage::delete(&key)
702-
}
703577
map.remove(&key);
704578
}
705579

@@ -818,9 +692,6 @@ impl MutinyStorage for IndexedDbStorage {
818692
.await
819693
.map_err(|e| MutinyError::write_err(anyhow!("Failed clear indexed db: {e}").into()))?;
820694

821-
// We use some localstorage right now for ensuring channel data
822-
LocalStorage::clear();
823-
824695
Ok(())
825696
}
826697

@@ -839,20 +710,15 @@ impl MutinyStorage for IndexedDbStorage {
839710
#[cfg(test)]
840711
mod tests {
841712
use super::*;
842-
use crate::indexed_db::{IndexedDbStorage, WALLET_OBJECT_STORE_NAME};
843-
use crate::utils::sleep;
713+
use crate::indexed_db::IndexedDbStorage;
844714
use crate::utils::test::log;
845715
use bip39::Mnemonic;
846-
use bitcoin::hashes::hex::ToHex;
847-
use gloo_storage::{LocalStorage, Storage};
848716
use mutiny_core::storage::MutinyStorage;
849-
use mutiny_core::test_utils::{MANAGER_BYTES, MONITOR_VERSION_HIGHER, MONITOR_VERSION_LOWER};
717+
use mutiny_core::utils::sleep;
850718
use mutiny_core::{encrypt::encryption_key_from_pass, logging::MutinyLogger};
851-
use rexie::TransactionMode;
852719
use serde_json::json;
853720
use std::str::FromStr;
854721
use std::sync::Arc;
855-
use wasm_bindgen::JsValue;
856722
use wasm_bindgen_test::{wasm_bindgen_test as test, wasm_bindgen_test_configure};
857723

858724
wasm_bindgen_test_configure!(run_in_browser);
@@ -1018,102 +884,17 @@ mod tests {
1018884
IndexedDbStorage::clear().await.unwrap();
1019885
}
1020886

1021-
async fn compare_local_storage_versions(
1022-
test_name: &str,
1023-
local_storage: Vec<u8>,
1024-
indexed_db: Vec<u8>,
1025-
) -> Vec<u8> {
1026-
let key = format!("{MONITORS_PREFIX_KEY}test_{test_name}");
1027-
// set in local storage
1028-
LocalStorage::set(&key, local_storage).unwrap();
1029-
// set in indexed db
1030-
let rexie = IndexedDbStorage::build_indexed_db_database().await.unwrap();
1031-
let tx = rexie
1032-
.transaction(&[WALLET_OBJECT_STORE_NAME], TransactionMode::ReadWrite)
1033-
.unwrap();
1034-
let store = tx.store(WALLET_OBJECT_STORE_NAME).unwrap();
1035-
store
1036-
.put(
1037-
&JsValue::from_serde(&indexed_db).unwrap(),
1038-
Some(&JsValue::from(&key)),
1039-
)
1040-
.await
1041-
.unwrap();
1042-
1043-
tx.done().await.unwrap();
1044-
1045-
let logger = Arc::new(MutinyLogger::default());
1046-
let storage = IndexedDbStorage::new(None, None, None, logger)
1047-
.await
1048-
.unwrap();
1049-
1050-
let bytes: Vec<u8> = storage.get(&key).unwrap().unwrap();
1051-
1052-
// clear the storage to clean up
1053-
IndexedDbStorage::clear().await.unwrap();
1054-
1055-
bytes
1056-
}
1057-
1058-
#[test]
1059-
async fn test_local_storage_version_0_indexed_db_version_max() {
1060-
let test_name = "test_local_storage_version_0_indexed_db_version_max";
1061-
log!("{test_name}");
1062-
1063-
let bytes = compare_local_storage_versions(
1064-
test_name,
1065-
MONITOR_VERSION_LOWER.to_vec(),
1066-
MONITOR_VERSION_HIGHER.to_vec(),
1067-
)
1068-
.await;
1069-
assert_eq!(bytes, MONITOR_VERSION_HIGHER);
1070-
}
1071-
1072-
#[test]
1073-
async fn test_local_storage_version_max_indexed_db_version_0() {
1074-
let test_name = "test_local_storage_version_max_indexed_db_version_0";
1075-
log!("{test_name}");
1076-
1077-
let bytes = compare_local_storage_versions(
1078-
test_name,
1079-
MONITOR_VERSION_HIGHER.to_vec(),
1080-
MONITOR_VERSION_LOWER.to_vec(),
1081-
)
1082-
.await;
1083-
assert_eq!(bytes, MONITOR_VERSION_HIGHER);
1084-
}
1085-
1086-
#[test]
1087-
async fn test_local_storage_version_max_indexed_db_version_max() {
1088-
let test_name = "test_local_storage_version_max_indexed_db_version_max";
1089-
log!("{test_name}");
1090-
1091-
let bytes = compare_local_storage_versions(
1092-
test_name,
1093-
MONITOR_VERSION_HIGHER.to_vec(),
1094-
MONITOR_VERSION_HIGHER.to_vec(),
1095-
)
1096-
.await;
1097-
assert_eq!(bytes, MONITOR_VERSION_HIGHER);
1098-
}
1099-
1100887
#[test]
1101888
async fn test_correct_incorrect_password_error() {
1102889
let test_name = "test_correct_incorrect_password_error";
1103890
log!("{test_name}");
1104891
let logger = Arc::new(MutinyLogger::default());
1105892

1106-
let key = format!("{CHANNEL_MANAGER_KEY}_test_{test_name}");
1107-
let data = VersionedValue {
1108-
version: 69,
1109-
// just use this as dummy data
1110-
value: Value::String(MANAGER_BYTES.to_hex()),
1111-
};
1112893
let storage = IndexedDbStorage::new(None, None, None, logger.clone())
1113894
.await
1114895
.unwrap();
1115-
1116-
storage.set_data(&key, data, None).unwrap();
896+
let seed = generate_seed(12).unwrap();
897+
storage.set_data(MNEMONIC_KEY, seed, None).unwrap();
1117898
// wait for the storage to be persisted
1118899
utils::sleep(1_000).await;
1119900

@@ -1125,9 +906,11 @@ mod tests {
1125906
.transpose()
1126907
.unwrap();
1127908

1128-
let result = IndexedDbStorage::new(password, cipher, None, logger).await;
909+
let storage = IndexedDbStorage::new(password, cipher, None, logger)
910+
.await
911+
.unwrap();
1129912

1130-
match result {
913+
match storage.get_mnemonic() {
1131914
Err(MutinyError::IncorrectPassword) => (),
1132915
Ok(_) => panic!("Expected IncorrectPassword error, got Ok"),
1133916
Err(e) => panic!("Expected IncorrectPassword error, got {:?}", e),

0 commit comments

Comments
 (0)