mirror of
https://github.com/logos-blockchain/lssa.git
synced 2026-01-02 21:33:09 +00:00
feat: deterministic keys
This commit is contained in:
parent
20c276e63e
commit
ec149d3227
@ -36,6 +36,9 @@ path = "../wallet"
|
||||
[dependencies.common]
|
||||
path = "../common"
|
||||
|
||||
[dependencies.key_protocol]
|
||||
path = "../key_protocol"
|
||||
|
||||
[dependencies.nssa]
|
||||
path = "../nssa"
|
||||
features = ["no_docker"]
|
||||
|
||||
@ -54,6 +54,8 @@ fn make_private_account_input_from_str(addr: &str) -> String {
|
||||
pub async fn pre_test(
|
||||
home_dir: PathBuf,
|
||||
) -> Result<(ServerHandle, JoinHandle<Result<()>>, TempDir)> {
|
||||
wallet::execute_setup("test_pass".to_string()).await?;
|
||||
|
||||
let home_dir_sequencer = home_dir.join("sequencer");
|
||||
|
||||
let mut sequencer_config =
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
use std::{collections::HashMap, path::PathBuf, pin::Pin, time::Duration};
|
||||
|
||||
use common::{PINATA_BASE58, sequencer_client::SequencerClient};
|
||||
use key_protocol::key_management::key_tree::chain_index::ChainIndex;
|
||||
use log::info;
|
||||
use nssa::{Address, ProgramDeploymentTransaction, program::Program};
|
||||
use nssa_core::{NullifierPublicKey, encryption::shared_key_derivation::Secp256k1Point};
|
||||
@ -13,7 +14,7 @@ use wallet::{
|
||||
pinata_program::PinataProgramAgnosticSubcommand,
|
||||
token_program::TokenProgramAgnosticSubcommand,
|
||||
},
|
||||
config::{PersistentAccountData, PersistentStorage},
|
||||
config::PersistentStorage,
|
||||
helperfunctions::{fetch_config, fetch_persistent_storage},
|
||||
};
|
||||
|
||||
@ -72,7 +73,9 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
#[nssa_integration_test]
|
||||
pub async fn test_success_move_to_another_account() {
|
||||
info!("########## test_success_move_to_another_account ##########");
|
||||
let command = Command::Account(AccountSubcommand::New(NewSubcommand::Public {}));
|
||||
let command = Command::Account(AccountSubcommand::New(NewSubcommand::Public {
|
||||
cci: ChainIndex::root(),
|
||||
}));
|
||||
|
||||
let wallet_config = fetch_config().await.unwrap();
|
||||
|
||||
@ -273,47 +276,43 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
let wallet_config = fetch_config().await.unwrap();
|
||||
|
||||
// Create new account for the token definition
|
||||
wallet::execute_subcommand(Command::Account(AccountSubcommand::New(
|
||||
NewSubcommand::Public {},
|
||||
let SubcommandReturnValue::RegisterAccount {
|
||||
addr: definition_addr,
|
||||
} = wallet::execute_subcommand(Command::Account(AccountSubcommand::New(
|
||||
NewSubcommand::Public {
|
||||
cci: ChainIndex::root(),
|
||||
},
|
||||
)))
|
||||
.await
|
||||
.unwrap();
|
||||
.unwrap()
|
||||
else {
|
||||
panic!("invalid subcommand return value");
|
||||
};
|
||||
// Create new account for the token supply holder
|
||||
wallet::execute_subcommand(Command::Account(AccountSubcommand::New(
|
||||
NewSubcommand::Public {},
|
||||
)))
|
||||
.await
|
||||
.unwrap();
|
||||
let SubcommandReturnValue::RegisterAccount { addr: supply_addr } =
|
||||
wallet::execute_subcommand(Command::Account(AccountSubcommand::New(
|
||||
NewSubcommand::Public {
|
||||
cci: ChainIndex::root(),
|
||||
},
|
||||
)))
|
||||
.await
|
||||
.unwrap()
|
||||
else {
|
||||
panic!("invalid subcommand return value");
|
||||
};
|
||||
// Create new account for receiving a token transaction
|
||||
wallet::execute_subcommand(Command::Account(AccountSubcommand::New(
|
||||
NewSubcommand::Public {},
|
||||
let SubcommandReturnValue::RegisterAccount {
|
||||
addr: recipient_addr,
|
||||
} = wallet::execute_subcommand(Command::Account(AccountSubcommand::New(
|
||||
NewSubcommand::Public {
|
||||
cci: ChainIndex::root(),
|
||||
},
|
||||
)))
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let PersistentStorage {
|
||||
accounts: persistent_accounts,
|
||||
last_synced_block: _,
|
||||
} = fetch_persistent_storage().await.unwrap();
|
||||
|
||||
let mut new_persistent_accounts_addr = Vec::new();
|
||||
|
||||
for per_acc in persistent_accounts {
|
||||
match per_acc {
|
||||
PersistentAccountData::Public(per_acc) => {
|
||||
if (per_acc.address.to_string() != ACC_RECEIVER)
|
||||
&& (per_acc.address.to_string() != ACC_SENDER)
|
||||
{
|
||||
new_persistent_accounts_addr.push(per_acc.address);
|
||||
}
|
||||
}
|
||||
_ => continue,
|
||||
}
|
||||
}
|
||||
|
||||
let [definition_addr, supply_addr, recipient_addr] = new_persistent_accounts_addr
|
||||
.try_into()
|
||||
.expect("Failed to produce new account, not present in persistent accounts");
|
||||
.unwrap()
|
||||
else {
|
||||
panic!("invalid subcommand return value");
|
||||
};
|
||||
|
||||
// Create new token
|
||||
let subcommand = TokenProgramAgnosticSubcommand::New {
|
||||
@ -433,7 +432,9 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
let SubcommandReturnValue::RegisterAccount {
|
||||
addr: definition_addr,
|
||||
} = wallet::execute_subcommand(Command::Account(AccountSubcommand::New(
|
||||
NewSubcommand::Public {},
|
||||
NewSubcommand::Public {
|
||||
cci: ChainIndex::root(),
|
||||
},
|
||||
)))
|
||||
.await
|
||||
.unwrap()
|
||||
@ -443,7 +444,9 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
// Create new account for the token supply holder (private)
|
||||
let SubcommandReturnValue::RegisterAccount { addr: supply_addr } =
|
||||
wallet::execute_subcommand(Command::Account(AccountSubcommand::New(
|
||||
NewSubcommand::Private {},
|
||||
NewSubcommand::Private {
|
||||
cci: ChainIndex::root(),
|
||||
},
|
||||
)))
|
||||
.await
|
||||
.unwrap()
|
||||
@ -454,7 +457,9 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
let SubcommandReturnValue::RegisterAccount {
|
||||
addr: recipient_addr,
|
||||
} = wallet::execute_subcommand(Command::Account(AccountSubcommand::New(
|
||||
NewSubcommand::Private {},
|
||||
NewSubcommand::Private {
|
||||
cci: ChainIndex::root(),
|
||||
},
|
||||
)))
|
||||
.await
|
||||
.unwrap()
|
||||
@ -584,7 +589,9 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
let SubcommandReturnValue::RegisterAccount {
|
||||
addr: definition_addr,
|
||||
} = wallet::execute_subcommand(Command::Account(AccountSubcommand::New(
|
||||
NewSubcommand::Public {},
|
||||
NewSubcommand::Public {
|
||||
cci: ChainIndex::root(),
|
||||
},
|
||||
)))
|
||||
.await
|
||||
.unwrap()
|
||||
@ -594,7 +601,9 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
// Create new account for the token supply holder (private)
|
||||
let SubcommandReturnValue::RegisterAccount { addr: supply_addr } =
|
||||
wallet::execute_subcommand(Command::Account(AccountSubcommand::New(
|
||||
NewSubcommand::Private {},
|
||||
NewSubcommand::Private {
|
||||
cci: ChainIndex::root(),
|
||||
},
|
||||
)))
|
||||
.await
|
||||
.unwrap()
|
||||
@ -605,7 +614,9 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
let SubcommandReturnValue::RegisterAccount {
|
||||
addr: recipient_addr,
|
||||
} = wallet::execute_subcommand(Command::Account(AccountSubcommand::New(
|
||||
NewSubcommand::Private {},
|
||||
NewSubcommand::Private {
|
||||
cci: ChainIndex::root(),
|
||||
},
|
||||
)))
|
||||
.await
|
||||
.unwrap()
|
||||
@ -716,7 +727,9 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
let SubcommandReturnValue::RegisterAccount {
|
||||
addr: definition_addr,
|
||||
} = wallet::execute_subcommand(Command::Account(AccountSubcommand::New(
|
||||
NewSubcommand::Public {},
|
||||
NewSubcommand::Public {
|
||||
cci: ChainIndex::root(),
|
||||
},
|
||||
)))
|
||||
.await
|
||||
.unwrap()
|
||||
@ -726,7 +739,9 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
// Create new account for the token supply holder (public)
|
||||
let SubcommandReturnValue::RegisterAccount { addr: supply_addr } =
|
||||
wallet::execute_subcommand(Command::Account(AccountSubcommand::New(
|
||||
NewSubcommand::Public {},
|
||||
NewSubcommand::Public {
|
||||
cci: ChainIndex::root(),
|
||||
},
|
||||
)))
|
||||
.await
|
||||
.unwrap()
|
||||
@ -737,7 +752,9 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
let SubcommandReturnValue::RegisterAccount {
|
||||
addr: recipient_addr,
|
||||
} = wallet::execute_subcommand(Command::Account(AccountSubcommand::New(
|
||||
NewSubcommand::Private {},
|
||||
NewSubcommand::Private {
|
||||
cci: ChainIndex::root(),
|
||||
},
|
||||
)))
|
||||
.await
|
||||
.unwrap()
|
||||
@ -847,7 +864,9 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
let SubcommandReturnValue::RegisterAccount {
|
||||
addr: definition_addr,
|
||||
} = wallet::execute_subcommand(Command::Account(AccountSubcommand::New(
|
||||
NewSubcommand::Public {},
|
||||
NewSubcommand::Public {
|
||||
cci: ChainIndex::root(),
|
||||
},
|
||||
)))
|
||||
.await
|
||||
.unwrap()
|
||||
@ -857,7 +876,9 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
// Create new account for the token supply holder (private)
|
||||
let SubcommandReturnValue::RegisterAccount { addr: supply_addr } =
|
||||
wallet::execute_subcommand(Command::Account(AccountSubcommand::New(
|
||||
NewSubcommand::Private {},
|
||||
NewSubcommand::Private {
|
||||
cci: ChainIndex::root(),
|
||||
},
|
||||
)))
|
||||
.await
|
||||
.unwrap()
|
||||
@ -868,7 +889,9 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
let SubcommandReturnValue::RegisterAccount {
|
||||
addr: recipient_addr,
|
||||
} = wallet::execute_subcommand(Command::Account(AccountSubcommand::New(
|
||||
NewSubcommand::Public {},
|
||||
NewSubcommand::Public {
|
||||
cci: ChainIndex::root(),
|
||||
},
|
||||
)))
|
||||
.await
|
||||
.unwrap()
|
||||
@ -1066,7 +1089,9 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
);
|
||||
let from: Address = ACC_SENDER_PRIVATE.parse().unwrap();
|
||||
|
||||
let command = Command::Account(AccountSubcommand::New(NewSubcommand::Private {}));
|
||||
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_addr } = sub_ret else {
|
||||
@ -1082,8 +1107,7 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
let (to_keys, _) = wallet_storage
|
||||
.storage
|
||||
.user_data
|
||||
.user_private_accounts
|
||||
.get(&to_addr)
|
||||
.get_private_account(&to_addr)
|
||||
.cloned()
|
||||
.unwrap();
|
||||
|
||||
@ -1134,7 +1158,9 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
|
||||
let from: Address = ACC_SENDER_PRIVATE.parse().unwrap();
|
||||
|
||||
let command = Command::Account(AccountSubcommand::New(NewSubcommand::Private {}));
|
||||
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_addr } = sub_ret else {
|
||||
@ -1150,8 +1176,7 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
let (to_keys, _) = wallet_storage
|
||||
.storage
|
||||
.user_data
|
||||
.user_private_accounts
|
||||
.get(&to_addr)
|
||||
.get_private_account(&to_addr)
|
||||
.cloned()
|
||||
.unwrap();
|
||||
|
||||
@ -1428,7 +1453,9 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
#[nssa_integration_test]
|
||||
pub async fn test_authenticated_transfer_initialize_function() {
|
||||
info!("########## test initialize account for authenticated transfer ##########");
|
||||
let command = Command::Account(AccountSubcommand::New(NewSubcommand::Public {}));
|
||||
let command = Command::Account(AccountSubcommand::New(NewSubcommand::Public {
|
||||
cci: ChainIndex::root(),
|
||||
}));
|
||||
let SubcommandReturnValue::RegisterAccount { addr } =
|
||||
wallet::execute_subcommand(command).await.unwrap()
|
||||
else {
|
||||
@ -1528,7 +1555,9 @@ pub fn prepare_function_map() -> HashMap<String, TestFunction> {
|
||||
// Create new account for the token supply holder (private)
|
||||
let SubcommandReturnValue::RegisterAccount { addr: winner_addr } =
|
||||
wallet::execute_subcommand(Command::Account(AccountSubcommand::New(
|
||||
NewSubcommand::Private {},
|
||||
NewSubcommand::Private {
|
||||
cci: ChainIndex::root(),
|
||||
},
|
||||
)))
|
||||
.await
|
||||
.unwrap()
|
||||
|
||||
@ -14,6 +14,7 @@ hex = "0.4.3"
|
||||
aes-gcm.workspace = true
|
||||
bip39.workspace = true
|
||||
hmac-sha512.workspace = true
|
||||
thiserror.workspace = true
|
||||
nssa-core = { path = "../nssa/core", features = ["host"] }
|
||||
|
||||
[dependencies.common]
|
||||
|
||||
@ -1,59 +1,57 @@
|
||||
use std::str::FromStr;
|
||||
use std::{fmt::Display, str::FromStr};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Serialize, Deserialize)]
|
||||
pub struct ChainIndex(Vec<u32>);
|
||||
|
||||
#[derive(thiserror::Error, Debug)]
|
||||
pub enum ChainIndexError {
|
||||
#[error("No root found")]
|
||||
NoRootFound,
|
||||
#[error("Failed to parse segment into a number")]
|
||||
ParseIntError(#[from] std::num::ParseIntError),
|
||||
}
|
||||
|
||||
impl FromStr for ChainIndex {
|
||||
type Err = hex::FromHexError;
|
||||
type Err = ChainIndexError;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
if s.is_empty() {
|
||||
return Ok(Self(vec![]));
|
||||
if !s.starts_with("/") {
|
||||
return Err(ChainIndexError::NoRootFound);
|
||||
}
|
||||
|
||||
let hex_decoded = hex::decode(s)?;
|
||||
|
||||
if !hex_decoded.len().is_multiple_of(4) {
|
||||
Err(hex::FromHexError::InvalidStringLength)
|
||||
} else {
|
||||
let mut res_vec = vec![];
|
||||
|
||||
for i in 0..(hex_decoded.len() / 4) {
|
||||
res_vec.push(u32::from_le_bytes([
|
||||
hex_decoded[4 * i],
|
||||
hex_decoded[4 * i + 1],
|
||||
hex_decoded[4 * i + 2],
|
||||
hex_decoded[4 * i + 3],
|
||||
]));
|
||||
}
|
||||
|
||||
Ok(Self(res_vec))
|
||||
if s == "/" {
|
||||
return Ok(ChainIndex(vec![]));
|
||||
}
|
||||
|
||||
let uprooted_substring = s.strip_prefix("/").unwrap();
|
||||
|
||||
let splitted_chain: Vec<&str> = uprooted_substring.split("/").collect();
|
||||
let mut res = vec![];
|
||||
|
||||
for split_ch in splitted_chain {
|
||||
let cci = split_ch.parse()?;
|
||||
res.push(cci);
|
||||
}
|
||||
|
||||
Ok(Self(res))
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::to_string_trait_impl)]
|
||||
impl ToString for ChainIndex {
|
||||
fn to_string(&self) -> String {
|
||||
if self.0.is_empty() {
|
||||
return "".to_string();
|
||||
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}/")?;
|
||||
}
|
||||
|
||||
let mut res_vec = vec![];
|
||||
|
||||
for index in &self.0 {
|
||||
res_vec.extend_from_slice(&index.to_le_bytes());
|
||||
}
|
||||
|
||||
hex::encode(res_vec)
|
||||
write!(f, "{}", self.0.last().unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
impl ChainIndex {
|
||||
pub fn root() -> Self {
|
||||
ChainIndex::from_str("").unwrap()
|
||||
ChainIndex::from_str("/").unwrap()
|
||||
}
|
||||
|
||||
pub fn chain(&self) -> &[u32] {
|
||||
@ -85,31 +83,40 @@ mod tests {
|
||||
#[test]
|
||||
fn test_chain_id_root_correct() {
|
||||
let chain_id = ChainIndex::root();
|
||||
let chain_id_2 = ChainIndex::from_str("").unwrap();
|
||||
let chain_id_2 = ChainIndex::from_str("/").unwrap();
|
||||
|
||||
assert_eq!(chain_id, chain_id_2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_chain_id_deser_correct() {
|
||||
let chain_id = ChainIndex::from_str("01010000").unwrap();
|
||||
let chain_id = ChainIndex::from_str("/257").unwrap();
|
||||
|
||||
assert_eq!(chain_id.chain(), &[257]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_chain_id_next_in_line_correct() {
|
||||
let chain_id = ChainIndex::from_str("01010000").unwrap();
|
||||
let chain_id = ChainIndex::from_str("/257").unwrap();
|
||||
let next_in_line = chain_id.next_in_line();
|
||||
|
||||
assert_eq!(next_in_line, ChainIndex::from_str("02010000").unwrap());
|
||||
assert_eq!(next_in_line, ChainIndex::from_str("/258").unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_chain_id_child_correct() {
|
||||
let chain_id = ChainIndex::from_str("01010000").unwrap();
|
||||
let chain_id = ChainIndex::from_str("/257").unwrap();
|
||||
let child = chain_id.n_th_child(3);
|
||||
|
||||
assert_eq!(child, ChainIndex::from_str("0101000003000000").unwrap());
|
||||
assert_eq!(child, ChainIndex::from_str("/257/3").unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_correct_display() {
|
||||
let chainid = ChainIndex(vec![5, 7, 8]);
|
||||
|
||||
let string_index = format!("{chainid}");
|
||||
|
||||
assert_eq!(string_index, "/5/7/8".to_string());
|
||||
}
|
||||
}
|
||||
|
||||
@ -40,6 +40,18 @@ impl<Node: KeyNode> KeyTree<Node> {
|
||||
Self { key_map, addr_map }
|
||||
}
|
||||
|
||||
pub fn new_from_root(root: Node) -> Self {
|
||||
let mut key_map = BTreeMap::new();
|
||||
let mut addr_map = HashMap::new();
|
||||
|
||||
addr_map.insert(root.address(), ChainIndex::root());
|
||||
key_map.insert(ChainIndex::root(), root);
|
||||
|
||||
Self { key_map, addr_map }
|
||||
}
|
||||
|
||||
//ToDo: Add function to create a tree from list of nodes with consistency check.
|
||||
|
||||
pub fn find_next_last_child_of_id(&self, parent_id: &ChainIndex) -> Option<u32> {
|
||||
if !self.key_map.contains_key(parent_id) {
|
||||
return None;
|
||||
@ -160,7 +172,7 @@ mod tests {
|
||||
|
||||
assert!(
|
||||
tree.key_map
|
||||
.contains_key(&ChainIndex::from_str("00000000").unwrap())
|
||||
.contains_key(&ChainIndex::from_str("/0").unwrap())
|
||||
);
|
||||
|
||||
let next_last_child_for_parent_id = tree
|
||||
@ -199,7 +211,7 @@ mod tests {
|
||||
|
||||
assert!(
|
||||
tree.key_map
|
||||
.contains_key(&ChainIndex::from_str("00000000").unwrap())
|
||||
.contains_key(&ChainIndex::from_str("/0").unwrap())
|
||||
);
|
||||
|
||||
let next_last_child_for_parent_id = tree
|
||||
@ -208,7 +220,7 @@ mod tests {
|
||||
|
||||
assert_eq!(next_last_child_for_parent_id, 1);
|
||||
|
||||
let key_opt = tree.generate_new_node(ChainIndex::from_str("03000000").unwrap());
|
||||
let key_opt = tree.generate_new_node(ChainIndex::from_str("/3").unwrap());
|
||||
|
||||
assert_eq!(key_opt, None);
|
||||
}
|
||||
@ -229,7 +241,7 @@ mod tests {
|
||||
|
||||
assert!(
|
||||
tree.key_map
|
||||
.contains_key(&ChainIndex::from_str("00000000").unwrap())
|
||||
.contains_key(&ChainIndex::from_str("/0").unwrap())
|
||||
);
|
||||
|
||||
let next_last_child_for_parent_id = tree
|
||||
@ -242,7 +254,7 @@ mod tests {
|
||||
|
||||
assert!(
|
||||
tree.key_map
|
||||
.contains_key(&ChainIndex::from_str("01000000").unwrap())
|
||||
.contains_key(&ChainIndex::from_str("/1").unwrap())
|
||||
);
|
||||
|
||||
let next_last_child_for_parent_id = tree
|
||||
@ -251,58 +263,58 @@ mod tests {
|
||||
|
||||
assert_eq!(next_last_child_for_parent_id, 2);
|
||||
|
||||
tree.generate_new_node(ChainIndex::from_str("00000000").unwrap())
|
||||
tree.generate_new_node(ChainIndex::from_str("/0").unwrap())
|
||||
.unwrap();
|
||||
|
||||
let next_last_child_for_parent_id = tree
|
||||
.find_next_last_child_of_id(&ChainIndex::from_str("00000000").unwrap())
|
||||
.find_next_last_child_of_id(&ChainIndex::from_str("/0").unwrap())
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(next_last_child_for_parent_id, 1);
|
||||
|
||||
assert!(
|
||||
tree.key_map
|
||||
.contains_key(&ChainIndex::from_str("0000000000000000").unwrap())
|
||||
.contains_key(&ChainIndex::from_str("/0/0").unwrap())
|
||||
);
|
||||
|
||||
tree.generate_new_node(ChainIndex::from_str("00000000").unwrap())
|
||||
tree.generate_new_node(ChainIndex::from_str("/0").unwrap())
|
||||
.unwrap();
|
||||
|
||||
let next_last_child_for_parent_id = tree
|
||||
.find_next_last_child_of_id(&ChainIndex::from_str("00000000").unwrap())
|
||||
.find_next_last_child_of_id(&ChainIndex::from_str("/0").unwrap())
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(next_last_child_for_parent_id, 2);
|
||||
|
||||
assert!(
|
||||
tree.key_map
|
||||
.contains_key(&ChainIndex::from_str("0000000001000000").unwrap())
|
||||
.contains_key(&ChainIndex::from_str("/0/1").unwrap())
|
||||
);
|
||||
|
||||
tree.generate_new_node(ChainIndex::from_str("00000000").unwrap())
|
||||
tree.generate_new_node(ChainIndex::from_str("/0").unwrap())
|
||||
.unwrap();
|
||||
|
||||
let next_last_child_for_parent_id = tree
|
||||
.find_next_last_child_of_id(&ChainIndex::from_str("00000000").unwrap())
|
||||
.find_next_last_child_of_id(&ChainIndex::from_str("/0").unwrap())
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(next_last_child_for_parent_id, 3);
|
||||
|
||||
assert!(
|
||||
tree.key_map
|
||||
.contains_key(&ChainIndex::from_str("0000000002000000").unwrap())
|
||||
.contains_key(&ChainIndex::from_str("/0/2").unwrap())
|
||||
);
|
||||
|
||||
tree.generate_new_node(ChainIndex::from_str("0000000001000000").unwrap())
|
||||
tree.generate_new_node(ChainIndex::from_str("/0/1").unwrap())
|
||||
.unwrap();
|
||||
|
||||
assert!(
|
||||
tree.key_map
|
||||
.contains_key(&ChainIndex::from_str("000000000100000000000000").unwrap())
|
||||
.contains_key(&ChainIndex::from_str("/0/1/0").unwrap())
|
||||
);
|
||||
|
||||
let next_last_child_for_parent_id = tree
|
||||
.find_next_last_child_of_id(&ChainIndex::from_str("0000000001000000").unwrap())
|
||||
.find_next_last_child_of_id(&ChainIndex::from_str("/0/1").unwrap())
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(next_last_child_for_parent_id, 1);
|
||||
|
||||
@ -166,4 +166,14 @@ mod tests {
|
||||
|
||||
let _ = top_secret_key_holder.generate_outgoing_viewing_secret_key();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn two_seeds_generated_same_from_same_mnemonic() {
|
||||
let mnemonic = "test_pass";
|
||||
|
||||
let seed_holder1 = SeedHolder::new_mnemonic(mnemonic.to_string());
|
||||
let seed_holder2 = SeedHolder::new_mnemonic(mnemonic.to_string());
|
||||
|
||||
assert_eq!(seed_holder1.seed, seed_holder2.seed);
|
||||
}
|
||||
}
|
||||
|
||||
@ -19,8 +19,6 @@ pub struct NSSAUserData {
|
||||
///Default private accounts
|
||||
pub default_user_private_accounts:
|
||||
HashMap<nssa::Address, (KeyChain, nssa_core::account::Account)>,
|
||||
///Mnemonic passphrase
|
||||
pub password: String,
|
||||
/// Tree of public keys
|
||||
pub public_key_tree: KeyTreePublic,
|
||||
/// Tree of private keys
|
||||
@ -82,38 +80,6 @@ impl NSSAUserData {
|
||||
default_user_private_accounts: default_accounts_key_chains,
|
||||
public_key_tree,
|
||||
private_key_tree,
|
||||
password: "mnemonic".to_string(),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn new_with_accounts_and_password(
|
||||
default_accounts_keys: HashMap<nssa::Address, nssa::PrivateKey>,
|
||||
default_accounts_key_chains: HashMap<
|
||||
nssa::Address,
|
||||
(KeyChain, nssa_core::account::Account),
|
||||
>,
|
||||
public_key_tree: KeyTreePublic,
|
||||
private_key_tree: KeyTreePrivate,
|
||||
password: String,
|
||||
) -> Result<Self> {
|
||||
if !Self::valid_public_key_transaction_pairing_check(&default_accounts_keys) {
|
||||
anyhow::bail!(
|
||||
"Key transaction pairing check not satisfied, there is addresses, which is not derived from keys"
|
||||
);
|
||||
}
|
||||
|
||||
if !Self::valid_private_key_transaction_pairing_check(&default_accounts_key_chains) {
|
||||
anyhow::bail!(
|
||||
"Key transaction pairing check not satisfied, there is addresses, which is not derived from keys"
|
||||
);
|
||||
}
|
||||
|
||||
Ok(Self {
|
||||
default_pub_account_signing_keys: default_accounts_keys,
|
||||
default_user_private_accounts: default_accounts_key_chains,
|
||||
public_key_tree,
|
||||
private_key_tree,
|
||||
password,
|
||||
})
|
||||
}
|
||||
|
||||
@ -137,9 +103,7 @@ impl NSSAUserData {
|
||||
Some(key)
|
||||
//Then seek in tree
|
||||
} else {
|
||||
self.public_key_tree
|
||||
.get_node(*address)
|
||||
.and_then(|chain_keys| Some(chain_keys.into()))
|
||||
self.public_key_tree.get_node(*address).map(Into::into)
|
||||
}
|
||||
}
|
||||
|
||||
@ -163,9 +127,7 @@ impl NSSAUserData {
|
||||
Some(key)
|
||||
//Then seek in tree
|
||||
} else {
|
||||
self.private_key_tree
|
||||
.get_node(*address)
|
||||
.and_then(|chain_keys| Some(chain_keys.into()))
|
||||
self.private_key_tree.get_node(*address).map(Into::into)
|
||||
}
|
||||
}
|
||||
|
||||
@ -179,9 +141,7 @@ impl NSSAUserData {
|
||||
Some(key)
|
||||
//Then seek in tree
|
||||
} else {
|
||||
self.private_key_tree
|
||||
.get_node_mut(*address)
|
||||
.and_then(|chain_keys| Some(chain_keys.into()))
|
||||
self.private_key_tree.get_node_mut(*address).map(Into::into)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,7 +3,7 @@ use std::collections::HashMap;
|
||||
use anyhow::Result;
|
||||
use key_protocol::{
|
||||
key_management::{
|
||||
key_tree::{KeyTreePrivate, KeyTreePublic},
|
||||
key_tree::{KeyTreePrivate, KeyTreePublic, chain_index::ChainIndex},
|
||||
secret_holders::SeedHolder,
|
||||
},
|
||||
key_protocol_core::NSSAUserData,
|
||||
@ -21,8 +21,73 @@ impl WalletChainStore {
|
||||
pub fn new(
|
||||
config: WalletConfig,
|
||||
persistent_accounts: Vec<PersistentAccountData>,
|
||||
password: String,
|
||||
) -> Result<Self> {
|
||||
if persistent_accounts.is_empty() {
|
||||
anyhow::bail!("Roots not found; please run setup beforehand");
|
||||
}
|
||||
|
||||
let mut public_init_acc_map = HashMap::new();
|
||||
let mut private_init_acc_map = HashMap::new();
|
||||
|
||||
let public_root = persistent_accounts
|
||||
.iter()
|
||||
.find(|data| match data {
|
||||
&PersistentAccountData::Public(data) => data.chain_index == ChainIndex::root(),
|
||||
_ => false,
|
||||
})
|
||||
.cloned()
|
||||
.unwrap();
|
||||
|
||||
let private_root = persistent_accounts
|
||||
.iter()
|
||||
.find(|data| match data {
|
||||
&PersistentAccountData::Private(data) => data.chain_index == ChainIndex::root(),
|
||||
_ => false,
|
||||
})
|
||||
.cloned()
|
||||
.unwrap();
|
||||
|
||||
let mut public_tree = KeyTreePublic::new_from_root(match public_root {
|
||||
PersistentAccountData::Public(data) => data.data,
|
||||
_ => unreachable!(),
|
||||
});
|
||||
let mut private_tree = KeyTreePrivate::new_from_root(match private_root {
|
||||
PersistentAccountData::Private(data) => data.data,
|
||||
_ => unreachable!(),
|
||||
});
|
||||
|
||||
for pers_acc_data in persistent_accounts {
|
||||
match pers_acc_data {
|
||||
PersistentAccountData::Public(data) => {
|
||||
public_tree.insert(data.address, data.chain_index, data.data);
|
||||
}
|
||||
PersistentAccountData::Private(data) => {
|
||||
private_tree.insert(data.address, data.chain_index, data.data);
|
||||
}
|
||||
PersistentAccountData::Preconfigured(acc_data) => match acc_data {
|
||||
InitialAccountData::Public(data) => {
|
||||
public_init_acc_map.insert(data.address.parse()?, data.pub_sign_key);
|
||||
}
|
||||
InitialAccountData::Private(data) => {
|
||||
private_init_acc_map
|
||||
.insert(data.address.parse()?, (data.key_chain, data.account));
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Self {
|
||||
user_data: NSSAUserData::new_with_accounts(
|
||||
public_init_acc_map,
|
||||
private_init_acc_map,
|
||||
public_tree,
|
||||
private_tree,
|
||||
)?,
|
||||
wallet_config: config,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn new_storage(config: WalletConfig, password: String) -> Result<Self> {
|
||||
let mut public_init_acc_map = HashMap::new();
|
||||
let mut private_init_acc_map = HashMap::new();
|
||||
|
||||
@ -42,19 +107,8 @@ impl WalletChainStore {
|
||||
}
|
||||
}
|
||||
|
||||
let mut public_tree = KeyTreePublic::new(&SeedHolder::new_mnemonic(password.clone()));
|
||||
let mut private_tree = KeyTreePrivate::new(&SeedHolder::new_mnemonic(password));
|
||||
|
||||
for pers_acc_data in persistent_accounts {
|
||||
match pers_acc_data {
|
||||
PersistentAccountData::Public(data) => {
|
||||
public_tree.insert(data.address, data.chain_index, data.data);
|
||||
}
|
||||
PersistentAccountData::Private(data) => {
|
||||
private_tree.insert(data.address, data.chain_index, data.data);
|
||||
}
|
||||
}
|
||||
}
|
||||
let public_tree = KeyTreePublic::new(&SeedHolder::new_mnemonic(password.clone()));
|
||||
let private_tree = KeyTreePrivate::new(&SeedHolder::new_mnemonic(password));
|
||||
|
||||
Ok(Self {
|
||||
user_data: NSSAUserData::new_with_accounts(
|
||||
@ -73,25 +127,41 @@ impl WalletChainStore {
|
||||
account: nssa_core::account::Account,
|
||||
) {
|
||||
println!("inserting at address {}, this account {:?}", addr, account);
|
||||
self.user_data
|
||||
.private_key_tree
|
||||
.addr_map
|
||||
.get(&addr)
|
||||
.and_then(|chain_index| {
|
||||
Some(
|
||||
|
||||
if self
|
||||
.user_data
|
||||
.default_user_private_accounts
|
||||
.contains_key(&addr)
|
||||
{
|
||||
self.user_data
|
||||
.default_user_private_accounts
|
||||
.entry(addr)
|
||||
.and_modify(|data| data.1 = account);
|
||||
} else {
|
||||
self.user_data
|
||||
.private_key_tree
|
||||
.addr_map
|
||||
.get(&addr)
|
||||
.map(|chain_index| {
|
||||
self.user_data
|
||||
.private_key_tree
|
||||
.key_map
|
||||
.entry(chain_index.clone())
|
||||
.and_modify(|data| data.value.1 = account),
|
||||
)
|
||||
});
|
||||
.and_modify(|data| data.value.1 = account)
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::config::InitialAccountData;
|
||||
use key_protocol::key_management::key_tree::{
|
||||
keys_private::ChildKeysPrivate, keys_public::ChildKeysPublic, traits::KeyNode,
|
||||
};
|
||||
|
||||
use crate::config::{
|
||||
InitialAccountData, PersistentAccountDataPrivate, PersistentAccountDataPublic,
|
||||
};
|
||||
|
||||
use super::*;
|
||||
|
||||
@ -199,10 +269,35 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
fn create_sample_persistent_accounts() -> Vec<PersistentAccountData> {
|
||||
let mut accs = vec![];
|
||||
|
||||
let public_data = ChildKeysPublic::root([42; 64]);
|
||||
|
||||
accs.push(PersistentAccountData::Public(PersistentAccountDataPublic {
|
||||
address: public_data.address(),
|
||||
chain_index: ChainIndex::root(),
|
||||
data: public_data,
|
||||
}));
|
||||
|
||||
let private_data = ChildKeysPrivate::root([47; 64]);
|
||||
|
||||
accs.push(PersistentAccountData::Private(
|
||||
PersistentAccountDataPrivate {
|
||||
address: private_data.address(),
|
||||
chain_index: ChainIndex::root(),
|
||||
data: private_data,
|
||||
},
|
||||
));
|
||||
|
||||
accs
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_new_initializes_correctly() {
|
||||
let config = create_sample_wallet_config();
|
||||
let accs = create_sample_persistent_accounts();
|
||||
|
||||
let _ = WalletChainStore::new(config.clone(), vec![], "test_pass".to_string()).unwrap();
|
||||
let _ = WalletChainStore::new(config.clone(), accs).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
@ -90,14 +90,14 @@ pub enum AccountSubcommand {
|
||||
#[derive(Subcommand, Debug, Clone)]
|
||||
pub enum NewSubcommand {
|
||||
///Register new public account
|
||||
Public {
|
||||
Public {
|
||||
#[arg(long)]
|
||||
cci: ChainIndex
|
||||
cci: ChainIndex,
|
||||
},
|
||||
///Register new private account
|
||||
Private {
|
||||
#[arg(long)]
|
||||
cci: ChainIndex
|
||||
cci: ChainIndex,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@ -49,12 +49,12 @@ pub enum InitialAccountData {
|
||||
pub enum PersistentAccountData {
|
||||
Public(PersistentAccountDataPublic),
|
||||
Private(PersistentAccountDataPrivate),
|
||||
Preconfigured(InitialAccountData),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct PersistentStorage {
|
||||
pub accounts: Vec<PersistentAccountData>,
|
||||
pub password: String,
|
||||
pub last_synced_block: u64,
|
||||
}
|
||||
|
||||
@ -72,6 +72,7 @@ impl PersistentAccountData {
|
||||
match &self {
|
||||
Self::Public(acc) => acc.address,
|
||||
Self::Private(acc) => acc.address,
|
||||
Self::Preconfigured(acc) => acc.address(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -100,6 +101,12 @@ impl From<PersistentAccountDataPrivate> for PersistentAccountData {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<InitialAccountData> for PersistentAccountData {
|
||||
fn from(value: InitialAccountData) -> Self {
|
||||
Self::Preconfigured(value)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct GasConfig {
|
||||
/// Gas spent per deploying one byte of data
|
||||
|
||||
@ -12,6 +12,7 @@ use serde::Serialize;
|
||||
use crate::{
|
||||
HOME_DIR_ENV_VAR,
|
||||
config::{
|
||||
InitialAccountData, InitialAccountDataPrivate, InitialAccountDataPublic,
|
||||
PersistentAccountDataPrivate, PersistentAccountDataPublic, PersistentStorage, WalletConfig,
|
||||
},
|
||||
};
|
||||
@ -102,11 +103,9 @@ pub async fn fetch_persistent_storage() -> Result<PersistentStorage> {
|
||||
Ok(serde_json::from_slice(&storage_content)?)
|
||||
}
|
||||
Err(err) => match err.kind() {
|
||||
std::io::ErrorKind::NotFound => Ok(PersistentStorage {
|
||||
accounts: vec![],
|
||||
password: "default".to_string(),
|
||||
last_synced_block: 0,
|
||||
}),
|
||||
std::io::ErrorKind::NotFound => {
|
||||
anyhow::bail!("Not found, please setup roots from config command beforehand");
|
||||
}
|
||||
_ => {
|
||||
anyhow::bail!("IO error {err:#?}");
|
||||
}
|
||||
@ -123,27 +122,53 @@ pub fn produce_data_for_storage(
|
||||
|
||||
for (addr, key) in &user_data.public_key_tree.addr_map {
|
||||
if let Some(data) = user_data.public_key_tree.key_map.get(key) {
|
||||
vec_for_storage.push(PersistentAccountDataPublic {
|
||||
address: *addr,
|
||||
chain_index: key.clone(),
|
||||
data: data.clone(),
|
||||
}.into());
|
||||
vec_for_storage.push(
|
||||
PersistentAccountDataPublic {
|
||||
address: *addr,
|
||||
chain_index: key.clone(),
|
||||
data: data.clone(),
|
||||
}
|
||||
.into(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
for (addr, key) in &user_data.private_key_tree.addr_map {
|
||||
if let Some(data) = user_data.private_key_tree.key_map.get(key) {
|
||||
vec_for_storage.push(PersistentAccountDataPrivate {
|
||||
address: *addr,
|
||||
chain_index: key.clone(),
|
||||
data: data.clone(),
|
||||
}.into());
|
||||
vec_for_storage.push(
|
||||
PersistentAccountDataPrivate {
|
||||
address: *addr,
|
||||
chain_index: key.clone(),
|
||||
data: data.clone(),
|
||||
}
|
||||
.into(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
for (addr, key) in &user_data.default_pub_account_signing_keys {
|
||||
vec_for_storage.push(
|
||||
InitialAccountData::Public(InitialAccountDataPublic {
|
||||
address: addr.to_string(),
|
||||
pub_sign_key: key.clone(),
|
||||
})
|
||||
.into(),
|
||||
)
|
||||
}
|
||||
|
||||
for (addr, (key_chain, account)) in &user_data.default_user_private_accounts {
|
||||
vec_for_storage.push(
|
||||
InitialAccountData::Private(InitialAccountDataPrivate {
|
||||
address: addr.to_string(),
|
||||
account: account.clone(),
|
||||
key_chain: key_chain.clone(),
|
||||
})
|
||||
.into(),
|
||||
)
|
||||
}
|
||||
|
||||
PersistentStorage {
|
||||
accounts: vec_for_storage,
|
||||
password: user_data.password.clone(),
|
||||
last_synced_block,
|
||||
}
|
||||
}
|
||||
|
||||
@ -10,7 +10,7 @@ use common::{
|
||||
use anyhow::Result;
|
||||
use chain_storage::WalletChainStore;
|
||||
use config::WalletConfig;
|
||||
use key_protocol::key_management::key_tree::chain_index::ChainIndex;
|
||||
use key_protocol::key_management::key_tree::{chain_index::ChainIndex, traits::KeyNode};
|
||||
use log::info;
|
||||
use nssa::{
|
||||
Account, Address, privacy_preserving_transaction::message::EncryptedAccountData,
|
||||
@ -62,11 +62,10 @@ impl WalletCore {
|
||||
|
||||
let PersistentStorage {
|
||||
accounts: persistent_accounts,
|
||||
password,
|
||||
last_synced_block,
|
||||
} = fetch_persistent_storage().await?;
|
||||
|
||||
let storage = WalletChainStore::new(config, persistent_accounts, password)?;
|
||||
let storage = WalletChainStore::new(config, persistent_accounts)?;
|
||||
|
||||
Ok(Self {
|
||||
storage,
|
||||
@ -76,6 +75,23 @@ impl WalletCore {
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn start_from_config_new_storage(
|
||||
config: WalletConfig,
|
||||
password: String,
|
||||
) -> Result<Self> {
|
||||
let client = Arc::new(SequencerClient::new(config.sequencer_addr.clone())?);
|
||||
let tx_poller = TxPoller::new(config.clone(), client.clone());
|
||||
|
||||
let storage = WalletChainStore::new_storage(config, password)?;
|
||||
|
||||
Ok(Self {
|
||||
storage,
|
||||
poller: tx_poller,
|
||||
sequencer_client: client.clone(),
|
||||
last_synced_block: 0,
|
||||
})
|
||||
}
|
||||
|
||||
///Store persistent data at home
|
||||
pub async fn store_persistent_data(&self) -> Result<PathBuf> {
|
||||
let home = get_home()?;
|
||||
@ -233,6 +249,18 @@ pub enum Command {
|
||||
Config(ConfigSubcommand),
|
||||
}
|
||||
|
||||
///Represents CLI command for a wallet with setup included
|
||||
#[derive(Debug, Subcommand, Clone)]
|
||||
#[clap(about)]
|
||||
pub enum OverCommand {
|
||||
#[command(subcommand)]
|
||||
Command(Command),
|
||||
Setup {
|
||||
#[arg(short, long)]
|
||||
password: String,
|
||||
},
|
||||
}
|
||||
|
||||
///To execute commands, env var NSSA_WALLET_HOME_DIR must be set into directory with config
|
||||
///
|
||||
/// All account adresses must be valid 32 byte base58 strings.
|
||||
@ -247,7 +275,7 @@ pub struct Args {
|
||||
pub continious_run: bool,
|
||||
/// Wallet command
|
||||
#[command(subcommand)]
|
||||
pub command: Option<Command>,
|
||||
pub command: Option<OverCommand>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
@ -341,8 +369,11 @@ pub async fn parse_block_range(
|
||||
if let NSSATransaction::PrivacyPreserving(tx) = nssa_tx {
|
||||
let mut affected_accounts = vec![];
|
||||
|
||||
for (acc_addr, (key_chain, _)) in
|
||||
&wallet_core.storage.user_data.user_private_accounts
|
||||
for (acc_addr, (key_chain, _)) in wallet_core
|
||||
.storage
|
||||
.user_data
|
||||
.default_user_private_accounts
|
||||
.iter()
|
||||
{
|
||||
let view_tag = EncryptedAccountData::compute_view_tag(
|
||||
key_chain.nullifer_public_key.clone(),
|
||||
@ -379,6 +410,51 @@ pub async fn parse_block_range(
|
||||
}
|
||||
}
|
||||
|
||||
for (_, keys_node) in wallet_core
|
||||
.storage
|
||||
.user_data
|
||||
.private_key_tree
|
||||
.key_map
|
||||
.iter()
|
||||
{
|
||||
let acc_addr = keys_node.address();
|
||||
let key_chain = &keys_node.value.0;
|
||||
|
||||
let view_tag = EncryptedAccountData::compute_view_tag(
|
||||
key_chain.nullifer_public_key.clone(),
|
||||
key_chain.incoming_viewing_public_key.clone(),
|
||||
);
|
||||
|
||||
for (ciph_id, encrypted_data) in tx
|
||||
.message()
|
||||
.encrypted_private_post_states
|
||||
.iter()
|
||||
.enumerate()
|
||||
{
|
||||
if encrypted_data.view_tag == view_tag {
|
||||
let ciphertext = &encrypted_data.ciphertext;
|
||||
let commitment = &tx.message.new_commitments[ciph_id];
|
||||
let shared_secret = key_chain
|
||||
.calculate_shared_secret_receiver(encrypted_data.epk.clone());
|
||||
|
||||
let res_acc = nssa_core::EncryptionScheme::decrypt(
|
||||
ciphertext,
|
||||
&shared_secret,
|
||||
commitment,
|
||||
ciph_id as u32,
|
||||
);
|
||||
|
||||
if let Some(res_acc) = res_acc {
|
||||
println!(
|
||||
"Received new account for addr {acc_addr:#?} with account object {res_acc:#?}"
|
||||
);
|
||||
|
||||
affected_accounts.push((acc_addr, res_acc));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (affected_addr, new_acc) in affected_accounts {
|
||||
wallet_core
|
||||
.storage
|
||||
@ -426,3 +502,12 @@ pub async fn execute_continious_run() -> Result<()> {
|
||||
latest_block_num = seq_client.get_last_block().await?.last_block;
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn execute_setup(password: String) -> Result<()> {
|
||||
let config = fetch_config().await?;
|
||||
let wallet_core = WalletCore::start_from_config_new_storage(config.clone(), password).await?;
|
||||
|
||||
wallet_core.store_persistent_data().await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
use anyhow::Result;
|
||||
use clap::{CommandFactory, Parser};
|
||||
use tokio::runtime::Builder;
|
||||
use wallet::{Args, execute_continious_run, execute_subcommand};
|
||||
use wallet::{Args, OverCommand, execute_continious_run, execute_setup, execute_subcommand};
|
||||
|
||||
pub const NUM_THREADS: usize = 2;
|
||||
|
||||
@ -17,8 +17,15 @@ fn main() -> Result<()> {
|
||||
env_logger::init();
|
||||
|
||||
runtime.block_on(async move {
|
||||
if let Some(command) = args.command {
|
||||
execute_subcommand(command).await.unwrap();
|
||||
if let Some(overcommand) = args.command {
|
||||
match overcommand {
|
||||
OverCommand::Command(command) => {
|
||||
execute_subcommand(command).await.unwrap();
|
||||
}
|
||||
OverCommand::Setup { password } => {
|
||||
execute_setup(password).await.unwrap();
|
||||
}
|
||||
}
|
||||
} else if args.continious_run {
|
||||
execute_continious_run().await.unwrap();
|
||||
} else {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user