diff options
| -rw-r--r-- | Cargo.lock | 63 | ||||
| -rw-r--r-- | Cargo.toml | 1 | ||||
| -rw-r--r-- | TODO.md | 6 | ||||
| -rw-r--r-- | src/custom_filters.rs | 11 | ||||
| -rw-r--r-- | src/handlers.rs | 94 | ||||
| -rw-r--r-- | src/main.rs | 6 | ||||
| -rw-r--r-- | src/routes.rs | 30 | ||||
| -rw-r--r-- | src/schema.rs | 65 |
8 files changed, 220 insertions, 56 deletions
| @@ -108,6 +108,15 @@ dependencies = [ | |||
| 108 | ] | 108 | ] |
| 109 | 109 | ||
| 110 | [[package]] | 110 | [[package]] |
| 111 | name = "cloudabi" | ||
| 112 | version = "0.0.3" | ||
| 113 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 114 | checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" | ||
| 115 | dependencies = [ | ||
| 116 | "bitflags", | ||
| 117 | ] | ||
| 118 | |||
| 119 | [[package]] | ||
| 111 | name = "cpuid-bool" | 120 | name = "cpuid-bool" |
| 112 | version = "0.1.2" | 121 | version = "0.1.2" |
| 113 | source = "registry+https://github.com/rust-lang/crates.io-index" | 122 | source = "registry+https://github.com/rust-lang/crates.io-index" |
| @@ -273,6 +282,7 @@ version = "0.1.0" | |||
| 273 | dependencies = [ | 282 | dependencies = [ |
| 274 | "chrono", | 283 | "chrono", |
| 275 | "log", | 284 | "log", |
| 285 | "parking_lot", | ||
| 276 | "pretty_env_logger", | 286 | "pretty_env_logger", |
| 277 | "serde", | 287 | "serde", |
| 278 | "serde_json", | 288 | "serde_json", |
| @@ -475,6 +485,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" | |||
| 475 | checksum = "9385f66bf6105b241aa65a61cb923ef20efc665cb9f9bb50ac2f0c4b7f378d41" | 485 | checksum = "9385f66bf6105b241aa65a61cb923ef20efc665cb9f9bb50ac2f0c4b7f378d41" |
| 476 | 486 | ||
| 477 | [[package]] | 487 | [[package]] |
| 488 | name = "lock_api" | ||
| 489 | version = "0.3.4" | ||
| 490 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 491 | checksum = "c4da24a77a3d8a6d4862d95f72e6fdb9c09a643ecdb402d754004a557f2bec75" | ||
| 492 | dependencies = [ | ||
| 493 | "scopeguard", | ||
| 494 | ] | ||
| 495 | |||
| 496 | [[package]] | ||
| 478 | name = "log" | 497 | name = "log" |
| 479 | version = "0.4.14" | 498 | version = "0.4.14" |
| 480 | source = "registry+https://github.com/rust-lang/crates.io-index" | 499 | source = "registry+https://github.com/rust-lang/crates.io-index" |
| @@ -597,6 +616,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index" | |||
| 597 | checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" | 616 | checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" |
| 598 | 617 | ||
| 599 | [[package]] | 618 | [[package]] |
| 619 | name = "parking_lot" | ||
| 620 | version = "0.10.2" | ||
| 621 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 622 | checksum = "d3a704eb390aafdc107b0e392f56a82b668e3a71366993b5340f5833fd62505e" | ||
| 623 | dependencies = [ | ||
| 624 | "lock_api", | ||
| 625 | "parking_lot_core", | ||
| 626 | ] | ||
| 627 | |||
| 628 | [[package]] | ||
| 629 | name = "parking_lot_core" | ||
| 630 | version = "0.7.2" | ||
| 631 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 632 | checksum = "d58c7c768d4ba344e3e8d72518ac13e259d7c7ade24167003b8488e10b6740a3" | ||
| 633 | dependencies = [ | ||
| 634 | "cfg-if 0.1.10", | ||
| 635 | "cloudabi", | ||
| 636 | "libc", | ||
| 637 | "redox_syscall 0.1.57", | ||
| 638 | "smallvec", | ||
| 639 | "winapi 0.3.9", | ||
| 640 | ] | ||
| 641 | |||
| 642 | [[package]] | ||
| 600 | name = "percent-encoding" | 643 | name = "percent-encoding" |
| 601 | version = "2.1.0" | 644 | version = "2.1.0" |
| 602 | source = "registry+https://github.com/rust-lang/crates.io-index" | 645 | source = "registry+https://github.com/rust-lang/crates.io-index" |
| @@ -784,6 +827,12 @@ dependencies = [ | |||
| 784 | 827 | ||
| 785 | [[package]] | 828 | [[package]] |
| 786 | name = "redox_syscall" | 829 | name = "redox_syscall" |
| 830 | version = "0.1.57" | ||
| 831 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 832 | checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" | ||
| 833 | |||
| 834 | [[package]] | ||
| 835 | name = "redox_syscall" | ||
| 787 | version = "0.2.5" | 836 | version = "0.2.5" |
| 788 | source = "registry+https://github.com/rust-lang/crates.io-index" | 837 | source = "registry+https://github.com/rust-lang/crates.io-index" |
| 789 | checksum = "94341e4e44e24f6b591b59e47a8a027df12e008d73fd5672dbea9cc22f4507d9" | 838 | checksum = "94341e4e44e24f6b591b59e47a8a027df12e008d73fd5672dbea9cc22f4507d9" |
| @@ -836,6 +885,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" | |||
| 836 | checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2" | 885 | checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2" |
| 837 | 886 | ||
| 838 | [[package]] | 887 | [[package]] |
| 888 | name = "scopeguard" | ||
| 889 | version = "1.1.0" | ||
| 890 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 891 | checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" | ||
| 892 | |||
| 893 | [[package]] | ||
| 839 | name = "serde" | 894 | name = "serde" |
| 840 | version = "1.0.125" | 895 | version = "1.0.125" |
| 841 | source = "registry+https://github.com/rust-lang/crates.io-index" | 896 | source = "registry+https://github.com/rust-lang/crates.io-index" |
| @@ -907,6 +962,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" | |||
| 907 | checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" | 962 | checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" |
| 908 | 963 | ||
| 909 | [[package]] | 964 | [[package]] |
| 965 | name = "smallvec" | ||
| 966 | version = "1.6.1" | ||
| 967 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| 968 | checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e" | ||
| 969 | |||
| 970 | [[package]] | ||
| 910 | name = "socket2" | 971 | name = "socket2" |
| 911 | version = "0.3.19" | 972 | version = "0.3.19" |
| 912 | source = "registry+https://github.com/rust-lang/crates.io-index" | 973 | source = "registry+https://github.com/rust-lang/crates.io-index" |
| @@ -937,7 +998,7 @@ dependencies = [ | |||
| 937 | "cfg-if 1.0.0", | 998 | "cfg-if 1.0.0", |
| 938 | "libc", | 999 | "libc", |
| 939 | "rand 0.8.3", | 1000 | "rand 0.8.3", |
| 940 | "redox_syscall", | 1001 | "redox_syscall 0.2.5", |
| 941 | "remove_dir_all", | 1002 | "remove_dir_all", |
| 942 | "winapi 0.3.9", | 1003 | "winapi 0.3.9", |
| 943 | ] | 1004 | ] |
| @@ -13,6 +13,7 @@ serde = { version = "1.0.104", features = ["derive"] } | |||
| 13 | chrono = { version = "0.4.10", features = ["serde"] } | 13 | chrono = { version = "0.4.10", features = ["serde"] } |
| 14 | log = "0.4.8" | 14 | log = "0.4.8" |
| 15 | pretty_env_logger = "0.3.1" | 15 | pretty_env_logger = "0.3.1" |
| 16 | parking_lot = "0.10.0" | ||
| 16 | 17 | ||
| 17 | [dev-dependencies] | 18 | [dev-dependencies] |
| 18 | serde_json = "1.0.44" | 19 | serde_json = "1.0.44" |
| @@ -1,4 +1,7 @@ | |||
| 1 | # TODO | 1 | # TODO |
| 2 | ## Process | ||
| 3 | - [ ] we need our own representation of students and their grades, "there is no blockchain" | ||
| 4 | |||
| 2 | ## Proof-of-work | 5 | ## Proof-of-work |
| 3 | - [ ] pick a block proposal scheme (= pick hash function) [list of hash functions](https://en.bitcoinwiki.org/wiki/List_of_hash_functions) | 6 | - [ ] pick a block proposal scheme (= pick hash function) [list of hash functions](https://en.bitcoinwiki.org/wiki/List_of_hash_functions) |
| 4 | - [ ] check the nonce for incoming blocks | 7 | - [ ] check the nonce for incoming blocks |
| @@ -7,4 +10,5 @@ | |||
| 7 | - [ ] pick a user authentication scheme | 10 | - [ ] pick a user authentication scheme |
| 8 | - [ ] implement it | 11 | - [ ] implement it |
| 9 | 12 | ||
| 10 | - [ ] Switch to RwLock (parking_lot) | 13 | ## Done & Brag |
| 14 | - [x] Switch to RwLock (parking_lot) (done at 2021-04-07 03:43, two possible schemes to represent inner Db (ledger) in code) | ||
diff --git a/src/custom_filters.rs b/src/custom_filters.rs index 86a78d4..7caf71a 100644 --- a/src/custom_filters.rs +++ b/src/custom_filters.rs | |||
| @@ -3,7 +3,7 @@ | |||
| 3 | use std::convert::Infallible; | 3 | use std::convert::Infallible; |
| 4 | use warp::{Filter, Rejection}; | 4 | use warp::{Filter, Rejection}; |
| 5 | 5 | ||
| 6 | use crate::schema::{Db, Transaction}; // `Block` coming later | 6 | use crate::schema::{Block, Db, Transaction}; |
| 7 | 7 | ||
| 8 | // Database context for routes | 8 | // Database context for routes |
| 9 | pub fn with_db(db: Db) -> impl Filter<Extract = (Db,), Error = Infallible> + Clone { | 9 | pub fn with_db(db: Db) -> impl Filter<Extract = (Db,), Error = Infallible> + Clone { |
| @@ -15,7 +15,12 @@ pub fn with_db(db: Db) -> impl Filter<Extract = (Db,), Error = Infallible> + Clo | |||
| 15 | // warp::query::<ListOptions>() | 15 | // warp::query::<ListOptions>() |
| 16 | // } | 16 | // } |
| 17 | 17 | ||
| 18 | // Accept only JSON body and reject big payloads | 18 | // Accept only json encoded Transaction body and reject big payloads |
| 19 | pub fn json_body() -> impl Filter<Extract = (Transaction,), Error = Rejection> + Clone { | 19 | pub fn transaction_json_body() -> impl Filter<Extract = (Transaction,), Error = Rejection> + Clone { |
| 20 | warp::body::content_length_limit(1024 * 32).and(warp::body::json()) | ||
| 21 | } | ||
| 22 | |||
| 23 | // Accept only json encoded Transaction body and reject big payloads | ||
| 24 | pub fn block_json_body() -> impl Filter<Extract = (Block,), Error = Rejection> + Clone { | ||
| 20 | warp::body::content_length_limit(1024 * 32).and(warp::body::json()) | 25 | warp::body::content_length_limit(1024 * 32).and(warp::body::json()) |
| 21 | } | 26 | } |
diff --git a/src/handlers.rs b/src/handlers.rs index 51c7b63..ecf5a92 100644 --- a/src/handlers.rs +++ b/src/handlers.rs | |||
| @@ -1,45 +1,93 @@ | |||
| 1 | // API handlers, the ends of each filter chain | 1 | /// API handlers, the ends of each filter chain |
| 2 | 2 | use log::debug; // this is more useful than debug! learn how to use this | |
| 3 | use log::debug; | 3 | use parking_lot::RwLockUpgradableReadGuard; |
| 4 | use std::convert::Infallible; | 4 | use std::convert::Infallible; |
| 5 | use warp::{http::StatusCode, reply}; | 5 | use warp::{http::StatusCode, reply}; |
| 6 | 6 | ||
| 7 | use crate::schema::{Db, Transaction}; // `Block` coming later | 7 | use crate::schema::{Block, Db, Transaction}; |
| 8 | |||
| 9 | /// GET /transaction | ||
| 10 | /// Returns JSON array of transactions | ||
| 11 | /// Cannot fail | ||
| 12 | pub async fn list_transactions(db: Db) -> Result<impl warp::Reply, Infallible> { | ||
| 13 | debug!("list all transactions"); | ||
| 14 | let mut result = Vec::new(); | ||
| 15 | |||
| 16 | let transactions = db.pending_transactions.read(); | ||
| 17 | // let transactions = transactions.clone().into_iter().collect(); | ||
| 18 | |||
| 19 | for (_, value) in transactions.iter() { | ||
| 20 | result.push(value) | ||
| 21 | } | ||
| 22 | |||
| 23 | Ok(reply::with_status(reply::json(&result), StatusCode::OK)) | ||
| 24 | } | ||
| 25 | |||
| 26 | /// GET /block | ||
| 27 | /// Returns JSON array of blocks | ||
| 28 | /// Cannot fail | ||
| 29 | /// Mostly around for debug purposes | ||
| 30 | pub async fn list_blocks(db: Db) -> Result<impl warp::Reply, Infallible> { | ||
| 31 | debug!("list all blocks"); | ||
| 32 | |||
| 33 | let mut result = Vec::new(); | ||
| 34 | let blocks = db.blockchain.read(); | ||
| 35 | |||
| 36 | for block in blocks.iter() { | ||
| 37 | result.push(block); | ||
| 38 | } | ||
| 8 | 39 | ||
| 9 | // PROPOSE Transaction | 40 | Ok(reply::with_status(reply::json(&result), StatusCode::OK)) |
| 10 | // POST /transaction | 41 | } |
| 42 | |||
| 43 | /// POST /transaction | ||
| 44 | /// Pushes a new transaction for pending transaction pool | ||
| 45 | /// Can reject the transaction proposal | ||
| 46 | /// TODO: when is a new transaction rejected <07-04-21, yigit> // | ||
| 11 | pub async fn propose_transaction( | 47 | pub async fn propose_transaction( |
| 12 | new_transaction: Transaction, | 48 | new_transaction: Transaction, |
| 13 | db: Db, | 49 | db: Db, |
| 14 | ) -> Result<impl warp::Reply, warp::Rejection> { | 50 | ) -> Result<impl warp::Reply, warp::Rejection> { |
| 15 | debug!("new transaction request {:?}", new_transaction); | 51 | debug!("new transaction request {:?}", new_transaction); |
| 16 | 52 | ||
| 17 | let mut transactions = db.lock().await; | 53 | // let mut transactions = db.lock().await; |
| 54 | let mut transactions = db.pending_transactions.write(); | ||
| 18 | 55 | ||
| 19 | transactions.push(new_transaction); | 56 | transactions.insert(new_transaction.source.to_owned(), new_transaction); |
| 20 | 57 | ||
| 21 | Ok(StatusCode::CREATED) | 58 | Ok(StatusCode::CREATED) |
| 22 | } | 59 | } |
| 23 | 60 | ||
| 24 | // GET Transaction List | 61 | /// POST /block |
| 25 | // GET /transaction | 62 | /// Proposes a new block for the next round |
| 26 | // Returns JSON array of transactions | 63 | /// Can reject the block |
| 27 | // Cannot fail? | 64 | pub async fn propose_block(new_block: Block, db: Db) -> Result<impl warp::Reply, warp::Rejection> { |
| 28 | pub async fn list_transactions(db: Db) -> Result<impl warp::Reply, Infallible> { | 65 | debug!("new block request {:?}", new_block); |
| 29 | debug!("list all transactions"); | ||
| 30 | 66 | ||
| 31 | let transactions = db.lock().await; | 67 | // https://blog.logrocket.com/create-an-async-crud-web-service-in-rust-with-warp/ (this has |
| 68 | // error.rs, error struct, looks very clean) | ||
| 32 | 69 | ||
| 33 | let transactions: Vec<Transaction> = transactions.clone().into_iter().collect(); | 70 | let pending_transactions = db.pending_transactions.upgradable_read(); |
| 71 | let blockchain = db.blockchain.upgradable_read(); | ||
| 34 | 72 | ||
| 35 | Ok(reply::with_status( | 73 | // TODO: check 1, new_block.transaction_list from pending_transactions pool? <07-04-21, yigit> // |
| 36 | reply::json(&transactions), | 74 | for transaction_hash in new_block.transaction_list.iter() { |
| 37 | StatusCode::OK, | 75 | if !pending_transactions.contains_key(transaction_hash) { |
| 38 | )) | 76 | return Ok(StatusCode::BAD_REQUEST); |
| 39 | } | 77 | } |
| 78 | } | ||
| 40 | 79 | ||
| 41 | // PROPOSE Block | 80 | // TODO: check 2, block hash (\w nonce) asserts $hash_condition? <07-04-21, yigit> // |
| 42 | // POST /block | 81 | // assume it is for now |
| 82 | |||
| 83 | let mut blockchain = RwLockUpgradableReadGuard::upgrade(blockchain); | ||
| 84 | blockchain.push(new_block); | ||
| 85 | |||
| 86 | let mut pending_transactions = RwLockUpgradableReadGuard::upgrade(pending_transactions); | ||
| 87 | pending_transactions.clear(); | ||
| 88 | |||
| 89 | Ok(StatusCode::CREATED) | ||
| 90 | } | ||
| 43 | 91 | ||
| 44 | // `GET /games` | 92 | // `GET /games` |
| 45 | // Returns JSON array of todos | 93 | // Returns JSON array of todos |
diff --git a/src/main.rs b/src/main.rs index bcd4173..7ef2597 100644 --- a/src/main.rs +++ b/src/main.rs | |||
| @@ -11,15 +11,15 @@ mod schema; | |||
| 11 | async fn main() { | 11 | async fn main() { |
| 12 | // Show debug logs by default by setting `RUST_LOG=restful_rust=debug` | 12 | // Show debug logs by default by setting `RUST_LOG=restful_rust=debug` |
| 13 | if env::var_os("RUST_LOG").is_none() { | 13 | if env::var_os("RUST_LOG").is_none() { |
| 14 | env::set_var("RUST_LOG", "restful_rust=debug"); | 14 | env::set_var("RUST_LOG", "gradecoin=debug"); |
| 15 | } | 15 | } |
| 16 | pretty_env_logger::init(); | 16 | pretty_env_logger::init(); |
| 17 | 17 | ||
| 18 | let db = schema::ledger(); // 1. we need this to return a _simple_ db | 18 | let db = schema::create_database(); |
| 19 | 19 | ||
| 20 | let api = routes::consensus_routes(db); | 20 | let api = routes::consensus_routes(db); |
| 21 | 21 | ||
| 22 | let routes = api.with(warp::log("restful_rust")); | 22 | let routes = api.with(warp::log("gradecoin")); |
| 23 | 23 | ||
| 24 | // Start the server | 24 | // Start the server |
| 25 | warp::serve(routes).run(([127, 0, 0, 1], 8080)).await; | 25 | warp::serve(routes).run(([127, 0, 0, 1], 8080)).await; |
diff --git a/src/routes.rs b/src/routes.rs index fc4426a..9054fb6 100644 --- a/src/routes.rs +++ b/src/routes.rs | |||
| @@ -4,12 +4,15 @@ use crate::custom_filters; | |||
| 4 | use crate::handlers; | 4 | use crate::handlers; |
| 5 | use crate::schema::Db; | 5 | use crate::schema::Db; |
| 6 | 6 | ||
| 7 | // Root, all routes combined | 7 | /// Root, all routes combined |
| 8 | pub fn consensus_routes(db: Db) -> impl Filter<Extract = impl Reply, Error = Rejection> + Clone { | 8 | pub fn consensus_routes(db: Db) -> impl Filter<Extract = impl Reply, Error = Rejection> + Clone { |
| 9 | transaction_list(db.clone()).or(transaction_propose(db.clone())) | 9 | transaction_list(db.clone()) |
| 10 | .or(transaction_propose(db.clone())) | ||
| 11 | .or(block_propose(db.clone())) | ||
| 12 | .or(block_list(db.clone())) | ||
| 10 | } | 13 | } |
| 11 | 14 | ||
| 12 | // GET /transaction | 15 | /// GET /transaction |
| 13 | pub fn transaction_list(db: Db) -> impl Filter<Extract = impl Reply, Error = Rejection> + Clone { | 16 | pub fn transaction_list(db: Db) -> impl Filter<Extract = impl Reply, Error = Rejection> + Clone { |
| 14 | warp::path!("transaction") | 17 | warp::path!("transaction") |
| 15 | .and(warp::get()) | 18 | .and(warp::get()) |
| @@ -17,15 +20,32 @@ pub fn transaction_list(db: Db) -> impl Filter<Extract = impl Reply, Error = Rej | |||
| 17 | .and_then(handlers::list_transactions) | 20 | .and_then(handlers::list_transactions) |
| 18 | } | 21 | } |
| 19 | 22 | ||
| 20 | // POST /transaction | 23 | /// GET /block |
| 24 | pub fn block_list(db: Db) -> impl Filter<Extract = impl Reply, Error = Rejection> + Clone { | ||
| 25 | warp::path!("block") | ||
| 26 | .and(warp::get()) | ||
| 27 | .and(custom_filters::with_db(db)) | ||
| 28 | .and_then(handlers::list_blocks) | ||
| 29 | } | ||
| 30 | |||
| 31 | /// POST /transaction | ||
| 21 | pub fn transaction_propose(db: Db) -> impl Filter<Extract = impl Reply, Error = Rejection> + Clone { | 32 | pub fn transaction_propose(db: Db) -> impl Filter<Extract = impl Reply, Error = Rejection> + Clone { |
| 22 | warp::path!("transaction") | 33 | warp::path!("transaction") |
| 23 | .and(warp::post()) | 34 | .and(warp::post()) |
| 24 | .and(custom_filters::json_body()) | 35 | .and(custom_filters::transaction_json_body()) |
| 25 | .and(custom_filters::with_db(db)) | 36 | .and(custom_filters::with_db(db)) |
| 26 | .and_then(handlers::propose_transaction) | 37 | .and_then(handlers::propose_transaction) |
| 27 | } | 38 | } |
| 28 | 39 | ||
| 40 | /// POST /block | ||
| 41 | pub fn block_propose(db: Db) -> impl Filter<Extract = impl Reply, Error = Rejection> + Clone { | ||
| 42 | warp::path!("block") | ||
| 43 | .and(warp::post()) | ||
| 44 | .and(custom_filters::block_json_body()) | ||
| 45 | .and(custom_filters::with_db(db)) | ||
| 46 | .and_then(handlers::propose_block) | ||
| 47 | } | ||
| 48 | |||
| 29 | /////////////////////////// | 49 | /////////////////////////// |
| 30 | // below are not mine. // | 50 | // below are not mine. // |
| 31 | /////////////////////////// | 51 | /////////////////////////// |
diff --git a/src/schema.rs b/src/schema.rs index ea36a70..57210a3 100644 --- a/src/schema.rs +++ b/src/schema.rs | |||
| @@ -1,31 +1,46 @@ | |||
| 1 | // Common types used across API | 1 | use chrono::NaiveDateTime; |
| 2 | 2 | use parking_lot::RwLock; | |
| 3 | use chrono::{NaiveDate, NaiveDateTime}; | ||
| 4 | use serde::{Deserialize, Serialize}; | 3 | use serde::{Deserialize, Serialize}; |
| 4 | use std::collections::HashMap; | ||
| 5 | use std::sync::Arc; | 5 | use std::sync::Arc; |
| 6 | use tokio::sync::Mutex; | ||
| 7 | 6 | ||
| 8 | // use crate::validators; | 7 | // use crate::validators; |
| 9 | 8 | ||
| 10 | pub fn ledger() -> Db { | 9 | // In memory data structure |
| 11 | // TODO: there was something simpler in one of the other tutorials? <07-04-21, yigit> // | 10 | |
| 12 | 11 | // Two approaches here | |
| 13 | Arc::new(Mutex::new(vec![ | 12 | // 1. Db is a type |
| 14 | Transaction { | 13 | // pub type Db = Arc<RwLock<Vec<Ledger>>>; |
| 15 | source: String::from("Myself"), | 14 | // Ledger is a struct, we wrap the ledger with arc + mutex in ledger() |
| 16 | target: String::from("Nobody"), | 15 | // to access transactions we need to unwrap blocks as well, vice versa |
| 17 | amount: 4, | 16 | // |
| 18 | timestamp: NaiveDate::from_ymd(2021, 4, 7).and_hms(00, 17, 00), | 17 | // 2. Db is a struct, attributes are wrapped |
| 19 | }, | 18 | // we can offload ::new() to it's member method |
| 20 | ])) | 19 | // blocks and transactions are accessible separately, which is the biggest pro |
| 20 | |||
| 21 | /// Creates a new database | ||
| 22 | pub fn create_database() -> Db { | ||
| 23 | Db::new() | ||
| 21 | } | 24 | } |
| 22 | 25 | ||
| 26 | #[derive(Debug, Clone)] | ||
| 27 | pub struct Db { | ||
| 28 | // heh. also https://doc.rust-lang.org/std/collections/struct.LinkedList.html says Vec is generally faster | ||
| 29 | pub blockchain: Arc<RwLock<Vec<Block>>>, | ||
| 30 | // 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>>>, | ||
| 32 | } | ||
| 23 | 33 | ||
| 24 | // For presentation purposes keep mocked data in in-memory structure | 34 | impl Db { |
| 25 | // In real life scenario connection with regular database would be established | 35 | fn new() -> Self { |
| 26 | 36 | Db { | |
| 27 | pub type Db = Arc<Mutex<Vec<Transaction>>>; | 37 | blockchain: Arc::new(RwLock::new(Vec::new())), |
| 38 | pending_transactions: Arc::new(RwLock::new(HashMap::new())), | ||
| 39 | } | ||
| 40 | } | ||
| 41 | } | ||
| 28 | 42 | ||
| 43 | /// A transaction between `source` and `target` that moves `amount` | ||
| 29 | #[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] | 44 | #[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] |
| 30 | pub struct Transaction { | 45 | pub struct Transaction { |
| 31 | pub source: String, | 46 | pub source: String, |
| @@ -34,14 +49,22 @@ pub struct Transaction { | |||
| 34 | pub timestamp: NaiveDateTime, | 49 | pub timestamp: NaiveDateTime, |
| 35 | } | 50 | } |
| 36 | 51 | ||
| 52 | /// A block that was proposed with `transaction_list` and `nonce` that made `hash` valid | ||
| 37 | #[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] | 53 | #[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] |
| 38 | pub struct Block { | 54 | pub struct Block { |
| 39 | pub transaction_list: Vec<Transaction>, // [Transaction; N] | 55 | pub transaction_list: Vec<String>, // hashes of the transactions (or just "source" for now) |
| 40 | pub nonce: i32, | 56 | pub nonce: i32, |
| 41 | pub timestamp: NaiveDateTime, | 57 | pub timestamp: NaiveDateTime, |
| 42 | pub hash: String, // future proof'd baby | 58 | pub hash: String, // future proof'd baby |
| 43 | } | 59 | } |
| 44 | 60 | ||
| 61 | // pub struct Ledger { | ||
| 62 | // // heh. also https://doc.rust-lang.org/std/collections/struct.LinkedList.html says Vec is generally faster | ||
| 63 | // blockchain: Vec<Block>, | ||
| 64 | // // every proposer can have _one_ pending transaction, a way to enforce this, String is proposer identifier | ||
| 65 | // pending_transactions: HashMap<String, Transaction>, | ||
| 66 | // } | ||
| 67 | |||
| 45 | // #[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] | 68 | // #[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] |
| 46 | // #[serde(rename_all = "camelCase")] | 69 | // #[serde(rename_all = "camelCase")] |
| 47 | // pub struct Game { | 70 | // pub struct Game { |
| @@ -99,6 +122,8 @@ pub struct Block { | |||
| 99 | // )) | 122 | // )) |
| 100 | // } | 123 | // } |
| 101 | 124 | ||
| 125 | // TODO: these tests are amazing, we should write some when schema is decided upon <07-04-21, yigit> // | ||
| 126 | |||
| 102 | // #[cfg(test)] | 127 | // #[cfg(test)] |
| 103 | // mod tests { | 128 | // mod tests { |
| 104 | // use super::*; | 129 | // use super::*; |
