From 33a76fcd633bdddc56c68325287c4dc7443521cd Mon Sep 17 00:00:00 2001 From: kn0sys Date: Fri, 6 Sep 2024 05:54:26 -0400 Subject: [PATCH] serialization and db patches --- neveko-core/src/auth.rs | 79 ++++++++------------- neveko-core/src/contact.rs | 40 +++++------ neveko-core/src/db.rs | 29 +++----- neveko-core/src/dispute.rs | 119 ++++++++++++++++++------------- neveko-core/src/error.rs | 4 +- neveko-core/src/proof.rs | 10 +-- neveko-core/src/user.rs | 8 +-- neveko-core/src/utils.rs | 142 +++++++++++++++++++++---------------- 8 files changed, 222 insertions(+), 209 deletions(-) diff --git a/neveko-core/src/auth.rs b/neveko-core/src/auth.rs index 941abee..b7fd7dc 100644 --- a/neveko-core/src/auth.rs +++ b/neveko-core/src/auth.rs @@ -47,8 +47,8 @@ pub fn create(address: &String) -> Result { token, xmr_address: String::from(address), }; - let env = utils::get_release_env(); - let s = db::DatabaseEnvironment::open(&env.value())?; + + let s = db::DatabaseEnvironment::open()?; debug!("insert auth: {:?}", &new_auth); let k = &new_auth.aid.as_bytes(); let v = bincode::serialize(&new_auth).unwrap_or_default(); @@ -59,8 +59,8 @@ pub fn create(address: &String) -> Result { /// Authorization lookup for recurring requests pub fn find(aid: &String) -> Result { info!("searching for auth: {}", aid); - let env = utils::get_release_env(); - let s = db::DatabaseEnvironment::open(&env.value())?; + + let s = db::DatabaseEnvironment::open()?; let r = db::DatabaseEnvironment::read(&s.env, &s.handle?, &aid.as_bytes().to_vec())?; if r.is_empty() { return Err(MdbError::NotFound); @@ -81,12 +81,12 @@ fn update_expiration(f_auth: &Authorization, address: &String) -> Result Result let u: User = user::create(&address)?; // update auth with uid let u_auth = Authorization::update_uid(f_auth, String::from(&u.uid)); - let env = utils::get_release_env(); - let s = db::DatabaseEnvironment::open(&env.value())?; + + let s = db::DatabaseEnvironment::open()?; db::DatabaseEnvironment::delete(&s.env, &s.handle?, &u_auth.aid.as_bytes()); let v = bincode::serialize(&u_auth).unwrap_or_default(); - let s = db::DatabaseEnvironment::open(&env.value())?; + let s = db::DatabaseEnvironment::open()?; db::write_chunks(&s.env, &s.handle?, u_auth.aid.as_bytes(), &v); monero::close_wallet(&wallet_name, &wallet_password).await; Ok(u_auth) @@ -185,7 +185,7 @@ fn get_auth_expiration() -> i64 { } fn create_token(address: String, created: i64) -> String { - let jwt_secret_key = utils::get_jwt_secret_key(); + let jwt_secret_key = utils::get_jwt_secret_key().unwrap_or_default(); let key: Hmac = Hmac::new_from_slice(jwt_secret_key.as_bytes()).expect("hash"); let header = Header { algorithm: AlgorithmType::Hs384, @@ -239,7 +239,7 @@ impl<'r> FromRequest<'r> for BearerToken { match token { Some(token) => { // check validity - let jwt_secret_key = utils::get_jwt_secret_key(); + let jwt_secret_key = utils::get_jwt_secret_key().unwrap_or_default(); let key: Hmac = Hmac::new_from_slice(jwt_secret_key.as_bytes()).expect(""); let jwt: Result< Token, _>, @@ -282,22 +282,21 @@ impl<'r> FromRequest<'r> for BearerToken { mod tests { use super::*; - async fn find_test_auth(k: &String) -> Result { - tokio::time::sleep(std::time::Duration::from_secs(1)).await; - let s: db::Interface = db::DatabaseEnvironment::async_open("test").await; - let v = db::DatabaseEnvironment::read(&s.env, &s.handle, k).await; - Authorization::from_db(String::from(k), v) + fn find_test_auth(k: &String) -> Result { + let s: db::Interface = db::DatabaseEnvironment::open()?; + let v = db::DatabaseEnvironment::read(&s.env, &s.handle, &k.as_bytes().to_vec())?; + let result: Authorization = bincode::deserialize(&v[..]).unwrap_or_default(); + Ok(result) } - async fn cleanup(k: &String) -> Result<(), MdbError>{ - tokio::time::sleep(std::time::Duration::from_secs(1)).await; - let s = db::DatabaseEnvironment::open("test").await?; - db::DatabaseEnvironment::delete(&s.env, &s.handle?, k).await; + fn cleanup(k: &String) -> Result<(), MdbError>{ + let s = db::DatabaseEnvironment::open()?; + db::DatabaseEnvironment::delete(&s.env, &s.handle?, k.as_bytes())?; + Ok(()) } #[test] fn create_test() { - // run and async cleanup so the test doesn't fail when deleting test data use tokio::runtime::Runtime; let rt = Runtime::new().expect("Unable to create Runtime for test"); let _enter = rt.enter(); @@ -306,49 +305,33 @@ mod tests { ); let test_auth = create(&address); assert_eq!(test_auth.xmr_address, address); - tokio::spawn(async move { - cleanup(&test_auth.aid).await; - }); - Runtime::shutdown_background(rt); + cleanup(&test_auth.aid); } #[test] - fn find_test() { - // run and async cleanup so the test doesn't fail when deleting test data - use tokio::runtime::Runtime; - let rt = Runtime::new().expect("Unable to create Runtime for test"); - let _enter = rt.enter(); + fn find_test() -> Result<(), MdbError> { let address: String = String::from( "73a4nWuvkYoYoksGurDjKZQcZkmaxLaKbbeiKzHnMmqKivrCzq5Q2JtJG1UZNZFqLPbQ3MiXCk2Q5bdwdUNSr7X9QrPubkn" ); let test_auth = create(&address); let aid = String::from(&test_auth.aid); - tokio::spawn(async move { - let f_auth: Authorization = find_test_auth(&aid).await; - assert_ne!(f_auth.xmr_address, address); - cleanup(&test_auth.aid).await; - }); - Runtime::shutdown_background(rt); + let f_auth: Authorization = find_test_auth(&aid); + assert_ne!(f_auth.xmr_address, address); + cleanup(&test_auth.aid); + Ok(()) } #[test] fn update_expiration_test() { - // run and async cleanup so the test doesn't fail when deleting test data - use tokio::runtime::Runtime; - let rt = Runtime::new().expect("Unable to create Runtime for test"); - let _enter = rt.enter(); let address: String = String::from( "73a4nWuvkYoYoksGurDjKZQcZkmaxLaKbbeiKzHnMmqKivrCzq5Q2JtJG1UZNZFqLPbQ3MiXCk2Q5bdwdUNSr7X9QrPubkn" ); let test_auth = create(&address); let aid = String::from(&test_auth.aid); - tokio::spawn(async move { - let f_auth = find_test_auth(&aid).await; - let u_auth = update_expiration(&f_auth, &address); - assert!(f_auth.created < u_auth.created); - cleanup(&test_auth.aid).await; - }); - Runtime::shutdown_background(rt); + let f_auth = find_test_auth(&aid); + let u_auth = update_expiration(&f_auth, &address); + assert!(f_auth.created < u_auth.created); + cleanup(&test_auth.aid); } #[test] diff --git a/neveko-core/src/contact.rs b/neveko-core/src/contact.rs index c2ce722..d23bb07 100644 --- a/neveko-core/src/contact.rs +++ b/neveko-core/src/contact.rs @@ -39,15 +39,15 @@ pub async fn create(c: &Json) -> Result { return Ok(Default::default()); } debug!("insert contact: {:?}", &new_contact); - let env = utils::get_release_env(); - let s = db::DatabaseEnvironment::open(&env.value())?; + + let s = db::DatabaseEnvironment::open()?; let k = &new_contact.cid; let v = bincode::serialize(&new_contact).unwrap_or_default(); db::write_chunks(&s.env, &s.handle?, k.as_bytes(), &v); // in order to retrieve all contact, write keys to with cl let list_key = crate::CONTACT_LIST_DB_KEY; let str_lk = String::from(list_key); - let s = db::DatabaseEnvironment::open(&env.value())?; + let s = db::DatabaseEnvironment::open()?; let lk_bytes = str_lk.as_bytes(); let r = db::DatabaseEnvironment::read(&s.env, &s.handle?, &lk_bytes.to_vec())?; if r.is_empty() { @@ -59,15 +59,15 @@ pub async fn create(c: &Json) -> Result { "writing contact index {} for key {}", contact_list, list_key ); - let s = db::DatabaseEnvironment::open(&env.value())?; + let s = db::DatabaseEnvironment::open()?; db::write_chunks(&s.env, &s.handle?, list_key.as_bytes(), &contact_list.as_bytes()); Ok(new_contact) } /// Contact lookup pub fn find(cid: &String) -> Result { - let env = utils::get_release_env(); - let s = db::DatabaseEnvironment::open(&env.value())?; + + let s = db::DatabaseEnvironment::open()?; let r = db::DatabaseEnvironment::read(&s.env, &s.handle?, &cid.as_bytes().to_vec())?; if r.is_empty() { error!("contact not found"); @@ -90,14 +90,14 @@ pub fn find_by_i2p_address(i2p_address: &String) -> Result { /// Contact deletion pub fn delete(cid: &String) -> Result<(), MdbError> { - let env = utils::get_release_env(); - let s = db::DatabaseEnvironment::open(&env.value())?; + + let s = db::DatabaseEnvironment::open()?; let r = db::DatabaseEnvironment::read(&s.env, &s.handle?, &cid.as_bytes().to_vec())?; if r.is_empty() { error!("contact not found"); return Err(MdbError::NotFound); } - let s = db::DatabaseEnvironment::open(&env.value())?; + let s = db::DatabaseEnvironment::open()?; db::DatabaseEnvironment::delete(&s.env, &s.handle?, cid.as_bytes()); Ok(()) } @@ -105,8 +105,8 @@ pub fn delete(cid: &String) -> Result<(), MdbError> { /// All contact lookup pub fn find_all() -> Result, MdbError> { info!("looking up all contacts"); - let env = utils::get_release_env(); - let s = db::DatabaseEnvironment::open(&env.value())?; + + let s = db::DatabaseEnvironment::open()?; let list_key = crate::CONTACT_LIST_DB_KEY; let r = db::DatabaseEnvironment::read(&s.env, &s.handle?, &list_key.as_bytes().to_vec())?; if r.is_empty() { @@ -143,8 +143,8 @@ async fn validate_contact(j: &Json) -> bool { /// Send our information pub async fn share() -> Result { - let env = utils::get_release_env(); - let s = db::DatabaseEnvironment::open(&env.value())?; + + let s = db::DatabaseEnvironment::open()?; let r = db::DatabaseEnvironment::read(&s.env, &s.handle?, &NEVEKO_VENDOR_ENABLED.as_bytes().to_vec())?; let str_r: String = bincode::deserialize(&r[..]).unwrap_or_default(); let is_vendor = str_r == NEVEKO_VENDOR_MODE_ON; @@ -154,7 +154,7 @@ pub async fn share() -> Result { monero::open_wallet(&wallet_name, &wallet_password).await; let m_address: reqres::XmrRpcAddressResponse = monero::get_address().await; monero::close_wallet(&wallet_name, &wallet_password).await; - let nmpk = utils::get_nmpk(); + let nmpk = utils::get_nmpk()?; let i2p_address = i2p::get_destination(None); let xmr_address = m_address.result.address; Ok(Contact { @@ -233,8 +233,8 @@ mod tests { use super::*; fn cleanup(k: &String) { - let env = utils::get_release_env(); - let s = db::DatabaseEnvironment::open(&env.value()); + + let s = db::DatabaseEnvironment::open(); db::DatabaseEnvironment::delete(&s.env, &s.handle, k); } @@ -276,12 +276,12 @@ mod tests { ..Default::default() }; tokio::spawn(async move { - let s = db::DatabaseEnvironment::async_open().await; - db::DatabaseEnvironment::async_write(&s.env, &s.handle, k, &Contact::to_db(&expected_contact)) - .await; + let s = db::DatabaseEnvironment::open().unwrap(); + let v = bincode::serialize(&expected_contact).unwrap_or_default(); + db::write_chunks(&s.env, &s.handle, k.as_bytes(), &v); let actual_contact: Contact = find(&String::from(k)); assert_eq!(expected_contact.xmr_address, actual_contact.xmr_address); - cleanup(&String::from(k)).await; + cleanup(&String::from(k)); }); Runtime::shutdown_background(rt); } diff --git a/neveko-core/src/db.rs b/neveko-core/src/db.rs index 94db7ef..fad3cb4 100644 --- a/neveko-core/src/db.rs +++ b/neveko-core/src/db.rs @@ -8,6 +8,8 @@ use lmdb::*; use log::{error, info}; use sysinfo::System; +use crate::utils; + /// Ratio of map size to available memory is 20 percent const MAP_SIZE_MEMORY_RATIO: f32 = 0.2; /// Ratio of chunk size to available memory is 0.2 percent @@ -15,7 +17,7 @@ const CHUNK_SIZE_MEMORY_RATIO: f32 = MAP_SIZE_MEMORY_RATIO * 0.01; /// The database environment for handling primary database operations. /// -/// By default the database will be written to /home/user/.valentinus/{ENV}/lmdb +/// By default the database will be written to /home/user/.neveko/{ENV}/lmdb pub struct DatabaseEnvironment { pub env: Environment, pub handle: Result, @@ -27,7 +29,7 @@ impl DatabaseEnvironment { /// of available memory and can be set via the `LMDB_MAP_SIZE` environment variable. /// /// The path of the user can be set with `LMDB_USER`. - pub fn open(env: &str) -> Result { + pub fn open() -> Result { let s = System::new_all(); let default_map_size: u64 = (s.available_memory() as f32 * MAP_SIZE_MEMORY_RATIO).floor() as u64; @@ -43,9 +45,10 @@ impl DatabaseEnvironment { info!("$LMDB_USER={}", user); info!("excecuting lmdb open"); let file_path: String = format!("/home/{}/.{}/", user, "valentinus"); + let env_str = utils::get_release_env().value(); let env: Environment = EnvBuilder::new() .map_size(env_map_size) - .open(format!("{}/{}", file_path, env), 0o777) + .open(format!("{}/{}", file_path, env_str), 0o777) .unwrap_or_else(|_| panic!("could not open LMDB at {}", file_path)); let default: Result = env.get_default_db(DbFlags::empty()); if default.is_err() { @@ -185,30 +188,18 @@ mod tests { #[test] fn environment_test() -> Result<(), MdbError> { - let db = DatabaseEnvironment::open("10-mb-test")?; + let db = DatabaseEnvironment::open()?; const DATA_SIZE_10MB: usize = 10000000; let mut data = vec![0u8; DATA_SIZE_10MB]; rand::thread_rng().fill_bytes(&mut data); let k = "test-key".as_bytes(); let expected = &data.to_vec(); write_chunks(&db.env, &db.handle?, &Vec::from(k), &Vec::from(data))?; - let db = DatabaseEnvironment::open("10-mb-test")?; + let db = DatabaseEnvironment::open()?; let actual = DatabaseEnvironment::read(&db.env, &db.handle?, &Vec::from(k)); assert_eq!(expected.to_vec(), actual?); - let db = DatabaseEnvironment::open("10-mb-test")?; - let _ = DatabaseEnvironment::delete(&db.env, &db.handle?, &Vec::from(k)); - let db = DatabaseEnvironment::open("100-mb-test")?; - const DATA_SIZE_100MB: usize = 100000000; - let mut data = vec![0u8; DATA_SIZE_100MB]; - rand::thread_rng().fill_bytes(&mut data); - let k = "test-key".as_bytes(); - let expected = &data.to_vec(); - write_chunks(&db.env, &db.handle?, &Vec::from(k), &Vec::from(data))?; - let db = DatabaseEnvironment::open("100-mb-test")?; - let actual = DatabaseEnvironment::read(&db.env, &db.handle?, &Vec::from(k)); - assert_eq!(expected.to_vec(), actual?); - let db = DatabaseEnvironment::open("100-mb-test")?; + let db = DatabaseEnvironment::open()?; let _ = DatabaseEnvironment::delete(&db.env, &db.handle?, &Vec::from(k)); Ok(()) } -} +} \ No newline at end of file diff --git a/neveko-core/src/dispute.rs b/neveko-core/src/dispute.rs index 795b615..7fb0586 100644 --- a/neveko-core/src/dispute.rs +++ b/neveko-core/src/dispute.rs @@ -3,11 +3,9 @@ use std::error::Error; use crate::{ - db, - models::*, - monero, - utils, + db, error::NevekoError, models::*, monero, utils }; +use kn0sys_lmdb_rs::MdbError; use log::{ debug, error, @@ -16,80 +14,91 @@ use log::{ use rocket::serde::json::Json; /// Create a new dispute -pub fn create(d: Json) -> Dispute { +pub fn create(d: Json) -> Result { let f_did: String = format!("{}{}", crate::DISPUTE_DB_KEY, utils::generate_rnd()); info!("create dispute: {}", &f_did); let new_dispute = Dispute { - did: String::from(&f_did), + did: String::from(&f_did), created: chrono::offset::Utc::now().timestamp(), orid: String::from(&d.orid), tx_set: String::from(&d.tx_set), }; debug!("insert dispute: {:?}", &d); - let s = db::DatabaseEnvironment::open(); + + let s = db::DatabaseEnvironment::open()?; let k = &d.did; - db::DatabaseEnvironment::write(&s.env, &s.handle, k, &Dispute::to_db(&new_dispute)); + let v = bincode::serialize(&new_dispute).unwrap_or_default(); + db::write_chunks(&s.env, &s.handle?, k.as_bytes(), &v); // in order to retrieve all orders, write keys to with dl let list_key = crate::DISPUTE_LIST_DB_KEY; - let r = db::DatabaseEnvironment::read(&s.env, &s.handle, &String::from(list_key)); + let s = db::DatabaseEnvironment::open()?; + let r = db::DatabaseEnvironment::read(&s.env, &s.handle?, &list_key.as_bytes().to_vec())?; if r.is_empty() { debug!("creating dispute index"); } - let dispute_list = [String::from(&r), String::from(&f_did)].join(","); + let s_r: String = bincode::deserialize(&r[..]).unwrap_or_default(); + let dispute_list = [String::from(&s_r), String::from(&f_did)].join(","); debug!( "writing dispute index {} for id: {}", dispute_list, list_key ); - db::DatabaseEnvironment::write(&s.env, &s.handle, &String::from(list_key), &dispute_list); + let s = db::DatabaseEnvironment::open()?; + db::write_chunks(&s.env, &s.handle?, list_key.as_bytes(), dispute_list.as_bytes()); // restart the dispute aut-settle thread - let cleared = is_dispute_clear(r); + let cleared = is_dispute_clear(s_r); if !cleared { debug!("restarting dispute auto-settle"); utils::restart_dispute_auto_settle(); } - new_dispute + Ok(new_dispute) } /// Dispute lookup -pub fn find(did: &String) -> Dispute { - let s = db::DatabaseEnvironment::open(); - let r = db::DatabaseEnvironment::read(&s.env, &s.handle, &String::from(did)); +pub fn find(did: &String) -> Result { + + let s = db::DatabaseEnvironment::open()?; + let r = db::DatabaseEnvironment::read(&s.env, &s.handle?, &did.as_bytes().to_vec())?; if r.is_empty() { error!("dispute not found"); - return Default::default(); + return Err(MdbError::NotFound); } - Dispute::from_db(String::from(did), r) + let result: Dispute = bincode::deserialize(&r[..]).unwrap_or_default(); + Ok(result) } /// Lookup all disputes -pub fn find_all() -> Vec { - let d_s = db::DatabaseEnvironment::open(); +pub fn find_all() -> Result, MdbError> { + + let d_s = db::DatabaseEnvironment::open()?; let d_list_key = crate::DISPUTE_LIST_DB_KEY; - let d_r = db::DatabaseEnvironment::read(&d_s.env, &d_s.handle, &String::from(d_list_key)); + let d_r = db::DatabaseEnvironment::read(&d_s.env, &d_s.handle?, &d_list_key.as_bytes().to_vec())?; if d_r.is_empty() { error!("dispute index not found"); } - let d_v_did = d_r.split(","); + let str_r: String = bincode::deserialize(&d_r[..]).unwrap_or_default(); + let d_v_did = str_r.split(","); let d_v: Vec = d_v_did.map(String::from).collect(); let mut disputes: Vec = Vec::new(); for o in d_v { - let dispute: Dispute = find(&o); + let dispute: Dispute = find(&o)?; if !dispute.did.is_empty() { disputes.push(dispute); } } - disputes + Ok(disputes) } /// Dispute deletion -pub fn delete(did: &String) { - let s = db::DatabaseEnvironment::open(); - let r = db::DatabaseEnvironment::read(&s.env, &s.handle, &String::from(did)); +pub fn delete(did: &String) -> Result<(), MdbError> { + + let s = db::DatabaseEnvironment::open()?; + let r = db::DatabaseEnvironment::read(&s.env, &s.handle?, &did.as_bytes().to_vec())?; if r.is_empty() { error!("dispute not found"); - return Default::default(); + return Err(MdbError::NotFound); } - db::DatabaseEnvironment::delete(&s.env, &s.handle, &String::from(did)) + let s = db::DatabaseEnvironment::open()?; + db::DatabaseEnvironment::delete(&s.env, &s.handle?, did.as_bytes()) } /// Triggered on DISPUTE_LAST_CHECK_DB_KEY. @@ -99,30 +108,33 @@ pub fn delete(did: &String) { /// creation date of the dispute plus the one week /// /// grace period then the dispute is auto-settled. -pub async fn settle_dispute() { +pub async fn settle_dispute() -> Result<(), MdbError>{ let tick: std::sync::mpsc::Receiver<()> = schedule_recv::periodic_ms(crate::DISPUTE_CHECK_INTERVAL); loop { debug!("running dispute auto-settle thread"); tick.recv().unwrap(); - let s = db::DatabaseEnvironment::open(); + + let s = db::DatabaseEnvironment::open()?; let list_key = crate::DISPUTE_LIST_DB_KEY; - let r = db::DatabaseEnvironment::read(&s.env, &s.handle, &String::from(list_key)); + let r = db::DatabaseEnvironment::read(&s.env, &s.handle?, &list_key.as_bytes().to_vec())?; if r.is_empty() { info!("dispute index not found"); } - let v_mid = r.split(","); + let str_r: String = bincode::deserialize(&r[..]).unwrap_or_default(); + let v_mid = str_r.split(","); let d_vec: Vec = v_mid.map(String::from).collect(); debug!("dispute contents: {:#?}", d_vec); - let cleared = is_dispute_clear(r); + let cleared = is_dispute_clear(str_r); if cleared { // index was created but cleared info!("terminating dispute auto-settle thread"); - db::DatabaseEnvironment::delete(&s.env, &s.handle, list_key); - return; + let s = db::DatabaseEnvironment::open()?; + db::DatabaseEnvironment::delete(&s.env, &s.handle?, list_key.as_bytes()); + return Ok(()); } for d in d_vec { - let dispute: Dispute = find(&d); + let dispute: Dispute = find(&d)?; if !dispute.did.is_empty() { let now = chrono::offset::Utc::now().timestamp(); let settle_date = dispute.created + crate::DISPUTE_AUTO_SETTLE as i64; @@ -135,7 +147,7 @@ pub async fn settle_dispute() { monero::close_wallet(&wallet_name, &wallet_password).await; if submit.result.tx_hash_list.is_empty() { error!("could not broadcast txset for dispute: {}", &dispute.did); - return; + return Ok(()); } // remove the dispute from the db remove_from_auto_settle(dispute.did); @@ -160,15 +172,17 @@ fn is_dispute_clear(r: String) -> bool { } /// clear dispute from index -fn remove_from_auto_settle(did: String) { +fn remove_from_auto_settle(did: String) -> Result<(), MdbError> { info!("removing id {} from disputes", &did); - let s = db::DatabaseEnvironment::open(); + + let s = db::DatabaseEnvironment::open()?; let list_key = crate::DISPUTE_LIST_DB_KEY; - let r = db::DatabaseEnvironment::read(&s.env, &s.handle, &String::from(list_key)); + let r = db::DatabaseEnvironment::read(&s.env, &s.handle?, &list_key.as_bytes().to_vec())?; if r.is_empty() { debug!("dispute list index is empty"); } - let pre_v_fts = r.split(","); + let str_r: String = bincode::deserialize(&r[..]).unwrap_or_default(); + let pre_v_fts = str_r.split(","); let v: Vec = pre_v_fts .map(|s| { if s != &did { @@ -183,7 +197,9 @@ fn remove_from_auto_settle(did: String) { "writing dipsute index {} for id: {}", dispute_list, list_key ); - db::DatabaseEnvironment::write(&s.env, &s.handle, &String::from(list_key), &dispute_list); + let s = db::DatabaseEnvironment::open()?; + db::write_chunks(&s.env, &s.handle?, list_key.as_bytes(), dispute_list.as_bytes()); + Ok(()) } /// Executes POST /market/dispute/create @@ -227,16 +243,21 @@ async fn transmit_dispute_request( /// A decomposition trigger for the dispute request so that the logic /// /// can be executed from the gui. -pub async fn trigger_dispute_request(contact: &String, dispute: &Dispute) -> Dispute { +pub async fn trigger_dispute_request(contact: &String, dispute: &Dispute) -> Result { info!("executing trigger_dispute_request"); - let s = db::DatabaseEnvironment::async_open().await; + + let s = db::DatabaseEnvironment::open() + .map_err(|_| NevekoError::Database(MdbError::Panic))?; let k = format!("{}-{}", crate::FTS_JWP_DB_KEY, &contact); - let jwp = db::DatabaseEnvironment::async_read(&s.env, &s.handle, &k).await; - let dispute = transmit_dispute_request(contact, &jwp, dispute).await; + let handle = &s.handle.map_err(|_| NevekoError::Database(MdbError::Panic))?; + let jwp = db::DatabaseEnvironment::read(&s.env, handle, &k.as_bytes().to_vec()) + .map_err(|_| NevekoError::Database(MdbError::Panic))?; + let str_jwp: String = bincode::deserialize(&jwp[..]).unwrap_or_default(); + let dispute = transmit_dispute_request(contact, &str_jwp, dispute).await; // handle a failure to create dispute if dispute.is_err() { error!("failed to create dispute"); - return Default::default(); + return Err(NevekoError::Dispute); } - dispute.unwrap_or(Default::default()) + Ok(dispute.map_err(|_| NevekoError::Dispute)?) } diff --git a/neveko-core/src/error.rs b/neveko-core/src/error.rs index db6edd1..1dcb7fa 100644 --- a/neveko-core/src/error.rs +++ b/neveko-core/src/error.rs @@ -1,11 +1,13 @@ use kn0sys_lmdb_rs::MdbError; use thiserror::Error; +/// Use for mapping errors in functions that can throw multiple errors. #[derive(Debug, Error)] -#[error("neveko error. See logs for more info.")] +#[error("Neveko error. See logs for more info.")] pub enum NevekoError { ///J4I2PRS(J4RsError), Database(MdbError), + Dispute, MoneroRpc, MoneroDaemon, Unknown, diff --git a/neveko-core/src/proof.rs b/neveko-core/src/proof.rs index c08bae9..6495b03 100644 --- a/neveko-core/src/proof.rs +++ b/neveko-core/src/proof.rs @@ -81,7 +81,7 @@ pub async fn create_jwp(proof: &TxProof) -> String { error!("invalid transaction proof"); return String::new(); } - let jwp_secret_key = utils::get_jwp_secret_key(); + let jwp_secret_key = utils::get_jwp_secret_key().unwrap_or_default(); let key: Hmac = Hmac::new_from_slice(jwp_secret_key.as_bytes()).expect("hash"); let header = Header { algorithm: AlgorithmType::Hs512, @@ -122,11 +122,11 @@ pub async fn prove_payment(contact: String, txp: &TxProof) -> Result { // cache the jwp for for fts - let env = utils::get_release_env(); - let s = db::DatabaseEnvironment::open(&env.value())?; + + let s = db::DatabaseEnvironment::open()?; let k = format!("{}-{}", crate::FTS_JWP_DB_KEY, &contact); db::DatabaseEnvironment::delete(&s.env, &s.handle?, k.as_bytes())?; - let s = db::DatabaseEnvironment::open(&env.value())?; + let s = db::DatabaseEnvironment::open()?; db::write_chunks(&s.env, &s.handle?, &k.as_bytes(), &r.jwp.as_bytes().to_vec()); Ok(r) } @@ -182,7 +182,7 @@ impl<'r> FromRequest<'r> for PaymentProof { match proof { Some(proof) => { // check validity of address, payment amount and tx confirmations - let jwp_secret_key = utils::get_jwp_secret_key(); + let jwp_secret_key = utils::get_jwp_secret_key().unwrap_or_default(); let key: Hmac = Hmac::new_from_slice(jwp_secret_key.as_bytes()).expect(""); let jwp: Result< Token, _>, diff --git a/neveko-core/src/user.rs b/neveko-core/src/user.rs index d2243b4..fc7cd12 100644 --- a/neveko-core/src/user.rs +++ b/neveko-core/src/user.rs @@ -21,8 +21,8 @@ pub fn create(address: &String) -> Result { name: String::new(), }; debug!("insert user: {:?}", &new_user); - let env = utils::get_release_env(); - let s = db::DatabaseEnvironment::open(&env.value())?; + + let s = db::DatabaseEnvironment::open()?; let k = &new_user.uid; let v = bincode::serialize(&new_user).unwrap_or_default(); db::write_chunks(&s.env, &s.handle?, k.as_bytes(), &v)?; @@ -31,8 +31,8 @@ pub fn create(address: &String) -> Result { /// User lookup pub fn find(uid: &String) -> Result { - let env = utils::get_release_env(); - let s = db::DatabaseEnvironment::open(&env.value())?; + + let s = db::DatabaseEnvironment::open()?; let r = db::DatabaseEnvironment::read(&s.env, &s.handle?, &uid.as_bytes().to_vec())?; if r.is_empty() { error!("user not found"); diff --git a/neveko-core/src/utils.rs b/neveko-core/src/utils.rs index ab6516d..7a6053d 100644 --- a/neveko-core/src/utils.rs +++ b/neveko-core/src/utils.rs @@ -11,7 +11,6 @@ use crate::{ monero, neveko25519, reqres, - utils, }; use clap::Parser; use kn0sys_lmdb_rs::MdbError; @@ -241,8 +240,8 @@ pub fn get_app_port() -> u16 { /// i2p http proxy pub fn get_i2p_http_proxy() -> String { let args = args::Args::parse(); - let advanced_proxy = std::env::var(crate::NEVEKO_I2P_PROXY_HOST).unwrap_or(empty_string()); - if advanced_proxy == empty_string() { + let advanced_proxy = std::env::var(crate::NEVEKO_I2P_PROXY_HOST).unwrap_or(String::new()); + if advanced_proxy.is_empty() { args.i2p_proxy_host } else { advanced_proxy @@ -409,20 +408,19 @@ async fn gen_app_wallet(password: &String) { /// Secret keys for signing internal/external auth tokens fn gen_signing_keys() -> Result<(), MdbError> { info!("generating signing keys"); - let jwp = get_jwp_secret_key(); - let jwt = get_jwt_secret_key(); + let jwp = get_jwp_secret_key()?; + let jwt = get_jwt_secret_key()?; // send to db - let env = utils::get_release_env(); if jwp.is_empty() { let mut data = [0u8; 32]; rand::thread_rng().fill_bytes(&mut data); - let s = db::DatabaseEnvironment::open(&env.value())?; + let s = db::DatabaseEnvironment::open()?; db::write_chunks(&s.env, &s.handle?, crate::NEVEKO_JWP_SECRET_KEY.as_bytes(), &data); } if jwt.is_empty() { let mut data = [0u8; 32]; rand::thread_rng().fill_bytes(&mut data); - let s = db::DatabaseEnvironment::open(&env.value())?; + let s = db::DatabaseEnvironment::open()?; db::write_chunks(&s.env, &s.handle?, crate::NEVEKO_JWT_SECRET_KEY.as_bytes(), &data); } Ok(()) @@ -431,52 +429,61 @@ fn gen_signing_keys() -> Result<(), MdbError> { /// TODO(c2m): add a button to gui to call this /// /// dont' forget to generate new keys as well -pub fn revoke_signing_keys() { - let s = db::DatabaseEnvironment::open(); - db::DatabaseEnvironment::delete(&s.env, &s.handle, crate::NEVEKO_JWT_SECRET_KEY); - db::DatabaseEnvironment::delete(&s.env, &s.handle, crate::NEVEKO_JWP_SECRET_KEY); +pub fn revoke_signing_keys() -> Result<(), MdbError> { + + let s = db::DatabaseEnvironment::open()?; + db::DatabaseEnvironment::delete(&s.env, &s.handle?, crate::NEVEKO_JWT_SECRET_KEY.as_bytes()); + let s = db::DatabaseEnvironment::open()?; + db::DatabaseEnvironment::delete(&s.env, &s.handle?, crate::NEVEKO_JWP_SECRET_KEY.as_bytes()); + Ok(()) } -pub fn get_jwt_secret_key() -> String { - let s = db::DatabaseEnvironment::open(); - let r = db::DatabaseEnvironment::read(&s.env, &s.handle, crate::NEVEKO_JWT_SECRET_KEY); +pub fn get_jwt_secret_key() -> Result { + + let s = db::DatabaseEnvironment::open()?; + let r = db::DatabaseEnvironment::read(&s.env, &s.handle?, &crate::NEVEKO_JWT_SECRET_KEY.as_bytes().to_vec())?; if r.is_empty() { error!("JWT key not found"); - return Default::default(); + return Err(MdbError::NotFound); } - r + let result: String = bincode::deserialize(&r[..]).unwrap_or_default(); + Ok(result) } -pub fn get_jwp_secret_key() -> String { - let s = db::DatabaseEnvironment::open(); - let r = db::DatabaseEnvironment::read(&s.env, &s.handle, crate::NEVEKO_JWP_SECRET_KEY); +pub fn get_jwp_secret_key() -> Result { + + let s = db::DatabaseEnvironment::open()?; + let r = db::DatabaseEnvironment::read(&s.env, &s.handle?, &crate::NEVEKO_JWP_SECRET_KEY.as_bytes().to_vec())?; if r.is_empty() { error!("JWP key not found"); - return Default::default(); + return Err(MdbError::NotFound); } - r + let result: String = bincode::deserialize(&r[..]).unwrap_or_default(); + Ok(result) } /// Returns the hex encoded neveko message public key from LMDB -pub fn get_nmpk() -> String { - let s = db::DatabaseEnvironment::open(); - let r = db::DatabaseEnvironment::read(&s.env, &s.handle, crate::NEVEKO_NMPK); +pub fn get_nmpk() -> Result { + let s = db::DatabaseEnvironment::open()?; + let r = db::DatabaseEnvironment::read(&s.env, &s.handle?, &crate::NEVEKO_NMPK.as_bytes().to_vec())?; if r.is_empty() { error!("neveko message public key not found"); - return Default::default(); + return Err(MdbError::NotFound); } - r + let result: String = bincode::deserialize(&r[..]).unwrap_or_default(); + Ok(result) } -async fn generate_nmpk() { +async fn generate_nmpk() -> Result<(), MdbError> { info!("generating neveko message public key"); - let nmpk: String = get_nmpk(); + let nmpk: String = get_nmpk()?; // send to db - let s = db::DatabaseEnvironment::open(); + let s = db::DatabaseEnvironment::open()?; if nmpk.is_empty() { let nmk: neveko25519::NevekoMessageKeys = neveko25519::generate_neveko_message_keys().await; - db::DatabaseEnvironment::write(&s.env, &s.handle, crate::NEVEKO_NMPK, &nmk.hex_nmpk); + db::write_chunks(&s.env, &s.handle?, crate::NEVEKO_NMPK.as_bytes(), nmk.hex_nmpk.as_bytes()); } + Ok(()) } /// Put all app pre-checks here @@ -502,8 +509,8 @@ pub async fn start_up() { tokio::time::sleep(std::time::Duration::new(5, 0)).await; monero::check_rpc_connection().await; let mut wallet_password = - std::env::var(crate::MONERO_WALLET_PASSWORD).unwrap_or(empty_string()); - if wallet_password == empty_string() { + std::env::var(crate::MONERO_WALLET_PASSWORD).unwrap_or_default(); + if wallet_password.is_empty() { print!( "MONERO_WALLET_PASSWORD not set, enter neveko wallet password for monero-wallet-rpc: " ); @@ -572,17 +579,19 @@ pub fn restart_dispute_auto_settle() { } /// Called on app startup if `--clear-fts` flag is passed. -fn clear_fts() { +fn clear_fts() -> Result<(), MdbError> { info!("clear fts"); - let s = db::DatabaseEnvironment::open(); - db::DatabaseEnvironment::delete(&s.env, &s.handle, crate::FTS_DB_KEY); + let s = db::DatabaseEnvironment::open()?; + db::DatabaseEnvironment::delete(&s.env, &s.handle?, crate::FTS_DB_KEY.as_bytes()); + Ok(()) } /// Called on app startup if `--clear-dispute` flag is passed. -fn clear_disputes() { +fn clear_disputes() -> Result<(), MdbError> { info!("clear_disputes"); - let s = db::DatabaseEnvironment::open(); - db::DatabaseEnvironment::delete(&s.env, &s.handle, crate::DISPUTE_LIST_DB_KEY); + let s = db::DatabaseEnvironment::open()?; + db::DatabaseEnvironment::delete(&s.env, &s.handle?, crate::DISPUTE_LIST_DB_KEY.as_bytes()); + Ok(()) } /// ### The highly ineffecient fee estimator. @@ -688,47 +697,54 @@ pub async fn can_transfer(invoice: u128) -> bool { } /// Gui toggle for vendor mode -pub fn toggle_vendor_enabled() -> bool { +pub fn toggle_vendor_enabled() -> Result { // TODO(c2m): Dont toggle vendors with orders status != Delivered - let s = db::DatabaseEnvironment::open(); - let r = db::DatabaseEnvironment::read(&s.env, &s.handle, contact::NEVEKO_VENDOR_ENABLED); - if r != contact::NEVEKO_VENDOR_MODE_ON { + let s = db::DatabaseEnvironment::open()?; + let r = db::DatabaseEnvironment::read(&s.env, &s.handle?, &contact::NEVEKO_VENDOR_ENABLED.as_bytes().to_vec())?; + let mode: String = bincode::deserialize(&r[..]).unwrap_or_default(); + if mode != contact::NEVEKO_VENDOR_MODE_ON { info!("neveko vendor mode enabled"); - db::DatabaseEnvironment::write( + let s = db::DatabaseEnvironment::open()?; + db::write_chunks( &s.env, - &s.handle, - contact::NEVEKO_VENDOR_ENABLED, - contact::NEVEKO_VENDOR_MODE_ON, + &s.handle?, + contact::NEVEKO_VENDOR_ENABLED.as_bytes(), + contact::NEVEKO_VENDOR_MODE_ON.as_bytes(), ); - true + Ok(true) } else { info!("neveko vendor mode disabled"); - db::DatabaseEnvironment::write( + let s = db::DatabaseEnvironment::open()?; + db::write_chunks( &s.env, - &s.handle, - contact::NEVEKO_VENDOR_ENABLED, - contact::NEVEKO_VENDOR_MODE_OFF, + &s.handle?, + contact::NEVEKO_VENDOR_ENABLED.as_bytes(), + contact::NEVEKO_VENDOR_MODE_OFF.as_bytes(), ); - false + Ok(false) } } -pub fn search_gui_db(f: String, data: String) -> String { - let s = db::DatabaseEnvironment::open(); +pub fn search_gui_db(f: String, data: String) -> Result { + let s = db::DatabaseEnvironment::open()?; let k = format!("{}-{}", f, data); - db::DatabaseEnvironment::read(&s.env, &s.handle, &k) + let r = db::DatabaseEnvironment::read(&s.env, &s.handle?, &k.as_bytes().to_vec())?; + let result: String = bincode::deserialize(&r[..]).unwrap_or_default(); + Ok(result) } -pub fn write_gui_db(f: String, key: String, data: String) { - let s = db::DatabaseEnvironment::open(); +pub fn write_gui_db(f: String, key: String, data: String) -> Result<(), MdbError> { + let s = db::DatabaseEnvironment::open()?; let k = format!("{}-{}", f, key); - db::DatabaseEnvironment::write(&s.env, &s.handle, &k, &data); + db::write_chunks(&s.env, &s.handle?, k.as_bytes(), data.as_bytes()); + Ok(()) } -pub fn clear_gui_db(f: String, key: String) { - let s = db::DatabaseEnvironment::open(); +pub fn clear_gui_db(f: String, key: String) -> Result<(), MdbError> { + let s = db::DatabaseEnvironment::open()?; let k = format!("{}-{}", f, key); - db::DatabaseEnvironment::delete(&s.env, &s.handle, &k); + db::DatabaseEnvironment::delete(&s.env, &s.handle?, k.as_bytes())?; + Ok(()) } // Tests @@ -842,4 +858,4 @@ mod tests { assert_eq!(expected, actual) }); } -} +} \ No newline at end of file