Skip to content

Commit

Permalink
feat(auditor): cache beta participants to the disk
Browse files Browse the repository at this point in the history
  • Loading branch information
RolandSherwin authored and joshuef committed May 22, 2024
1 parent 0cf55fb commit 4380a4e
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 30 deletions.
4 changes: 3 additions & 1 deletion sn_auditor/src/dag_db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,15 @@ use std::{
pub const SPEND_DAG_FILENAME: &str = "spend_dag";
#[cfg(feature = "svg-dag")]
pub const SPEND_DAG_SVG_FILENAME: &str = "spend_dag.svg";
/// Store a locally copy to restore on restart
pub const BETA_PARTICIPANTS_FILENAME: &str = "beta_participants.txt";

/// Abstraction for the Spend DAG database
/// Currently in memory, with disk backup, but should probably be a real DB at scale
#[derive(Clone)]
pub struct SpendDagDb {
client: Option<Client>,
path: PathBuf,
pub(crate) path: PathBuf,
dag: Arc<RwLock<SpendDag>>,
forwarded_payments: Arc<RwLock<ForwardedPayments>>,
pub(crate) beta_participants: Arc<RwLock<BTreeMap<Hash, String>>>,
Expand Down
78 changes: 55 additions & 23 deletions sn_auditor/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,10 @@ extern crate tracing;
mod dag_db;
mod routes;

use dag_db::SpendDagDb;

use bls::SecretKey;
use clap::Parser;
use color_eyre::eyre::{eyre, Result};
use dag_db::SpendDagDb;
use sn_client::Client;
use sn_logging::{Level, LogBuilder, LogFormat, LogOutputDest};
use sn_peers_acquisition::get_peers_from_args;
Expand Down Expand Up @@ -83,23 +82,7 @@ async fn main() -> Result<()> {
let log_builder = logging_init(opt.log_output_dest, opt.log_format)?;
let _log_handles = log_builder.initialize()?;

let beta_participants = if let Some(participants_file) = opt.beta_participants {
let raw_data = std::fs::read_to_string(&participants_file)?;
// instead of serde_json, just use a line separated file
let discord_names = raw_data
.lines()
.map(|line| line.trim().to_string())
.collect::<Vec<String>>();

println!(
"Tracking beta rewards for the {} discord usernames provided in {:?}",
discord_names.len(),
participants_file
);
discord_names
} else {
Vec::new()
};
let beta_participants = load_and_update_beta_participants(opt.beta_participants)?;

let maybe_sk = if let Some(sk_str) = opt.beta_encryption_key {
match SecretKey::from_hex(&sk_str) {
Expand Down Expand Up @@ -208,10 +191,7 @@ async fn initialize_background_spend_dag_collection(
foundation_sk: Option<SecretKey>,
) -> Result<SpendDagDb> {
println!("Initialize spend dag...");
let path = dirs_next::data_dir()
.ok_or(eyre!("Could not obtain data directory path"))?
.join("safe")
.join("auditor");
let path = get_auditor_data_dir_path()?;

// clean the local spend DAG if requested
if clean {
Expand Down Expand Up @@ -318,3 +298,55 @@ async fn start_server(dag: SpendDagDb) -> Result<()> {
}
Ok(())
}

// get the data dir path for auditor
fn get_auditor_data_dir_path() -> Result<PathBuf> {
let path = dirs_next::data_dir()
.ok_or(eyre!("Could not obtain data directory path"))?
.join("safe")
.join("auditor");

Ok(path)
}

fn load_and_update_beta_participants(
provided_participants_file: Option<PathBuf>,
) -> Result<Vec<String>> {
let mut beta_participants = if let Some(participants_file) = provided_participants_file {
let raw_data = std::fs::read_to_string(&participants_file)?;
// instead of serde_json, just use a line separated file
let discord_names = raw_data
.lines()
.map(|line| line.trim().to_string())
.collect::<Vec<String>>();
println!(
"Tracking beta rewards for the {} discord usernames provided in {:?}",
discord_names.len(),
participants_file
);
discord_names
} else {
vec![]
};
// restore beta participants from local cached copy
let local_participants_file =
get_auditor_data_dir_path()?.join(dag_db::BETA_PARTICIPANTS_FILENAME);
if local_participants_file.exists() {
let raw_data = std::fs::read_to_string(&local_participants_file)?;
let discord_names = raw_data
.lines()
.map(|line| line.trim().to_string())
.collect::<Vec<String>>();
println!(
"Restoring beta rewards for the {} discord usernames from {:?}",
discord_names.len(),
local_participants_file
);
beta_participants.extend(discord_names);
}
// write the beta participants to disk
let _ = std::fs::write(local_participants_file, beta_participants.join("\n"))
.map_err(|e| eprintln!("Failed to write beta participants to disk: {e}"));

Ok(beta_participants)
}
46 changes: 40 additions & 6 deletions sn_auditor/src/routes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,15 @@
// KIND, either express or implied. Please review the Licences for the specific language governing
// permissions and limitations relating to use of the SAFE Network Software.

use crate::dag_db::{self, SpendDagDb};
use color_eyre::eyre::{eyre, Result};
use sn_client::transfers::SpendAddress;
use std::{io::Cursor, str::FromStr};
use std::{
fs::{File, OpenOptions},
io::{Cursor, Write},
path::PathBuf,
str::FromStr,
};
use tiny_http::{Request, Response};

pub(crate) fn spend_dag_svg(_dag: &SpendDagDb) -> Result<Response<Cursor<Vec<u8>>>> {
Expand Down Expand Up @@ -87,10 +93,38 @@ pub(crate) fn add_participant(
);
}

match dag.track_new_beta_participants(vec![discord_id.to_owned()]) {
Ok(()) => Ok(Response::from_string("Added participant")),
Err(e) => Ok(
Response::from_string(format!("Failed to add participant: {e}")).with_status_code(500),
),
if let Err(err) = dag.track_new_beta_participants(vec![discord_id.to_owned()]) {
return Ok(
Response::from_string(format!("Failed to add participant: {err}"))
.with_status_code(400),
);
}

// append the new participant to the local file
let local_participants_file = dag.path.join(dag_db::BETA_PARTICIPANTS_FILENAME);
if let Err(err) =
write_discord_id_to_local_file(&local_participants_file, discord_id.to_owned())
{
return Ok(
Response::from_string(format!("Failed to cache participant to file: {err}"))
.with_status_code(400),
);
}

Ok(Response::from_string("Successfully added participant "))
}

fn write_discord_id_to_local_file(path: &PathBuf, id: String) -> Result<()> {
if path.exists() {
let mut file = OpenOptions::new()
.append(true)
.open(path)
.map_err(|e| eyre!("Failed to open file: {e}"))?;
writeln!(file, "{id}")?;
} else {
let mut file = File::create(path).map_err(|e| eyre!("Failed to create file: {e}"))?;
writeln!(file, "{id}")?;
}

Ok(())
}

0 comments on commit 4380a4e

Please sign in to comment.