Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(account): keep all accounts in memory #174

Merged
merged 31 commits into from
Dec 18, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
6c3e3ec
feat(manager): initial work on account guard
lucasfernog Dec 15, 2020
eef5039
feat(manager): adjust `get_account` to use the store
lucasfernog Dec 15, 2020
832166d
Merge branch 'develop' into fix/account-storage
lucasfernog Dec 15, 2020
3790e30
refactor(lib): use AccountGuard instead of Account
lucasfernog Dec 15, 2020
9a7685a
fix(lib): tests and examples compilation
lucasfernog Dec 15, 2020
e6ce170
fix(lib): tests
lucasfernog Dec 15, 2020
ab1fb18
chore(transfer): return message instead of wrapper
lucasfernog Dec 16, 2020
ca93f15
refactor(lib): update nodejs binding with latest account refactor
lucasfernog Dec 16, 2020
184d2d5
feat(account): add bridge methods to the guard
lucasfernog Dec 16, 2020
c8b93d0
Merge branch 'develop' into fix/account-storage
lucasfernog Dec 16, 2020
b11b3f8
fix(sync): deadlocks
lucasfernog Dec 16, 2020
6919b14
feat(bindings): add loadAccounts method
lucasfernog Dec 16, 2020
3cfb6a3
chore(lib): cleanup
lucasfernog Dec 16, 2020
f8aa72c
chore(transfer): lock write only when needed
lucasfernog Dec 16, 2020
6aa0430
chore(account): rename AccountGuard to AccountHandle
lucasfernog Dec 16, 2020
92f6d95
chore(lib): inline usage of account handle where appropriate
lucasfernog Dec 16, 2020
1d90529
chore(lib): rename AccountHandle variables to account_handle
lucasfernog Dec 16, 2020
9f5ed37
perf(manager): get accounts by alias method
lucasfernog Dec 16, 2020
b9c51b6
refactor(lib): use tokio's RwLock on AccountHandle
lucasfernog Dec 16, 2020
d7482fb
refactor(lib): use tokio's RwLock on Client
lucasfernog Dec 16, 2020
828cc23
refactor(lib): use tokio's RwLock on accountmanager accounts
lucasfernog Dec 16, 2020
9c0f561
feat(manager): use polling system with tokio instead of thread::spawn
lucasfernog Dec 16, 2020
bbc280c
chore(bindings): rename variable
lucasfernog Dec 16, 2020
285a326
refactor(account): perform mutable operations with `do_mut`
lucasfernog Dec 16, 2020
2a00b38
refactor(manager): remove `load_accounts` and `start_background_sync`
lucasfernog Dec 16, 2020
95fdca3
refactor(manager): change get_account_by_alias' alias type
lucasfernog Dec 16, 2020
09451b8
fix(tests): deadlock
lucasfernog Dec 17, 2020
c94b8ec
fix(tests): actor spawn
lucasfernog Dec 17, 2020
8e94f8e
fix(tests): doc tests
lucasfernog Dec 17, 2020
36c1140
code review changes
lucasfernog Dec 18, 2020
63eb171
fix(tests): deadlock
lucasfernog Dec 18, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ serde_repr = "0.1"
once_cell = "1.4"
iota-core = { git = "https://github.com/iotaledger/iota.rs", branch = "dev" }
url = { version = "2.1", features = [ "serde" ] }
tokio = "0.2"
tokio = { version = "0.2", features = ["macros", "sync"] }
rand = "0.3"
rusqlite = { version = "0.23", features = ["bundled"], optional = true }
slip10 = "0.4"
Expand Down
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,16 +80,18 @@ use iota_wallet::{
storage::sqlite::SqliteStorageAdapter,
};
use std::path::PathBuf;

#[tokio::main]
async fn main() -> iota_wallet::Result<()> {
let storage_folder: PathBuf = "./my-db".into();
let manager =
AccountManager::with_storage_adapter(&storage_folder, SqliteStorageAdapter::new(&storage_folder, "accounts")?)?;
AccountManager::with_storage_adapter(&storage_folder, SqliteStorageAdapter::new(&storage_folder, "accounts")?).await?;
let client_options = ClientOptionsBuilder::node("http://api.lb-0.testnet.chrysalis2.com")?.build();
let account = manager
.create_account(client_options)
.signer_type(SignerType::EnvMnemonic)
.initialise()?;
.initialise()
.await?;
Ok(())
}
```
Expand Down
4 changes: 0 additions & 4 deletions bindings/node/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,6 @@ Creates a new instance of the AccountManager.
| [storagePath] | <code>string</code> | <code>undefined</code> | The path where the database file will be saved |
| [storageType] | <code>number</code> | <code>undefined</code> | The type of the database. Stronghold = 1, Sqlite = 2 |

#### startBackgroundSync(): void

Initialises the background polling mechanism and MQTT monitoring. Automatically called on `setStrongholdPassword`.

#### setStrongholdPassword(password): void

Sets the stronghold password and initialises it.
Expand Down
1 change: 0 additions & 1 deletion bindings/node/lib/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,6 @@ export declare interface ManagerOptions {

export declare class AccountManager {
constructor(storagePath?: string)
startBackgroundSync(): void
setStrongholdPassword(password: string): void
createAccount(account: AccountToCreate): Account
getAccount(accountId: string | number): Account | undefined
Expand Down
138 changes: 63 additions & 75 deletions bindings/node/native/src/classes/account/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,39 +3,26 @@

use std::str::FromStr;

use iota_wallet::{
account::{Account, AccountIdentifier},
message::MessageId,
};
use iota_wallet::{account::AccountIdentifier, message::MessageId};
use neon::prelude::*;

mod sync;

pub struct AccountWrapper(pub String);

impl Drop for AccountWrapper {
fn drop(&mut self) {
crate::remove_account(&self.0);
}
}
pub struct AccountWrapper(pub AccountIdentifier);

declare_types! {
pub class JsAccount for AccountWrapper {
init(mut cx) {
let account = cx.argument::<JsString>(0)?.value();
let account: Account = serde_json::from_str(&account).expect("invalid account JSON");
let id = crate::store_account(account);
Ok(AccountWrapper(id))
let account_id = cx.argument::<JsString>(0)?.value();
Ok(AccountWrapper(serde_json::from_str(&account_id).expect("invalid account identifier")))
}

method id(mut cx) {
let id = {
let this = cx.this();
let guard = cx.lock();
let id = &this.borrow(&guard).0;
let account = crate::get_account(id);
let account = account.read().unwrap();
account.id().clone()
id.clone()
};

match id {
Expand All @@ -49,9 +36,8 @@ declare_types! {
let this = cx.this();
let guard = cx.lock();
let id = &this.borrow(&guard).0;
let account = crate::get_account(id);
let account = account.read().unwrap();
*account.index()
let account_handle = crate::get_account(id);
crate::block_on(async move { account_handle.index().await })
};

Ok(cx.number(index as f64).upcast())
Expand All @@ -62,9 +48,8 @@ declare_types! {
let this = cx.this();
let guard = cx.lock();
let id = &this.borrow(&guard).0;
let account = crate::get_account(id);
let account = account.read().unwrap();
account.alias().clone()
let account_handle = crate::get_account(id);
crate::block_on(async move { account_handle.alias().await })
};

Ok(cx.string(alias).upcast())
Expand All @@ -75,9 +60,8 @@ declare_types! {
let this = cx.this();
let guard = cx.lock();
let id = &this.borrow(&guard).0;
let account = crate::get_account(id);
let account = account.read().unwrap();
account.available_balance()
let account_handle = crate::get_account(id);
crate::block_on(async move { account_handle.available_balance().await })
};
Ok(cx.number(balance as f64).upcast())
}
Expand All @@ -87,9 +71,8 @@ declare_types! {
let this = cx.this();
let guard = cx.lock();
let id = &this.borrow(&guard).0;
let account = crate::get_account(id);
let account = account.read().unwrap();
account.total_balance()
let account_handle = crate::get_account(id);
crate::block_on(async move { account_handle.total_balance().await })
};
Ok(cx.number(balance as f64).upcast())
}
Expand All @@ -113,17 +96,19 @@ declare_types! {

let this = cx.this();
let id = cx.borrow(&this, |r| r.0.clone());
let account = crate::get_account(&id);
let account = account.read().unwrap();
let messages = account.list_messages(count, from, filter);

let js_array = JsArray::new(&mut cx, messages.len() as u32);
for (index, message) in messages.iter().enumerate() {
let value = neon_serde::to_value(&mut cx, &message)?;
js_array.set(&mut cx, index as u32, value)?;
}
let account_handle = crate::get_account(&id);
crate::block_on(async move {
let account = account_handle.read().await;
let messages = account.list_messages(count, from, filter);

let js_array = JsArray::new(&mut cx, messages.len() as u32);
for (index, message) in messages.iter().enumerate() {
let value = neon_serde::to_value(&mut cx, &message)?;
js_array.set(&mut cx, index as u32, value)?;
}

Ok(js_array.upcast())
Ok(js_array.upcast())
})
}

method listAddresses(mut cx) {
Expand All @@ -134,17 +119,19 @@ declare_types! {

let this = cx.this();
let id = cx.borrow(&this, |r| r.0.clone());
let account = crate::get_account(&id);
let account = account.read().unwrap();
let addresses = account.list_addresses(unspent);

let js_array = JsArray::new(&mut cx, addresses.len() as u32);
for (index, address) in addresses.iter().enumerate() {
let value = neon_serde::to_value(&mut cx, &address)?;
js_array.set(&mut cx, index as u32, value)?;
}
let account_handle = crate::get_account(&id);
crate::block_on(async move {
let account = account_handle.read().await;
let addresses = account.list_addresses(unspent);

let js_array = JsArray::new(&mut cx, addresses.len() as u32);
for (index, address) in addresses.iter().enumerate() {
let value = neon_serde::to_value(&mut cx, &address)?;
js_array.set(&mut cx, index as u32, value)?;
}

Ok(js_array.upcast())
Ok(js_array.upcast())
})
}

method setAlias(mut cx) {
Expand All @@ -153,10 +140,8 @@ declare_types! {
let this = cx.this();
let guard = cx.lock();
let id = &this.borrow(&guard).0;
let account = crate::get_account(id);
let mut account = account.write().unwrap();
account.set_alias(alias);
account.save_pending_changes().expect("failed to save account");
let account_handle = crate::get_account(id);
crate::block_on(async move { account_handle.set_alias(alias).await; });
}
Ok(cx.undefined().upcast())
}
Expand All @@ -168,10 +153,8 @@ declare_types! {
let this = cx.this();
let guard = cx.lock();
let id = &this.borrow(&guard).0;
let account = crate::get_account(id);
let mut account = account.write().unwrap();
account.set_client_options(client_options);
account.save_pending_changes().expect("failed to save account");
let account_handle = crate::get_account(id);
crate::block_on(async move { account_handle.set_client_options(client_options).await; });
}
Ok(cx.undefined().upcast())
}
Expand All @@ -180,37 +163,42 @@ declare_types! {
let message_id = MessageId::from_str(cx.argument::<JsString>(0)?.value().as_str()).expect("invalid message id length");
let this = cx.this();
let id = cx.borrow(&this, |r| r.0.clone());
let account = crate::get_account(&id);
let account = account.read().unwrap();
let message = account.get_message(&message_id);
match message {
Some(m) => Ok(neon_serde::to_value(&mut cx, &m)?),
None => Ok(cx.undefined().upcast())
}
crate::block_on(async move {
let account_handle = crate::get_account(&id);
let account = account_handle.read().await;
let message = account.get_message(&message_id);
match message {
Some(m) => Ok(neon_serde::to_value(&mut cx, &m)?),
None => Ok(cx.undefined().upcast())
}
})
}

method generateAddress(mut cx) {
let address = {
let this = cx.this();
let guard = cx.lock();
let id = &this.borrow(&guard).0;
let account = crate::get_account(id);
let mut account = account.write().unwrap();
account.generate_address().expect("error generating address")
crate::block_on(async move {
let account_handle = crate::get_account(id);
account_handle.generate_address().await.expect("error generating address")
})
};
Ok(neon_serde::to_value(&mut cx, &address)?)
}

method latestAddress(mut cx) {
let this = cx.this();
let id = cx.borrow(&this, |r| r.0.clone());
let account = crate::get_account(&id);
let account = account.read().unwrap();
let address = account.latest_address();
match address {
Some(a) => Ok(neon_serde::to_value(&mut cx, &a)?),
None => Ok(cx.undefined().upcast())
}
crate::block_on(async move {
let account_handle = crate::get_account(&id);
let account = account_handle.read().await;
let address = account.latest_address();
match address {
Some(a) => Ok(neon_serde::to_value(&mut cx, &a)?),
None => Ok(cx.undefined().upcast())
}
})
}

method sync(mut cx) {
Expand Down
43 changes: 23 additions & 20 deletions bindings/node/native/src/classes/account/sync.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
// Copyright 2020 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

use iota_wallet::{account::SyncedAccount, WalletError};
use iota_wallet::{
account::{AccountIdentifier, SyncedAccount},
WalletError,
};
use neon::prelude::*;
use serde::Deserialize;

Expand All @@ -16,7 +19,7 @@ pub struct SyncOptions {
}

pub struct SyncTask {
pub account_id: String,
pub account_id: AccountIdentifier,
pub options: SyncOptions,
}

Expand All @@ -26,30 +29,30 @@ impl Task for SyncTask {
type JsEvent = JsValue;

fn perform(&self) -> Result<Self::Output, Self::Error> {
let account = crate::get_account(&self.account_id);
let mut acc = account.write().unwrap();
let mut synchronizer = acc.sync();
if let Some(address_index) = self.options.address_index {
synchronizer = synchronizer.address_index(address_index);
}
if let Some(gap_limit) = self.options.gap_limit {
synchronizer = synchronizer.gap_limit(gap_limit);
}
if let Some(skip_persistance) = self.options.skip_persistance {
if skip_persistance {
synchronizer = synchronizer.skip_persistance();
crate::block_on(async move {
let account = crate::get_account(&self.account_id);
let mut synchronizer = account.sync().await;
if let Some(address_index) = self.options.address_index {
synchronizer = synchronizer.address_index(address_index);
}
}
crate::block_on(crate::convert_async_panics(|| async { synchronizer.execute().await }))
if let Some(gap_limit) = self.options.gap_limit {
synchronizer = synchronizer.gap_limit(gap_limit);
}
if let Some(skip_persistance) = self.options.skip_persistance {
if skip_persistance {
synchronizer = synchronizer.skip_persistance();
}
}
synchronizer.execute().await
})
}

fn complete(self, mut cx: TaskContext, value: Result<Self::Output, Self::Error>) -> JsResult<Self::JsEvent> {
match value {
Ok(val) => {
let synced = serde_json::to_string(&val).unwrap();
let synced = cx.string(synced);
let account_id = cx.string(&self.account_id);
Ok(crate::JsSyncedAccount::new(&mut cx, vec![synced, account_id])?.upcast())
let id = crate::store_synced_account(val);
let id = cx.string(id);
Ok(crate::JsSyncedAccount::new(&mut cx, vec![id])?.upcast())
}
Err(e) => cx.throw_error(e.to_string()),
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@

use std::sync::{Arc, RwLock};

use iota_wallet::{account_manager::AccountManager, message::Message, WalletError};
use iota_wallet::{account::AccountIdentifier, account_manager::AccountManager, message::Message, WalletError};
use neon::prelude::*;

pub struct InternalTransferTask {
pub manager: Arc<RwLock<AccountManager>>,
pub from_account_id: String,
pub to_account_id: String,
pub from_account_id: AccountIdentifier,
pub to_account_id: AccountIdentifier,
pub amount: u64,
}

Expand All @@ -21,18 +21,9 @@ impl Task for InternalTransferTask {
fn perform(&self) -> Result<Self::Output, Self::Error> {
let manager = self.manager.read().unwrap();
crate::block_on(crate::convert_async_panics(|| async {
let from_account = crate::get_account(&self.from_account_id);
let from_account = from_account.read().unwrap();
let to_account = crate::get_account(&self.to_account_id);
let to_account = to_account.read().unwrap();
let res = manager
.internal_transfer(from_account.id(), to_account.id(), self.amount)
.await?;

crate::update_account(&self.from_account_id, res.from_account);
crate::update_account(&self.to_account_id, res.to_account);

Ok(res.message)
manager
.internal_transfer(&self.from_account_id, &self.to_account_id, self.amount)
.await
}))
}

Expand Down
Loading