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> // |