Skip to content

Commit

Permalink
feat(auditor): add new beta participants via endpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
RolandSherwin authored and joshuef committed May 22, 2024
1 parent 537f224 commit 0cf55fb
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 53 deletions.
2 changes: 1 addition & 1 deletion node-launchpad/src/components/discord_username.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ impl Component for DiscordUsernameInputBox {
}
_ => {
// max 32 limit as per discord docs
if self.discord_input_filed.value().len() >= 32 {
if self.discord_input_filed.value().chars().count() >= 32 {
return Ok(vec![]);
}
self.discord_input_filed.handle_event(&Event::Key(key));
Expand Down
99 changes: 60 additions & 39 deletions sn_auditor/src/dag_db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
// permissions and limitations relating to use of the SAFE Network Software.

use bls::SecretKey;
#[cfg(feature = "svg-dag")]
use color_eyre::eyre::Context;
use color_eyre::eyre::{bail, eyre, Result};
#[cfg(feature = "svg-dag")]
use graphviz_rust::{cmd::Format, exec, parse, printer::PrinterContext};
Expand Down Expand Up @@ -35,7 +37,7 @@ pub struct SpendDagDb {
path: PathBuf,
dag: Arc<RwLock<SpendDag>>,
forwarded_payments: Arc<RwLock<ForwardedPayments>>,
beta_participants: BTreeMap<Hash, String>,
pub(crate) beta_participants: Arc<RwLock<BTreeMap<Hash, String>>>,
encryption_sk: Option<SecretKey>,
}

Expand All @@ -54,8 +56,13 @@ impl SpendDagDb {
/// Create a new SpendDagDb
/// If a local spend DAG file is found, it will be loaded
/// Else a new DAG will be created containing only Genesis
pub async fn new(path: PathBuf, client: Client) -> Result<Self> {
pub async fn new(
path: PathBuf,
client: Client,
encryption_sk: Option<SecretKey>,
) -> Result<Self> {
let dag_path = path.join(SPEND_DAG_FILENAME);
info!("Loading DAG from {dag_path:?}...");
let dag = match SpendDag::load_from_file(&dag_path) {
Ok(d) => {
println!("Found a local spend DAG file");
Expand All @@ -72,13 +79,18 @@ impl SpendDagDb {
path,
dag: Arc::new(RwLock::new(dag)),
forwarded_payments: Arc::new(RwLock::new(BTreeMap::new())),
beta_participants: BTreeMap::new(),
encryption_sk: None,
beta_participants: Arc::new(RwLock::new(BTreeMap::new())),
encryption_sk,
})
}

// Check if the DAG has an encryption secret key set
pub fn has_encryption_sk(&self) -> bool {
self.encryption_sk.is_some()
}

/// Create a new SpendDagDb from a local file and no network connection
pub fn offline(dag_path: PathBuf) -> Result<Self> {
pub fn offline(dag_path: PathBuf, encryption_sk: Option<SecretKey>) -> Result<Self> {
let path = dag_path
.parent()
.ok_or_else(|| eyre!("Failed to get parent path"))?
Expand All @@ -89,16 +101,11 @@ impl SpendDagDb {
path,
dag: Arc::new(RwLock::new(dag)),
forwarded_payments: Arc::new(RwLock::new(BTreeMap::new())),
beta_participants: BTreeMap::new(),
encryption_sk: None,
beta_participants: Arc::new(RwLock::new(BTreeMap::new())),
encryption_sk,
})
}

/// Set encryption secret key for beta program
pub fn set_encryption_sk(&mut self, sk: Option<SecretKey>) {
self.encryption_sk = sk;
}

/// Get info about a single spend in JSON format
pub fn spend_json(&self, address: SpendAddress) -> Result<String> {
let dag_ref = self.dag.clone();
Expand Down Expand Up @@ -150,7 +157,8 @@ impl SpendDagDb {
#[cfg(feature = "svg-dag")]
pub fn load_svg(&self) -> Result<Vec<u8>> {
let svg_path = self.path.join(SPEND_DAG_SVG_FILENAME);
let svg = std::fs::read(svg_path)?;
let svg = std::fs::read(&svg_path)
.context(format!("Could not load svg from path: {svg_path:?}"))?;
Ok(svg)
}

Expand Down Expand Up @@ -190,12 +198,12 @@ impl SpendDagDb {
.await?;

// write update to DAG
let dag_ref = self.dag.clone();
let mut w_handle = dag_ref
let mut dag_w_handle = self
.dag
.write()
.map_err(|e| eyre!("Failed to get write lock: {e}"))?;
*w_handle = dag;
std::mem::drop(w_handle);
*dag_w_handle = dag;
std::mem::drop(dag_w_handle);

#[cfg(feature = "svg-dag")]
{
Expand All @@ -210,7 +218,7 @@ impl SpendDagDb {
}

// gather forwarded payments in a background thread so we don't block
let mut self_clone = self.clone();
let self_clone = self.clone();
tokio::spawn(async move {
if let Err(e) = self_clone.gather_forwarded_payments().await {
error!("Failed to gather forwarded payments: {e}");
Expand All @@ -224,8 +232,8 @@ impl SpendDagDb {
/// This can be used to enrich our DAG with a DAG from another node to avoid costly computations
/// Make sure to verify the other DAG is trustworthy before calling this function to merge it in
pub fn merge(&mut self, other: SpendDag) -> Result<()> {
let dag_ref = self.dag.clone();
let mut w_handle = dag_ref
let mut w_handle = self
.dag
.write()
.map_err(|e| eyre!("Failed to get write lock: {e}"))?;
w_handle.merge(other, true)?;
Expand All @@ -252,34 +260,44 @@ impl SpendDagDb {
Ok(json)
}

/// Initialize reward forward tracking, gathers current rewards from the DAG
pub(crate) async fn init_reward_forward_tracking(
&mut self,
participants: Vec<String>,
sk: SecretKey,
) -> Result<()> {
self.beta_participants = participants
.iter()
.map(|h| (Hash::hash(h.as_bytes()), h.clone()))
.collect();
/// Track new beta participants. This just add the participants to the list of tracked participants.
pub(crate) fn track_new_beta_participants(&self, participants: Vec<String>) -> Result<()> {
// track new participants
{
let w_handle = self.forwarded_payments.clone();
let mut fwd_payments = w_handle
let mut beta_participants = self
.beta_participants
.write()
.map_err(|e| eyre!("Failed to get beta participants write lock: {e}"))?;
for p in participants.iter() {
beta_participants.insert(Hash::hash(p.as_bytes()), p.clone());
}
}
// initialize forwarded payments
{
let mut fwd_payments = self
.forwarded_payments
.write()
.map_err(|e| eyre!("Failed to get forwarded payments write lock: {e}"))?;
*fwd_payments = participants
.into_iter()
.map(|n| (n, BTreeSet::new()))
.collect();
}
self.encryption_sk = Some(sk);
Ok(())
}

/// Initialize reward forward tracking, gathers current rewards from the DAG
pub(crate) async fn init_reward_forward_tracking(
&self,
participants: Vec<String>,
) -> Result<()> {
self.track_new_beta_participants(participants)?;
self.gather_forwarded_payments().await?;
Ok(())
}

// Gather forwarded payments from the DAG
pub(crate) async fn gather_forwarded_payments(&mut self) -> Result<()> {
pub(crate) async fn gather_forwarded_payments(&self) -> Result<()> {
info!("Gathering forwarded payments...");

// make sure we have the foundation secret key
Expand All @@ -289,8 +307,7 @@ impl SpendDagDb {
.ok_or_else(|| eyre!("Foundation secret key not set"))?;

// get spends from current DAG
let r_handle = self.dag.clone();
let dag = r_handle.read().map_err(|e| {
let dag = self.dag.read().map_err(|e| {
eyre!("Failed to get dag read lock for gathering forwarded payments: {e}")
})?;
let all_spends = dag.all_spends();
Expand All @@ -304,7 +321,11 @@ impl SpendDagDb {
};
let addr = spend.address();
let amount = spend.spend.amount;
if let Some(user_name) = self.beta_participants.get(&user_name_hash) {
let beta_participants_read = self
.beta_participants
.read()
.map_err(|e| eyre!("Failed to get payments write lock: {e}"))?;
if let Some(user_name) = beta_participants_read.get(&user_name_hash) {
debug!("Got forwarded reward from {user_name} of {amount} at {addr:?}");
payments
.entry(user_name.to_owned())
Expand All @@ -323,8 +344,8 @@ impl SpendDagDb {
}

// save new payments
let w_handle = self.forwarded_payments.clone();
let mut self_payments = w_handle
let mut self_payments = self
.forwarded_payments
.write()
.map_err(|e| eyre!("Failed to get payments write lock: {e}"))?;
self_payments.extend(payments);
Expand Down
20 changes: 9 additions & 11 deletions sn_auditor/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,11 +112,10 @@ async fn main() -> Result<()> {
let beta_rewards_on = maybe_sk.is_some();

if let Some(dag_to_view) = opt.offline_viewer {
let mut dag = SpendDagDb::offline(dag_to_view)?;
let dag = SpendDagDb::offline(dag_to_view, maybe_sk)?;
#[cfg(feature = "svg-dag")]
dag.dump_dag_svg()?;

dag.set_encryption_sk(maybe_sk);
start_server(dag).await?;
return Ok(());
}
Expand Down Expand Up @@ -222,7 +221,7 @@ async fn initialize_background_spend_dag_collection(
}

// initialize the DAG
let dag = dag_db::SpendDagDb::new(path.clone(), client.clone())
let dag = dag_db::SpendDagDb::new(path.clone(), client.clone(), foundation_sk)
.await
.map_err(|e| eyre!("Could not create SpendDag Db: {e}"))?;

Expand Down Expand Up @@ -250,17 +249,15 @@ async fn initialize_background_spend_dag_collection(

// initialize beta rewards program tracking
if !beta_participants.is_empty() {
let sk = match foundation_sk {
Some(sk) => sk,
None => panic!("Foundation SK required to initialize beta rewards program"),
if !dag.has_encryption_sk() {
panic!("Foundation SK required to initialize beta rewards program");
};

println!("Initializing beta rewards program tracking...");
let mut d = dag.clone();
let _ = d
.init_reward_forward_tracking(beta_participants, sk)
.await
.map_err(|e| eprintln!("Could not initialize beta rewards: {e}"));
if let Err(e) = dag.init_reward_forward_tracking(beta_participants).await {
eprintln!("Could not initialize beta rewards: {e}");
return Err(e);
}
}

// background thread to update DAG
Expand Down Expand Up @@ -298,6 +295,7 @@ async fn start_server(dag: SpendDagDb) -> Result<()> {
let response = match request.url() {
"/" => routes::spend_dag_svg(&dag),
s if s.starts_with("/spend/") => routes::spend(&dag, &request),
s if s.starts_with("/add-participant/") => routes::add_participant(&dag, &request),
"/beta-rewards" => routes::beta_rewards(&dag),
_ => routes::not_found(),
};
Expand Down
30 changes: 28 additions & 2 deletions sn_auditor/src/routes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@ use sn_client::transfers::SpendAddress;
use std::{io::Cursor, str::FromStr};
use tiny_http::{Request, Response};

use crate::dag_db::SpendDagDb;

pub(crate) fn spend_dag_svg(_dag: &SpendDagDb) -> Result<Response<Cursor<Vec<u8>>>> {
#[cfg(not(feature = "svg-dag"))]
return Ok(Response::from_string(
Expand Down Expand Up @@ -68,3 +66,31 @@ pub(crate) fn beta_rewards(dag: &SpendDagDb) -> Result<Response<Cursor<Vec<u8>>>
let response = Response::from_data(json);
Ok(response)
}

pub(crate) fn add_participant(
dag: &SpendDagDb,
request: &Request,
) -> Result<Response<Cursor<Vec<u8>>>> {
let discord_id = match request.url().split('/').last() {
Some(discord_id) => discord_id,
None => {
return Ok(Response::from_string(
"No discord_id provided. Should be /add-participant/[your_discord_id_here]",
)
.with_status_code(400))
}
};

if discord_id.chars().count() >= 32 {
return Ok(
Response::from_string("discord_id cannot be more than 32 chars").with_status_code(400),
);
}

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),
),
}
}

0 comments on commit 0cf55fb

Please sign in to comment.