1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
|
use chrono::NaiveDateTime;
use parking_lot::RwLock;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::sync::Arc;
// use crate::validators;
// In memory data structure
// Two approaches here
// 1. Db is a type pub type Db = Arc<RwLock<Vec<Ledger>>>; Ledger is a struct, we wrap the ledger
// with arc + mutex in ledger() to access transactions we need to unwrap blocks as well, vice
// versa
//
// 2. Db is a struct attributes are wrapped we can offload ::new() to it's member method blocks and
// transactions are accessible separately, which is the biggest pro
//
// 3. use an actual database (for blockchain and users this makes the most sense tbh but pending
// transactions are perfectly fine in memory)
/// Creates a new database
pub fn create_database() -> Db {
Db::new()
}
#[derive(Debug, Clone)]
pub struct Db {
// heh. also https://doc.rust-lang.org/std/collections/struct.LinkedList.html says Vec is generally faster
pub blockchain: Arc<RwLock<Vec<Block>>>,
// every proposer can have _one_ pending transaction, a way to enforce this, String is proposer identifier
pub pending_transactions: Arc<RwLock<HashMap<String, Transaction>>>,
// this was bound to happen eventually
pub users: Arc<RwLock<HashMap<String, User>>>,
}
impl Db {
fn new() -> Self {
Db {
blockchain: Arc::new(RwLock::new(Vec::new())),
pending_transactions: Arc::new(RwLock::new(HashMap::new())),
users: Arc::new(RwLock::new(HashMap::new())),
}
}
}
/// A transaction between `source` and `target` that moves `amount` Note:
/// https://serde.rs/container-attrs.html might be valueable to normalize the serialize/deserialize
/// conventions as these will be hashed
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Transaction {
pub source: String,
pub target: String,
pub amount: i32,
pub timestamp: NaiveDateTime,
}
/// A block that was proposed with `transaction_list` and `nonce` that made `hash` valid
/// https://serde.rs/container-attrs.html might be valueable to normalize the serialize/deserialize
/// conventions as these will be hashed
#[derive(Serialize, Deserialize, Debug)]
pub struct Block {
// TODO: transaction list should hold transaction hash values <09-04-21, yigit> //
// but do we link them somehow? (like a log of old transactions?)
// we can leave this as is and whenever we have a new block we _could_ just log it to file
// somewhere
// I want to keep this as a String vector because it makes things easier elsewhere
pub transaction_list: Vec<String>, // hashes of the transactions (or just "source" for now)
pub nonce: String,
pub timestamp: NaiveDateTime,
pub hash: String, // future proof'd baby
}
#[derive(Serialize, Deserialize, Debug)]
pub struct User {
pub username: String,
pub pubkey: String
}
// TODO: write schema tests using the original repo <09-04-21, yigit> //
|