Add save processes and members to disk
This commit is contained in:
parent
5391dca929
commit
21711edd39
@ -18,7 +18,7 @@ use sdk_common::process::{lock_processes, Process, ProcessState, CACHEDPROCESSES
|
|||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
|
|
||||||
use crate::{lock_freezed_utxos, MutexExt, DAEMON, WALLET};
|
use crate::{lock_freezed_utxos, MutexExt, DAEMON, STORAGE, WALLET};
|
||||||
|
|
||||||
pub(crate) fn handle_commit_request(commit_msg: CommitMessage) -> Result<OutPoint> {
|
pub(crate) fn handle_commit_request(commit_msg: CommitMessage) -> Result<OutPoint> {
|
||||||
// Attempt to process the initial transaction or reference
|
// Attempt to process the initial transaction or reference
|
||||||
@ -96,6 +96,9 @@ fn handle_initial_transaction(tx: Transaction, commit_msg: &CommitMessage) -> Re
|
|||||||
new_process,
|
new_process,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Dump to disk
|
||||||
|
dump_cached_processes()?;
|
||||||
|
|
||||||
// Add to frozen UTXOs
|
// Add to frozen UTXOs
|
||||||
lock_freezed_utxos()?.insert(root_commitment);
|
lock_freezed_utxos()?.insert(root_commitment);
|
||||||
|
|
||||||
@ -146,10 +149,7 @@ fn handle_member_list(pcd_commitment: &Value, roles: &HashMap<String, RoleDefini
|
|||||||
|
|
||||||
// Handle the case where `init_tx` is a reference to an existing outpoint
|
// Handle the case where `init_tx` is a reference to an existing outpoint
|
||||||
fn handle_existing_commitment(outpoint: OutPoint, commit_msg: CommitMessage) -> Result<OutPoint> {
|
fn handle_existing_commitment(outpoint: OutPoint, commit_msg: CommitMessage) -> Result<OutPoint> {
|
||||||
let mut commitments = CACHEDPROCESSES
|
let mut commitments = lock_processes()?;
|
||||||
.get()
|
|
||||||
.ok_or(Error::msg("CACHEDPROCESSES not initialized"))?
|
|
||||||
.lock_anyhow()?;
|
|
||||||
let commitment = commitments
|
let commitment = commitments
|
||||||
.get_mut(&outpoint)
|
.get_mut(&outpoint)
|
||||||
.ok_or(Error::msg("Commitment not found"))?;
|
.ok_or(Error::msg("Commitment not found"))?;
|
||||||
@ -161,6 +161,20 @@ fn handle_existing_commitment(outpoint: OutPoint, commit_msg: CommitMessage) ->
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn dump_cached_processes() -> Result<(), anyhow::Error> {
|
||||||
|
let processes = lock_processes()?.clone();
|
||||||
|
|
||||||
|
let storage = STORAGE.get().ok_or(Error::msg("STORAGE is not initialized"))?.lock_anyhow()?;
|
||||||
|
|
||||||
|
let processes_file = &storage.processes_file;
|
||||||
|
|
||||||
|
processes_file.save(&processes)?;
|
||||||
|
|
||||||
|
log::debug!("saved processes");
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
// Register a new state when validation tokens are empty
|
// Register a new state when validation tokens are empty
|
||||||
fn register_new_state(commitment: &mut Process, commit_msg: CommitMessage) -> Result<OutPoint> {
|
fn register_new_state(commitment: &mut Process, commit_msg: CommitMessage) -> Result<OutPoint> {
|
||||||
let concurrent_states = commitment.get_latest_concurrent_states()?;
|
let concurrent_states = commitment.get_latest_concurrent_states()?;
|
||||||
|
103
src/main.rs
103
src/main.rs
@ -11,11 +11,12 @@ use std::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use bitcoincore_rpc::json::{self as bitcoin_json};
|
use bitcoincore_rpc::json::{self as bitcoin_json};
|
||||||
|
use commit::MEMBERLIST;
|
||||||
use futures_util::{future, pin_mut, stream::TryStreamExt, FutureExt, StreamExt};
|
use futures_util::{future, pin_mut, stream::TryStreamExt, FutureExt, StreamExt};
|
||||||
use log::{debug, error, warn};
|
use log::{debug, error, warn};
|
||||||
use message::{broadcast_message, process_message, BroadcastType, MessageCache, MESSAGECACHE};
|
use message::{broadcast_message, process_message, BroadcastType, MessageCache, MESSAGECACHE};
|
||||||
use scan::{check_transaction_alone, compute_partial_tweak_to_transaction};
|
use scan::{check_transaction_alone, compute_partial_tweak_to_transaction};
|
||||||
use sdk_common::{network::InitMessage, process::CACHEDPROCESSES, sp_client::{bitcoin::{
|
use sdk_common::{network::InitMessage, pcd::Member, process::{Process, CACHEDPROCESSES}, sp_client::{bitcoin::{
|
||||||
consensus::deserialize,
|
consensus::deserialize,
|
||||||
hex::{DisplayHex, FromHex},
|
hex::{DisplayHex, FromHex},
|
||||||
Amount, Network, Transaction,
|
Amount, Network, Transaction,
|
||||||
@ -31,6 +32,7 @@ use sdk_common::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use sdk_common::sp_client::spclient::{derive_keys_from_seed, SpClient, SpendKey};
|
use sdk_common::sp_client::spclient::{derive_keys_from_seed, SpClient, SpendKey};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
use tokio::net::{TcpListener, TcpStream};
|
use tokio::net::{TcpListener, TcpStream};
|
||||||
use tokio::sync::mpsc::{unbounded_channel, UnboundedSender};
|
use tokio::sync::mpsc::{unbounded_channel, UnboundedSender};
|
||||||
use tokio_stream::wrappers::UnboundedReceiverStream;
|
use tokio_stream::wrappers::UnboundedReceiverStream;
|
||||||
@ -75,11 +77,11 @@ pub struct PublicLists {
|
|||||||
pub static LISTS: OnceLock<Mutex<PublicLists>> = OnceLock::new();
|
pub static LISTS: OnceLock<Mutex<PublicLists>> = OnceLock::new();
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct WalletFile {
|
pub struct StateFile {
|
||||||
path: PathBuf,
|
path: PathBuf,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WalletFile {
|
impl StateFile {
|
||||||
fn new(path: PathBuf) -> Self {
|
fn new(path: PathBuf) -> Self {
|
||||||
Self { path }
|
Self { path }
|
||||||
}
|
}
|
||||||
@ -95,46 +97,56 @@ impl WalletFile {
|
|||||||
return Err(Error::msg("wallet file has no parent dir"));
|
return Err(Error::msg("wallet file has no parent dir"));
|
||||||
}
|
}
|
||||||
|
|
||||||
// check that parent exists
|
// Ensure the parent directory exists
|
||||||
if !parent.exists() {
|
if !parent.exists() {
|
||||||
fs::create_dir_all(parent)?;
|
fs::create_dir_all(parent)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
fs::File::create_new(&self.path)?;
|
// Create a new file
|
||||||
|
fs::File::create(&self.path)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn save(&self, new_value: &SpWallet) -> Result<()> {
|
fn save<T: Serialize>(&self, data: &T) -> Result<()> {
|
||||||
let mut f = fs::File::options()
|
let mut f = fs::File::options()
|
||||||
.write(true)
|
.write(true)
|
||||||
.truncate(true)
|
.truncate(true)
|
||||||
.open(&self.path)?;
|
.open(&self.path)?;
|
||||||
|
|
||||||
let json = serde_json::to_string(new_value)?;
|
let json = serde_json::to_string(data)?;
|
||||||
f.write_all(json.as_bytes())?;
|
f.write_all(json.as_bytes())?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load(&self) -> Result<SpWallet> {
|
fn load<T: for<'de> Deserialize<'de>>(&self) -> Result<T> {
|
||||||
let mut f = fs::File::open(&self.path)?;
|
let mut f = fs::File::open(&self.path)?;
|
||||||
|
|
||||||
let mut content = vec![];
|
let mut content = vec![];
|
||||||
f.read_to_end(&mut content)?;
|
f.read_to_end(&mut content)?;
|
||||||
|
|
||||||
let res: SpWallet = serde_json::from_slice(&content)?;
|
let res: T = serde_json::from_slice(&content)?;
|
||||||
|
|
||||||
Ok(res)
|
Ok(res)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct DiskStorage {
|
||||||
|
// wallet_file: StateFile,
|
||||||
|
pub processes_file: StateFile,
|
||||||
|
pub members_file: StateFile,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub static STORAGE: OnceLock<Mutex<DiskStorage>> = OnceLock::new();
|
||||||
|
|
||||||
const FAUCET_AMT: Amount = Amount::from_sat(100_000);
|
const FAUCET_AMT: Amount = Amount::from_sat(100_000);
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct SilentPaymentWallet {
|
struct SilentPaymentWallet {
|
||||||
sp_wallet: Mutex<SpWallet>,
|
sp_wallet: Mutex<SpWallet>,
|
||||||
storage: Mutex<WalletFile>,
|
storage: Mutex<StateFile>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SilentPaymentWallet {
|
impl SilentPaymentWallet {
|
||||||
@ -143,7 +155,7 @@ impl SilentPaymentWallet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn save(&self) -> Result<()> {
|
pub fn save(&self) -> Result<()> {
|
||||||
let wallet = self.sp_wallet.lock_anyhow()?;
|
let wallet = self.sp_wallet.lock_anyhow()?.clone();
|
||||||
self.storage.lock_anyhow()?.save(&wallet)
|
self.storage.lock_anyhow()?.save(&wallet)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -329,10 +341,6 @@ async fn main() -> Result<()> {
|
|||||||
warn!("Running on mainnet, you're on your own");
|
warn!("Running on mainnet, you're on your own");
|
||||||
}
|
}
|
||||||
|
|
||||||
CACHEDPROCESSES
|
|
||||||
.set(Mutex::new(HashMap::new()))
|
|
||||||
.expect("CachedProcesses initialization failed");
|
|
||||||
|
|
||||||
MESSAGECACHE
|
MESSAGECACHE
|
||||||
.set(MessageCache::new())
|
.set(MessageCache::new())
|
||||||
.expect("Message Cache initialization failed");
|
.expect("Message Cache initialization failed");
|
||||||
@ -361,19 +369,34 @@ async fn main() -> Result<()> {
|
|||||||
app_dir.push(".4nk");
|
app_dir.push(".4nk");
|
||||||
let mut wallet_file = app_dir.clone();
|
let mut wallet_file = app_dir.clone();
|
||||||
wallet_file.push(&config.wallet_name);
|
wallet_file.push(&config.wallet_name);
|
||||||
|
let mut processes_file = app_dir.clone();
|
||||||
|
processes_file.push("processes");
|
||||||
|
let mut members_file = app_dir.clone();
|
||||||
|
members_file.push("members");
|
||||||
|
|
||||||
let wallet_file = WalletFile::new(wallet_file);
|
let wallet_file = StateFile::new(wallet_file);
|
||||||
|
let processes_file = StateFile::new(processes_file);
|
||||||
|
let members_file = StateFile::new(members_file);
|
||||||
|
|
||||||
// load an existing sp_wallet, or create a new one
|
// load an existing sp_wallet, or create a new one
|
||||||
let sp_wallet = match wallet_file.load() {
|
let sp_wallet = match wallet_file.load() {
|
||||||
|
Ok(wallet) => {
|
||||||
|
// TODO: Verify the wallet is compatible with the current network
|
||||||
|
wallet
|
||||||
|
}
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
|
// Create a new wallet file if it doesn't exist or fails to load
|
||||||
wallet_file.create()?;
|
wallet_file.create()?;
|
||||||
|
|
||||||
|
// Generate a seed and derive keys
|
||||||
let mut seed = [0u8; 64];
|
let mut seed = [0u8; 64];
|
||||||
thread_rng().fill(&mut seed);
|
thread_rng().fill(&mut seed);
|
||||||
|
|
||||||
let (scan_sk, spend_sk) = derive_keys_from_seed(&seed, config.network)
|
let (scan_sk, spend_sk) = derive_keys_from_seed(&seed, config.network)
|
||||||
.expect("Couldn't generate a new sp_wallet");
|
.expect("Couldn't generate a new sp_wallet");
|
||||||
|
|
||||||
let new_client = SpClient::new(
|
let new_client = SpClient::new(
|
||||||
config.wallet_name,
|
config.wallet_name.clone(),
|
||||||
scan_sk,
|
scan_sk,
|
||||||
SpendKey::Secret(spend_sk),
|
SpendKey::Secret(spend_sk),
|
||||||
None,
|
None,
|
||||||
@ -381,16 +404,41 @@ async fn main() -> Result<()> {
|
|||||||
)
|
)
|
||||||
.expect("Failed to create a new SpClient");
|
.expect("Failed to create a new SpClient");
|
||||||
|
|
||||||
|
// Initialize a new wallet with the generated client
|
||||||
let mut wallet = SpWallet::new(new_client, None, vec![])?;
|
let mut wallet = SpWallet::new(new_client, None, vec![])?;
|
||||||
|
|
||||||
// set birthday to avoid unnecessary scanning
|
// Set birthday and update scan information
|
||||||
let outputs = wallet.get_mut_outputs();
|
let outputs = wallet.get_mut_outputs();
|
||||||
outputs.set_birthday(current_tip);
|
outputs.set_birthday(current_tip);
|
||||||
outputs.update_last_scan(current_tip);
|
outputs.update_last_scan(current_tip);
|
||||||
|
|
||||||
|
// Save the newly created wallet to disk
|
||||||
|
wallet_file.save(&wallet)?;
|
||||||
|
|
||||||
wallet
|
wallet
|
||||||
}
|
}
|
||||||
Ok(wallet) => wallet, // TODO check network
|
};
|
||||||
|
|
||||||
|
let cached_processes: HashMap<OutPoint, Process> = match processes_file.load() {
|
||||||
|
Ok(processes) => {
|
||||||
|
processes
|
||||||
|
}
|
||||||
|
Err(_) => {
|
||||||
|
debug!("creating process file at {}", processes_file.path.display());
|
||||||
|
processes_file.create()?;
|
||||||
|
|
||||||
|
HashMap::new()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let members: HashMap<Member, OutPoint> = match members_file.load() {
|
||||||
|
Ok(members) => members,
|
||||||
|
Err(_) => {
|
||||||
|
debug!("creating members file at {}", members_file.path.display());
|
||||||
|
members_file.create()?;
|
||||||
|
|
||||||
|
HashMap::new()
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let our_sp_address = sp_wallet.get_client().get_receiving_address();
|
let our_sp_address = sp_wallet.get_client().get_receiving_address();
|
||||||
@ -418,6 +466,23 @@ async fn main() -> Result<()> {
|
|||||||
|
|
||||||
WALLET.get().unwrap().save().unwrap();
|
WALLET.get().unwrap().save().unwrap();
|
||||||
|
|
||||||
|
CACHEDPROCESSES
|
||||||
|
.set(Mutex::new(cached_processes))
|
||||||
|
.expect("Failed to initialize CACHEDPROCESSES");
|
||||||
|
|
||||||
|
MEMBERLIST
|
||||||
|
.set(Mutex::new(members))
|
||||||
|
.expect("Failed to initialize MEMBERLIST");
|
||||||
|
|
||||||
|
let storage = DiskStorage {
|
||||||
|
processes_file,
|
||||||
|
members_file,
|
||||||
|
};
|
||||||
|
|
||||||
|
STORAGE
|
||||||
|
.set(Mutex::new(storage))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
if last_scan < current_tip {
|
if last_scan < current_tip {
|
||||||
log::info!("Scanning for our outputs");
|
log::info!("Scanning for our outputs");
|
||||||
scan_blocks(current_tip - last_scan, &config.electrum_url)?;
|
scan_blocks(current_tip - last_scan, &config.electrum_url)?;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user