mirror of
https://github.com/logos-blockchain/lssa.git
synced 2026-01-02 13:23:10 +00:00
feat: keys restoration from mnemonic
This commit is contained in:
parent
6cbc5028cf
commit
e92ad2132f
@ -3,6 +3,7 @@ use std::{
|
||||
collections::HashMap,
|
||||
path::PathBuf,
|
||||
pin::Pin,
|
||||
str::FromStr,
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
|
||||
@ -1647,6 +1648,136 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
info!("Success!");
|
||||
}
|
||||
|
||||
#[nssa_integration_test]
|
||||
pub async fn test_keys_restoration() {
|
||||
info!("########## test_keys_restoration ##########");
|
||||
let from: Address = ACC_SENDER_PRIVATE.parse().unwrap();
|
||||
|
||||
let command = Command::Account(AccountSubcommand::New(NewSubcommand::Private {
|
||||
cci: ChainIndex::root(),
|
||||
}));
|
||||
|
||||
let sub_ret = wallet::execute_subcommand(command).await.unwrap();
|
||||
let SubcommandReturnValue::RegisterAccount { addr: to_addr1 } = sub_ret else {
|
||||
panic!("FAILED TO REGISTER ACCOUNT");
|
||||
};
|
||||
|
||||
let command = Command::Account(AccountSubcommand::New(NewSubcommand::Private {
|
||||
cci: ChainIndex::from_str("/0").unwrap(),
|
||||
}));
|
||||
|
||||
let sub_ret = wallet::execute_subcommand(command).await.unwrap();
|
||||
let SubcommandReturnValue::RegisterAccount { addr: to_addr2 } = sub_ret else {
|
||||
panic!("FAILED TO REGISTER ACCOUNT");
|
||||
};
|
||||
|
||||
let command = Command::AuthTransfer(AuthTransferSubcommand::Send {
|
||||
from: make_private_account_input_from_str(&from.to_string()),
|
||||
to: Some(make_private_account_input_from_str(&to_addr1.to_string())),
|
||||
to_npk: None,
|
||||
to_ipk: None,
|
||||
amount: 100,
|
||||
});
|
||||
|
||||
wallet::execute_subcommand(command).await.unwrap();
|
||||
|
||||
let command = Command::AuthTransfer(AuthTransferSubcommand::Send {
|
||||
from: make_private_account_input_from_str(&from.to_string()),
|
||||
to: Some(make_private_account_input_from_str(&to_addr2.to_string())),
|
||||
to_npk: None,
|
||||
to_ipk: None,
|
||||
amount: 100,
|
||||
});
|
||||
|
||||
wallet::execute_subcommand(command).await.unwrap();
|
||||
|
||||
let from: Address = ACC_SENDER.parse().unwrap();
|
||||
|
||||
let command = Command::Account(AccountSubcommand::New(NewSubcommand::Public {
|
||||
cci: ChainIndex::root(),
|
||||
}));
|
||||
|
||||
let sub_ret = wallet::execute_subcommand(command).await.unwrap();
|
||||
let SubcommandReturnValue::RegisterAccount { addr: to_addr3 } = sub_ret else {
|
||||
panic!("FAILED TO REGISTER ACCOUNT");
|
||||
};
|
||||
|
||||
let command = Command::Account(AccountSubcommand::New(NewSubcommand::Public {
|
||||
cci: ChainIndex::from_str("/0").unwrap(),
|
||||
}));
|
||||
|
||||
let sub_ret = wallet::execute_subcommand(command).await.unwrap();
|
||||
let SubcommandReturnValue::RegisterAccount { addr: to_addr4 } = sub_ret else {
|
||||
panic!("FAILED TO REGISTER ACCOUNT");
|
||||
};
|
||||
|
||||
let command = Command::AuthTransfer(AuthTransferSubcommand::Send {
|
||||
from: make_public_account_input_from_str(&from.to_string()),
|
||||
to: Some(make_public_account_input_from_str(&to_addr3.to_string())),
|
||||
to_npk: None,
|
||||
to_ipk: None,
|
||||
amount: 100,
|
||||
});
|
||||
|
||||
wallet::execute_subcommand(command).await.unwrap();
|
||||
|
||||
let command = Command::AuthTransfer(AuthTransferSubcommand::Send {
|
||||
from: make_public_account_input_from_str(&from.to_string()),
|
||||
to: Some(make_public_account_input_from_str(&to_addr4.to_string())),
|
||||
to_npk: None,
|
||||
to_ipk: None,
|
||||
amount: 100,
|
||||
});
|
||||
|
||||
wallet::execute_subcommand(command).await.unwrap();
|
||||
|
||||
info!("########## PREPARATION END ##########");
|
||||
|
||||
wallet::execute_keys_restoration("test_pass".to_string(), 10)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let wallet_config = fetch_config().await.unwrap();
|
||||
let wallet_storage = WalletCore::start_from_config_update_chain(wallet_config.clone())
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
assert!(
|
||||
wallet_storage
|
||||
.storage
|
||||
.user_data
|
||||
.private_key_tree
|
||||
.get_node(to_addr1)
|
||||
.is_some()
|
||||
);
|
||||
assert!(
|
||||
wallet_storage
|
||||
.storage
|
||||
.user_data
|
||||
.private_key_tree
|
||||
.get_node(to_addr2)
|
||||
.is_some()
|
||||
);
|
||||
assert!(
|
||||
wallet_storage
|
||||
.storage
|
||||
.user_data
|
||||
.public_key_tree
|
||||
.get_node(to_addr3)
|
||||
.is_some()
|
||||
);
|
||||
assert!(
|
||||
wallet_storage
|
||||
.storage
|
||||
.user_data
|
||||
.public_key_tree
|
||||
.get_node(to_addr4)
|
||||
.is_some()
|
||||
);
|
||||
|
||||
info!("Success!");
|
||||
}
|
||||
|
||||
println!("{function_map:#?}");
|
||||
|
||||
function_map
|
||||
|
||||
@ -42,10 +42,13 @@ impl FromStr for ChainIndex {
|
||||
impl Display for ChainIndex {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "/")?;
|
||||
for cci in &self.0[..(self.0.len() - 1)] {
|
||||
write!(f, "{cci}/")?;
|
||||
if *self != Self::root() {
|
||||
for cci in &self.0[..(self.0.len() - 1)] {
|
||||
write!(f, "{cci}/")?;
|
||||
}
|
||||
write!(f, "{}", self.0.last().unwrap())?;
|
||||
}
|
||||
write!(f, "{}", self.0.last().unwrap())
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@ -74,6 +77,16 @@ impl ChainIndex {
|
||||
|
||||
ChainIndex(chain)
|
||||
}
|
||||
|
||||
pub fn depth(&self) -> u32 {
|
||||
let mut res = 0;
|
||||
|
||||
for cci in &self.0 {
|
||||
res += cci + 1;
|
||||
}
|
||||
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@ -1,5 +1,10 @@
|
||||
use std::collections::{BTreeMap, HashMap};
|
||||
use std::{
|
||||
collections::{BTreeMap, HashMap},
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
use anyhow::Result;
|
||||
use common::sequencer_client::SequencerClient;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::key_management::{
|
||||
@ -128,24 +133,80 @@ impl<Node: KeyNode> KeyTree<Node> {
|
||||
self.key_map.insert(chain_index, node);
|
||||
}
|
||||
|
||||
pub fn remove(&mut self, addr: nssa::Address) -> Option<Node> {
|
||||
let chain_index = self.addr_map.remove(&addr).unwrap();
|
||||
self.key_map.remove(&chain_index)
|
||||
}
|
||||
|
||||
pub fn generate_tree_for_depth(&mut self, depth: u32) {
|
||||
let mut id_stack = vec![ChainIndex::root()];
|
||||
|
||||
while !id_stack.is_empty() {
|
||||
let curr_id = id_stack.pop().unwrap();
|
||||
|
||||
while let Some(curr_id) = id_stack.pop() {
|
||||
self.generate_new_node(curr_id.clone());
|
||||
|
||||
let mut next_id = curr_id.n_th_child(0);
|
||||
|
||||
while (next_id.chain().iter().sum::<u32>()) < depth - 1 {
|
||||
while (next_id.depth()) < depth - 1 {
|
||||
id_stack.push(next_id.clone());
|
||||
next_id = next_id.next_in_line();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl KeyTree<ChildKeysPrivate> {
|
||||
pub fn cleanup_tree_for_depth(&mut self, depth: u32) {
|
||||
let mut id_stack = vec![ChainIndex::root()];
|
||||
|
||||
while let Some(curr_id) = id_stack.pop() {
|
||||
if let Some(node) = self.key_map.get(&curr_id)
|
||||
&& node.value.1 == nssa::Account::default()
|
||||
&& curr_id != ChainIndex::root()
|
||||
{
|
||||
let addr = node.address();
|
||||
self.remove(addr);
|
||||
}
|
||||
|
||||
let mut next_id = curr_id.n_th_child(0);
|
||||
|
||||
while (next_id.depth()) < depth - 1 {
|
||||
id_stack.push(next_id.clone());
|
||||
next_id = next_id.next_in_line();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl KeyTree<ChildKeysPublic> {
|
||||
pub async fn cleanup_tree_for_depth(
|
||||
&mut self,
|
||||
depth: u32,
|
||||
client: Arc<SequencerClient>,
|
||||
) -> Result<()> {
|
||||
let mut id_stack = vec![ChainIndex::root()];
|
||||
|
||||
while let Some(curr_id) = id_stack.pop() {
|
||||
if let Some(node) = self.key_map.get(&curr_id) {
|
||||
let address = node.address();
|
||||
let node_acc = client.get_account(address.to_string()).await?.account;
|
||||
|
||||
if node_acc == nssa::Account::default() && curr_id != ChainIndex::root() {
|
||||
self.remove(address);
|
||||
}
|
||||
}
|
||||
|
||||
let mut next_id = curr_id.n_th_child(0);
|
||||
|
||||
while (next_id.depth()) < depth - 1 {
|
||||
id_stack.push(next_id.clone());
|
||||
next_id = next_id.next_in_line();
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::str::FromStr;
|
||||
|
||||
@ -265,7 +265,7 @@ pub enum OverCommand {
|
||||
password: String,
|
||||
#[arg(short, long)]
|
||||
depth: u32,
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
///To execute commands, env var NSSA_WALLET_HOME_DIR must be set into directory with config
|
||||
@ -521,10 +521,59 @@ pub async fn execute_setup(password: String) -> Result<()> {
|
||||
|
||||
pub async fn execute_keys_restoration(password: String, depth: u32) -> Result<()> {
|
||||
let config = fetch_config().await?;
|
||||
let mut wallet_core = WalletCore::start_from_config_new_storage(config.clone(), password.clone()).await?;
|
||||
let mut wallet_core =
|
||||
WalletCore::start_from_config_new_storage(config.clone(), password.clone()).await?;
|
||||
|
||||
wallet_core.storage.user_data.public_key_tree.generate_tree_for_depth(depth);
|
||||
wallet_core.storage.user_data.private_key_tree.generate_tree_for_depth(depth);
|
||||
wallet_core
|
||||
.storage
|
||||
.user_data
|
||||
.public_key_tree
|
||||
.generate_tree_for_depth(depth);
|
||||
|
||||
println!("Public tree generated");
|
||||
|
||||
wallet_core
|
||||
.storage
|
||||
.user_data
|
||||
.private_key_tree
|
||||
.generate_tree_for_depth(depth);
|
||||
|
||||
println!("Private tree generated");
|
||||
|
||||
wallet_core
|
||||
.storage
|
||||
.user_data
|
||||
.public_key_tree
|
||||
.cleanup_tree_for_depth(depth, wallet_core.sequencer_client.clone())
|
||||
.await?;
|
||||
|
||||
println!("Public tree cleaned up");
|
||||
|
||||
let last_block = wallet_core
|
||||
.sequencer_client
|
||||
.get_last_block()
|
||||
.await?
|
||||
.last_block;
|
||||
|
||||
println!("Last block is {last_block}");
|
||||
|
||||
parse_block_range(
|
||||
1,
|
||||
last_block,
|
||||
wallet_core.sequencer_client.clone(),
|
||||
&mut wallet_core,
|
||||
)
|
||||
.await?;
|
||||
|
||||
println!("Private tree clean up start");
|
||||
|
||||
wallet_core
|
||||
.storage
|
||||
.user_data
|
||||
.private_key_tree
|
||||
.cleanup_tree_for_depth(depth);
|
||||
|
||||
println!("Private tree cleaned up");
|
||||
|
||||
wallet_core.store_persistent_data().await?;
|
||||
|
||||
|
||||
@ -1,7 +1,10 @@
|
||||
use anyhow::Result;
|
||||
use clap::{CommandFactory, Parser};
|
||||
use tokio::runtime::Builder;
|
||||
use wallet::{Args, OverCommand, execute_continious_run, execute_keys_restoration, execute_setup, execute_subcommand};
|
||||
use wallet::{
|
||||
Args, OverCommand, execute_continious_run, execute_keys_restoration, execute_setup,
|
||||
execute_subcommand,
|
||||
};
|
||||
|
||||
pub const NUM_THREADS: usize = 2;
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user