diff options
Diffstat (limited to 'src/schema.rs')
| -rw-r--r-- | src/schema.rs | 95 |
1 files changed, 79 insertions, 16 deletions
diff --git a/src/schema.rs b/src/schema.rs index 556e625..909b5cd 100644 --- a/src/schema.rs +++ b/src/schema.rs | |||
| @@ -1,41 +1,42 @@ | |||
| 1 | use chrono::NaiveDateTime; | 1 | use chrono::{NaiveDate, NaiveDateTime}; |
| 2 | use lazy_static::lazy_static; | ||
| 2 | use parking_lot::RwLock; | 3 | use parking_lot::RwLock; |
| 3 | use serde::{Deserialize, Serialize}; | 4 | use serde::{Deserialize, Serialize}; |
| 4 | use std::collections::HashMap; | 5 | use std::collections::{HashMap, HashSet}; |
| 6 | use std::fmt; | ||
| 7 | use std::fs; | ||
| 5 | use std::sync::Arc; | 8 | use std::sync::Arc; |
| 6 | 9 | ||
| 7 | // use crate::validators; | 10 | // use crate::validators; |
| 8 | 11 | ||
| 9 | // In memory data structure | 12 | /// We need persistence for blocks and users, not so much for transactions |
| 10 | // Two approaches here | 13 | /// There are around 30 students, a full fledged database would be an overkill (for next year?) |
| 11 | // 1. Db is a type pub type Db = Arc<RwLock<Vec<Ledger>>>; Ledger is a struct, we wrap the ledger | 14 | /// Pending transactions are held in memory, these are cleared with every new block |
| 12 | // with arc + mutex in ledger() to access transactions we need to unwrap blocks as well, vice | 15 | /// Only the last block is held in memory, every block is written to a file |
| 13 | // versa | 16 | /// Users are held in memory and they're also backed up to text files |
| 14 | // | ||
| 15 | // 2. Db is a struct attributes are wrapped we can offload ::new() to it's member method blocks and | ||
| 16 | // transactions are accessible separately, which is the biggest pro | ||
| 17 | // | ||
| 18 | // 3. use an actual database (for blockchain and users this makes the most sense tbh but pending | ||
| 19 | // transactions are perfectly fine in memory) | ||
| 20 | 17 | ||
| 21 | /// Creates a new database | 18 | /// Creates a new database connection |
| 22 | pub fn create_database() -> Db { | 19 | pub fn create_database() -> Db { |
| 20 | fs::create_dir_all("blocks").unwrap(); | ||
| 21 | fs::create_dir_all("users").unwrap(); | ||
| 23 | Db::new() | 22 | Db::new() |
| 24 | } | 23 | } |
| 25 | 24 | ||
| 26 | #[derive(Debug, Clone)] | 25 | #[derive(Debug, Clone)] |
| 27 | pub struct Db { | 26 | pub struct Db { |
| 28 | // heh. also https://doc.rust-lang.org/std/collections/struct.LinkedList.html says Vec is generally faster | 27 | // heh. also https://doc.rust-lang.org/std/collections/struct.LinkedList.html says Vec is generally faster |
| 29 | pub blockchain: Arc<RwLock<Vec<Block>>>, | 28 | pub blockchain: Arc<RwLock<Block>>, |
| 30 | // every proposer can have _one_ pending transaction, a way to enforce this, String is proposer identifier | 29 | // every proposer can have _one_ pending transaction, a way to enforce this, String is proposer identifier |
| 31 | pub pending_transactions: Arc<RwLock<HashMap<String, Transaction>>>, | 30 | pub pending_transactions: Arc<RwLock<HashMap<String, Transaction>>>, |
| 31 | pub users: Arc<RwLock<HashMap<String, User>>>, | ||
| 32 | } | 32 | } |
| 33 | 33 | ||
| 34 | impl Db { | 34 | impl Db { |
| 35 | fn new() -> Self { | 35 | fn new() -> Self { |
| 36 | Db { | 36 | Db { |
| 37 | blockchain: Arc::new(RwLock::new(Vec::new())), | 37 | blockchain: Arc::new(RwLock::new(Block::new())), |
| 38 | pending_transactions: Arc::new(RwLock::new(HashMap::new())), | 38 | pending_transactions: Arc::new(RwLock::new(HashMap::new())), |
| 39 | users: Arc::new(RwLock::new(HashMap::new())), | ||
| 39 | } | 40 | } |
| 40 | } | 41 | } |
| 41 | } | 42 | } |
| @@ -43,6 +44,7 @@ impl Db { | |||
| 43 | /// A transaction between `source` and `target` that moves `amount` | 44 | /// A transaction between `source` and `target` that moves `amount` |
| 44 | #[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] | 45 | #[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] |
| 45 | pub struct Transaction { | 46 | pub struct Transaction { |
| 47 | // TODO: new field by <11-04-21, yigit> // | ||
| 46 | pub source: String, | 48 | pub source: String, |
| 47 | pub target: String, | 49 | pub target: String, |
| 48 | pub amount: i32, | 50 | pub amount: i32, |
| @@ -65,5 +67,66 @@ pub struct Block { | |||
| 65 | pub hash: String, // future proof'd baby | 67 | pub hash: String, // future proof'd baby |
| 66 | } | 68 | } |
| 67 | 69 | ||
| 70 | impl Block { | ||
| 71 | /// Genesis block | ||
| 72 | pub fn new() -> Block { | ||
| 73 | Block { | ||
| 74 | transaction_list: vec![], | ||
| 75 | nonce: String::from(""), | ||
| 76 | timestamp: NaiveDate::from_ymd(2021, 04, 11).and_hms(20, 45, 00), | ||
| 77 | hash: String::from(""), | ||
| 78 | } | ||
| 79 | } | ||
| 80 | } | ||
| 81 | |||
| 82 | /// Or simply a Student | ||
| 83 | #[derive(Serialize, Deserialize, Debug)] | ||
| 84 | pub struct User { | ||
| 85 | pub user_id: MetuId, | ||
| 86 | pub public_key: String, | ||
| 87 | pub balance: i32, | ||
| 88 | } | ||
| 89 | |||
| 90 | /// The values will be hard coded so MetuId::new() can accept/reject values based on that | ||
| 91 | #[derive(Serialize, Deserialize, Debug)] | ||
| 92 | pub struct MetuId { | ||
| 93 | id: String, | ||
| 94 | } | ||
| 95 | |||
| 96 | #[derive(Serialize, Deserialize, Debug)] | ||
| 97 | pub struct AuthRequest { | ||
| 98 | pub student_id: String, | ||
| 99 | pub public_key: String, | ||
| 100 | } | ||
| 101 | |||
| 102 | lazy_static! { | ||
| 103 | static ref OUR_STUDENTS: HashSet<&'static str> = { | ||
| 104 | [ | ||
| 105 | "e254275", "e223687", "e211024", "e209888", "e223725", "e209362", "e209898", "e230995", | ||
| 106 | "e223743", "e223747", "e223749", "e223751", "e188126", "e209913", "e203608", "e233013", | ||
| 107 | "e216982", "e217185", "e223780", "e194931", "e223783", "e254550", "e217203", "e217477", | ||
| 108 | "e223786", "e231060", "e223795", | ||
| 109 | ] | ||
| 110 | .iter() | ||
| 111 | .cloned() | ||
| 112 | .collect() | ||
| 113 | }; | ||
| 114 | } | ||
| 115 | |||
| 116 | impl fmt::Display for MetuId { | ||
| 117 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
| 118 | write!(f, "{}", self.id) | ||
| 119 | } | ||
| 120 | } | ||
| 121 | |||
| 122 | impl MetuId { | ||
| 123 | pub fn new(id: String) -> Option<Self> { | ||
| 124 | if OUR_STUDENTS.contains(&*id) { | ||
| 125 | Some(MetuId { id: id }) | ||
| 126 | } else { | ||
| 127 | None | ||
| 128 | } | ||
| 129 | } | ||
| 130 | } | ||
| 68 | 131 | ||
| 69 | // TODO: write schema tests using the original repo <09-04-21, yigit> // | 132 | // TODO: write schema tests using the original repo <09-04-21, yigit> // |
