diff options
author | Yigit Sever | 2021-04-12 05:32:53 +0300 |
---|---|---|
committer | Yigit Sever | 2021-04-12 05:32:53 +0300 |
commit | 44d21b676f90a2fc8b255eb9c1393e53f40c9daa (patch) | |
tree | edfadfd279dc9fcfaa6c27f819c7f0e69d14599c | |
parent | 6c0345ecda5e46da88bc6ca513a28c648c29833c (diff) | |
download | gradecoin-44d21b676f90a2fc8b255eb9c1393e53f40c9daa.tar.gz gradecoin-44d21b676f90a2fc8b255eb9c1393e53f40c9daa.tar.bz2 gradecoin-44d21b676f90a2fc8b255eb9c1393e53f40c9daa.zip |
Implement proof-of-work
Using blacke2s: https://docs.rs/blake2/0.9.1/blake2/
Using this guy's hash checker https://gist.github.com/gkbrk/2e4835e3a17b3fb6e1e7
blacke2s with 5 bits 0 can mine a block between 20 seconds to 359 during
my tests, hope it'll be fun
-rw-r--r-- | Cargo.lock | 35 | ||||
-rw-r--r-- | Cargo.toml | 2 | ||||
-rw-r--r-- | TODO.md | 4 | ||||
-rw-r--r-- | examples/mining.rs | 35 | ||||
-rw-r--r-- | src/custom_filters.rs | 8 | ||||
-rw-r--r-- | src/handlers.rs | 54 | ||||
-rw-r--r-- | src/lib.rs | 9 | ||||
-rw-r--r-- | src/main.rs | 6 | ||||
-rw-r--r-- | src/routes.rs | 80 | ||||
-rw-r--r-- | src/schema.rs | 12 |
10 files changed, 207 insertions, 38 deletions
@@ -45,6 +45,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" | |||
45 | checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" | 45 | checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" |
46 | 46 | ||
47 | [[package]] | 47 | [[package]] |
48 | name = "blake2" | ||
49 | version = "0.9.1" | ||
50 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
51 | checksum = "10a5720225ef5daecf08657f23791354e1685a8c91a4c60c7f3d3b2892f978f4" | ||
52 | dependencies = [ | ||
53 | "crypto-mac", | ||
54 | "digest", | ||
55 | "opaque-debug", | ||
56 | ] | ||
57 | |||
58 | [[package]] | ||
48 | name = "block-buffer" | 59 | name = "block-buffer" |
49 | version = "0.9.0" | 60 | version = "0.9.0" |
50 | source = "registry+https://github.com/rust-lang/crates.io-index" | 61 | source = "registry+https://github.com/rust-lang/crates.io-index" |
@@ -123,6 +134,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" | |||
123 | checksum = "8aebca1129a03dc6dc2b127edd729435bbc4a37e1d5f4d7513165089ceb02634" | 134 | checksum = "8aebca1129a03dc6dc2b127edd729435bbc4a37e1d5f4d7513165089ceb02634" |
124 | 135 | ||
125 | [[package]] | 136 | [[package]] |
137 | name = "crypto-mac" | ||
138 | version = "0.8.0" | ||
139 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
140 | checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab" | ||
141 | dependencies = [ | ||
142 | "generic-array", | ||
143 | "subtle", | ||
144 | ] | ||
145 | |||
146 | [[package]] | ||
126 | name = "digest" | 147 | name = "digest" |
127 | version = "0.9.0" | 148 | version = "0.9.0" |
128 | source = "registry+https://github.com/rust-lang/crates.io-index" | 149 | source = "registry+https://github.com/rust-lang/crates.io-index" |
@@ -280,7 +301,9 @@ dependencies = [ | |||
280 | name = "gradecoin" | 301 | name = "gradecoin" |
281 | version = "0.1.0" | 302 | version = "0.1.0" |
282 | dependencies = [ | 303 | dependencies = [ |
304 | "blake2", | ||
283 | "chrono", | 305 | "chrono", |
306 | "hex-literal", | ||
284 | "lazy_static", | 307 | "lazy_static", |
285 | "log", | 308 | "log", |
286 | "parking_lot", | 309 | "parking_lot", |
@@ -353,6 +376,12 @@ dependencies = [ | |||
353 | ] | 376 | ] |
354 | 377 | ||
355 | [[package]] | 378 | [[package]] |
379 | name = "hex-literal" | ||
380 | version = "0.3.1" | ||
381 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
382 | checksum = "5af1f635ef1bc545d78392b136bfe1c9809e029023c84a3638a864a10b8819c8" | ||
383 | |||
384 | [[package]] | ||
356 | name = "http" | 385 | name = "http" |
357 | version = "0.2.3" | 386 | version = "0.2.3" |
358 | source = "registry+https://github.com/rust-lang/crates.io-index" | 387 | source = "registry+https://github.com/rust-lang/crates.io-index" |
@@ -980,6 +1009,12 @@ dependencies = [ | |||
980 | ] | 1009 | ] |
981 | 1010 | ||
982 | [[package]] | 1011 | [[package]] |
1012 | name = "subtle" | ||
1013 | version = "2.4.0" | ||
1014 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
1015 | checksum = "1e81da0851ada1f3e9d4312c704aa4f8806f0f9d69faaf8df2f3464b4a9437c2" | ||
1016 | |||
1017 | [[package]] | ||
983 | name = "syn" | 1018 | name = "syn" |
984 | version = "1.0.68" | 1019 | version = "1.0.68" |
985 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1020 | source = "registry+https://github.com/rust-lang/crates.io-index" |
@@ -16,6 +16,8 @@ pretty_env_logger = "0.3.1" | |||
16 | parking_lot = "0.10.0" | 16 | parking_lot = "0.10.0" |
17 | serde_json = "1.0.59" | 17 | serde_json = "1.0.59" |
18 | lazy_static = "1.4.0" | 18 | lazy_static = "1.4.0" |
19 | blake2 = "0.9.1" | ||
20 | hex-literal = "0.3.1" | ||
19 | 21 | ||
20 | [dev-dependencies] | 22 | [dev-dependencies] |
21 | serde_test = "1.0.117" | 23 | serde_test = "1.0.117" |
@@ -1,8 +1,6 @@ | |||
1 | # TODO | 1 | # TODO |
2 | 2 | ||
3 | ## Proof-of-work | 3 | ## Proof-of-work |
4 | - [ ] pick a block proposal scheme (= pick hash function) [list of hash functions](https://en.bitcoinwiki.org/wiki/List_of_hash_functions) | ||
5 | - [ ] check the nonce for incoming blocks | ||
6 | 4 | ||
7 | ## Authentication | 5 | ## Authentication |
8 | - [X] pick a user authentication scheme = [JWT](https://tools.ietf.org/html/rfc7519) Seems perfect | 6 | - [X] pick a user authentication scheme = [JWT](https://tools.ietf.org/html/rfc7519) Seems perfect |
@@ -26,3 +24,5 @@ | |||
26 | ## Done & Brag | 24 | ## Done & Brag |
27 | - [x] Switch to RwLock (parking_lot) (done at 2021-04-07 03:43, two possible schemes to represent inner Db (ledger) in code) | 25 | - [x] Switch to RwLock (parking_lot) (done at 2021-04-07 03:43, two possible schemes to represent inner Db (ledger) in code) |
28 | - [x] We need our own representation of students and their grades, "there is no blockchain" (done at 2021-04-12 00:05) | 26 | - [x] We need our own representation of students and their grades, "there is no blockchain" (done at 2021-04-12 00:05) |
27 | - [x] pick a block proposal scheme (= pick hash function) [list of hash functions](https://en.bitcoinwiki.org/wiki/List_of_hash_functions) (done at 2021-04-12 05:30) | ||
28 | - [x] check the nonce for incoming blocks (done at 2021-04-12 05:30) | ||
diff --git a/examples/mining.rs b/examples/mining.rs new file mode 100644 index 0000000..56e33f3 --- /dev/null +++ b/examples/mining.rs | |||
@@ -0,0 +1,35 @@ | |||
1 | use chrono::NaiveDate; | ||
2 | use gradecoin::schema::NakedBlock; | ||
3 | use serde_json; | ||
4 | use std::time::Instant; | ||
5 | |||
6 | use blake2::{Blake2s, Digest}; | ||
7 | |||
8 | pub fn main() { | ||
9 | let mut b = NakedBlock { | ||
10 | transaction_list: vec![ | ||
11 | "hash_value".to_owned(), | ||
12 | ], | ||
13 | nonce: 0, | ||
14 | timestamp: NaiveDate::from_ymd(2021, 04, 08).and_hms(12, 30, 30), | ||
15 | }; | ||
16 | |||
17 | let now = Instant::now(); | ||
18 | |||
19 | for nonce in 0..u32::MAX { | ||
20 | b.nonce = nonce; | ||
21 | |||
22 | let j = serde_json::to_vec(&b).unwrap(); | ||
23 | |||
24 | let result = Blake2s::digest(&j); | ||
25 | |||
26 | let first_five = result[31] as i32 + result[30] as i32 + (result[29] << 4) as i32; | ||
27 | |||
28 | if first_five == 0 { | ||
29 | println!("{} - {:x}\n{:?}", nonce, result, b); | ||
30 | break; | ||
31 | } | ||
32 | } | ||
33 | |||
34 | println!("it took {} seconds", now.elapsed().as_secs()); | ||
35 | } | ||
diff --git a/src/custom_filters.rs b/src/custom_filters.rs index 0806c6d..315ba4a 100644 --- a/src/custom_filters.rs +++ b/src/custom_filters.rs | |||
@@ -1,10 +1,7 @@ | |||
1 | // Common filters ment to be shared between many endpoints | 1 | use gradecoin::schema::{AuthRequest, Block, Db, Transaction}; |
2 | |||
3 | use std::convert::Infallible; | 2 | use std::convert::Infallible; |
4 | use warp::{Filter, Rejection}; | 3 | use warp::{Filter, Rejection}; |
5 | 4 | ||
6 | use crate::schema::{Block, Db, Transaction, AuthRequest}; | ||
7 | |||
8 | // Database context for routes | 5 | // Database context for routes |
9 | pub fn with_db(db: Db) -> impl Filter<Extract = (Db,), Error = Infallible> + Clone { | 6 | pub fn with_db(db: Db) -> impl Filter<Extract = (Db,), Error = Infallible> + Clone { |
10 | warp::any().map(move || db.clone()) | 7 | warp::any().map(move || db.clone()) |
@@ -12,7 +9,8 @@ pub fn with_db(db: Db) -> impl Filter<Extract = (Db,), Error = Infallible> + Clo | |||
12 | 9 | ||
13 | // Accept only json encoded User body and reject big payloads | 10 | // Accept only json encoded User body and reject big payloads |
14 | // TODO: find a good limit for this, (=e2482057; 8 char String + rsa pem) <11-04-21, yigit> // | 11 | // TODO: find a good limit for this, (=e2482057; 8 char String + rsa pem) <11-04-21, yigit> // |
15 | pub fn auth_request_json_body() -> impl Filter<Extract = (AuthRequest,), Error = Rejection> + Clone { | 12 | pub fn auth_request_json_body() -> impl Filter<Extract = (AuthRequest,), Error = Rejection> + Clone |
13 | { | ||
16 | warp::body::content_length_limit(1024 * 32).and(warp::body::json()) | 14 | warp::body::content_length_limit(1024 * 32).and(warp::body::json()) |
17 | } | 15 | } |
18 | 16 | ||
diff --git a/src/handlers.rs b/src/handlers.rs index bfd57bc..6edc96f 100644 --- a/src/handlers.rs +++ b/src/handlers.rs | |||
@@ -2,12 +2,15 @@ | |||
2 | use log::debug; | 2 | use log::debug; |
3 | use parking_lot::RwLockUpgradableReadGuard; | 3 | use parking_lot::RwLockUpgradableReadGuard; |
4 | use serde_json; | 4 | use serde_json; |
5 | use serde_json::json; | ||
5 | use std::convert::Infallible; | 6 | use std::convert::Infallible; |
6 | use warp::{http::Response, http::StatusCode, reply}; | 7 | use warp::{http::Response, http::StatusCode, reply}; |
7 | 8 | ||
9 | use blake2::{Blake2s, Digest}; | ||
10 | |||
8 | use std::fs; | 11 | use std::fs; |
9 | 12 | ||
10 | use crate::schema::{AuthRequest, Block, Db, MetuId, Transaction, User}; | 13 | use gradecoin::schema::{AuthRequest, Block, Db, MetuId, NakedBlock, Transaction, User}; |
11 | 14 | ||
12 | /// POST /register | 15 | /// POST /register |
13 | /// Enables a student to introduce themselves to the system | 16 | /// Enables a student to introduce themselves to the system |
@@ -22,7 +25,6 @@ pub async fn authenticate_user( | |||
22 | let userlist = db.users.upgradable_read(); | 25 | let userlist = db.users.upgradable_read(); |
23 | 26 | ||
24 | if userlist.contains_key(&given_id) { | 27 | if userlist.contains_key(&given_id) { |
25 | |||
26 | let res = Response::builder() | 28 | let res = Response::builder() |
27 | .status(StatusCode::BAD_REQUEST) | 29 | .status(StatusCode::BAD_REQUEST) |
28 | .body("This user is already authenticated"); | 30 | .body("This user is already authenticated"); |
@@ -124,24 +126,44 @@ pub async fn propose_block(new_block: Block, db: Db) -> Result<impl warp::Reply, | |||
124 | } | 126 | } |
125 | } | 127 | } |
126 | 128 | ||
127 | // TODO: check 2, block hash (\w nonce) asserts $hash_condition? <07-04-21, yigit> // | 129 | let naked_block = NakedBlock { |
128 | // assume it is for now | 130 | transaction_list: new_block.transaction_list.clone(), |
131 | nonce: new_block.nonce.clone(), | ||
132 | timestamp: new_block.timestamp.clone(), | ||
133 | }; | ||
129 | 134 | ||
130 | let mut blockchain = RwLockUpgradableReadGuard::upgrade(blockchain); | 135 | let naked_block_flat = serde_json::to_vec(&naked_block).unwrap(); |
131 | 136 | ||
132 | let block_json = serde_json::to_string(&new_block).unwrap(); | 137 | let hashvalue = Blake2s::digest(&naked_block_flat); |
138 | let hash_string = format!("{:x}", hashvalue); | ||
133 | 139 | ||
134 | // let mut file = File::create(format!("{}.block", new_block.timestamp.timestamp())).unwrap(); | 140 | // 5 rightmost bits are zero |
135 | fs::write( | 141 | let should_zero = hashvalue[31] as i32 + hashvalue[30] as i32 + (hashvalue[29] << 4) as i32; |
136 | format!("blocks/{}.block", new_block.timestamp.timestamp()), | ||
137 | block_json, | ||
138 | ) | ||
139 | .unwrap(); | ||
140 | 142 | ||
141 | *blockchain = new_block; | 143 | if should_zero == 0 { |
144 | // one last check to see if block is telling the truth | ||
145 | if hash_string == new_block.hash { | ||
146 | let mut blockchain = RwLockUpgradableReadGuard::upgrade(blockchain); | ||
142 | 147 | ||
143 | let mut pending_transactions = RwLockUpgradableReadGuard::upgrade(pending_transactions); | 148 | let block_json = serde_json::to_string(&new_block).unwrap(); |
144 | pending_transactions.clear(); | ||
145 | 149 | ||
146 | Ok(StatusCode::CREATED) | 150 | fs::write( |
151 | format!("blocks/{}.block", new_block.timestamp.timestamp()), | ||
152 | block_json, | ||
153 | ) | ||
154 | .unwrap(); | ||
155 | |||
156 | *blockchain = new_block; | ||
157 | |||
158 | let mut pending_transactions = RwLockUpgradableReadGuard::upgrade(pending_transactions); | ||
159 | pending_transactions.clear(); | ||
160 | |||
161 | Ok(StatusCode::CREATED) | ||
162 | } else { | ||
163 | Ok(StatusCode::BAD_REQUEST) | ||
164 | } | ||
165 | } else { | ||
166 | // reject | ||
167 | Ok(StatusCode::BAD_REQUEST) | ||
168 | } | ||
147 | } | 169 | } |
diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..aed4591 --- /dev/null +++ b/src/lib.rs | |||
@@ -0,0 +1,9 @@ | |||
1 | pub mod schema; | ||
2 | |||
3 | pub use schema::create_database; | ||
4 | pub use schema::AuthRequest; | ||
5 | pub use schema::Block; | ||
6 | pub use schema::Db; | ||
7 | pub use schema::MetuId; | ||
8 | pub use schema::Transaction; | ||
9 | pub use schema::User; | ||
diff --git a/src/main.rs b/src/main.rs index 373223c..5683aea 100644 --- a/src/main.rs +++ b/src/main.rs | |||
@@ -1,10 +1,10 @@ | |||
1 | use gradecoin::schema::create_database; | ||
1 | use std::env; | 2 | use std::env; |
2 | use warp::Filter; | 3 | use warp::Filter; |
3 | 4 | ||
4 | mod handlers; | ||
5 | mod custom_filters; | 5 | mod custom_filters; |
6 | mod handlers; | ||
6 | mod routes; | 7 | mod routes; |
7 | mod schema; | ||
8 | // mod validators; | 8 | // mod validators; |
9 | 9 | ||
10 | #[tokio::main] | 10 | #[tokio::main] |
@@ -15,7 +15,7 @@ async fn main() { | |||
15 | } | 15 | } |
16 | pretty_env_logger::init(); | 16 | pretty_env_logger::init(); |
17 | 17 | ||
18 | let db = schema::create_database(); | 18 | let db = create_database(); |
19 | 19 | ||
20 | let api = routes::consensus_routes(db); | 20 | let api = routes::consensus_routes(db); |
21 | 21 | ||
diff --git a/src/routes.rs b/src/routes.rs index 9f0adc5..03a2569 100644 --- a/src/routes.rs +++ b/src/routes.rs | |||
@@ -2,7 +2,7 @@ use warp::{Filter, Rejection, Reply}; | |||
2 | 2 | ||
3 | use crate::custom_filters; | 3 | use crate::custom_filters; |
4 | use crate::handlers; | 4 | use crate::handlers; |
5 | use crate::schema::Db; | 5 | use gradecoin::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 { |
@@ -65,12 +65,11 @@ mod tests { | |||
65 | // use std::sync::Arc; | 65 | // use std::sync::Arc; |
66 | use warp::http::StatusCode; | 66 | use warp::http::StatusCode; |
67 | 67 | ||
68 | use crate::schema; | 68 | use gradecoin::schema::{create_database, AuthRequest, Block, Transaction}; |
69 | use crate::schema::{AuthRequest, Block, Transaction}; | ||
70 | 69 | ||
71 | /// Create a mock database to be used in tests | 70 | /// Create a mock database to be used in tests |
72 | fn mocked_db() -> Db { | 71 | fn mocked_db() -> Db { |
73 | let db = schema::create_database(); | 72 | let db = create_database(); |
74 | 73 | ||
75 | db.pending_transactions.write().insert( | 74 | db.pending_transactions.write().insert( |
76 | "hash_value".to_owned(), | 75 | "hash_value".to_owned(), |
@@ -88,7 +87,7 @@ mod tests { | |||
88 | "old_transaction_hash_2".to_owned(), | 87 | "old_transaction_hash_2".to_owned(), |
89 | "old_transaction_hash_3".to_owned(), | 88 | "old_transaction_hash_3".to_owned(), |
90 | ], | 89 | ], |
91 | nonce: "not_a_thing_yet".to_owned(), | 90 | nonce: 0, |
92 | timestamp: chrono::NaiveDate::from_ymd(2021, 04, 08).and_hms(12, 30, 30), | 91 | timestamp: chrono::NaiveDate::from_ymd(2021, 04, 08).and_hms(12, 30, 30), |
93 | hash: "not_a_thing_yet".to_owned(), | 92 | hash: "not_a_thing_yet".to_owned(), |
94 | }; | 93 | }; |
@@ -122,6 +121,26 @@ mod tests { | |||
122 | } | 121 | } |
123 | } | 122 | } |
124 | 123 | ||
124 | /// Create a mock block with a correct mined hash to be used in tests | ||
125 | fn mocked_block() -> Block { | ||
126 | Block { | ||
127 | transaction_list: vec!["hash_value".to_owned()], | ||
128 | nonce: 560108, | ||
129 | timestamp: chrono::NaiveDate::from_ymd(2021, 04, 08).and_hms(12, 30, 30), | ||
130 | hash: "c7d053f3e5b056ba948db3f5c0d30408fb0c29a328a0c3c1cf435fb68d700000".to_owned(), | ||
131 | } | ||
132 | } | ||
133 | |||
134 | /// Create a mock block with a wrong hash and nonce | ||
135 | fn mocked_wrong_block() -> Block { | ||
136 | Block { | ||
137 | transaction_list: vec!["foobarbaz".to_owned(), "dazsaz".to_owned()], | ||
138 | nonce: 1000, // can you imagine | ||
139 | timestamp: chrono::NaiveDate::from_ymd(2021, 04, 12).and_hms(05, 29, 30), | ||
140 | hash: "tnarstnarsuthnarsthlarjstk".to_owned(), | ||
141 | } | ||
142 | } | ||
143 | |||
125 | /// Test simple GET request to /transaction, resource that exists | 144 | /// Test simple GET request to /transaction, resource that exists |
126 | /// https://tools.ietf.org/html/rfc7231#section-6.3.1 | 145 | /// https://tools.ietf.org/html/rfc7231#section-6.3.1 |
127 | /// We should get the only pending transaction available in the database as json | 146 | /// We should get the only pending transaction available in the database as json |
@@ -160,7 +179,7 @@ mod tests { | |||
160 | 179 | ||
161 | assert_eq!(res.status(), StatusCode::OK); | 180 | assert_eq!(res.status(), StatusCode::OK); |
162 | 181 | ||
163 | let expected_json_body = r#"{"transaction_list":["old_transaction_hash_1","old_transaction_hash_2","old_transaction_hash_3"],"nonce":"not_a_thing_yet","timestamp":"2021-04-08T12:30:30","hash":"not_a_thing_yet"}"#; | 182 | let expected_json_body = r#"{"transaction_list":["old_transaction_hash_1","old_transaction_hash_2","old_transaction_hash_3"],"nonce":0,"timestamp":"2021-04-08T12:30:30","hash":"not_a_thing_yet"}"#; |
164 | assert_eq!(res.body(), expected_json_body); | 183 | assert_eq!(res.body(), expected_json_body); |
165 | } | 184 | } |
166 | 185 | ||
@@ -201,7 +220,48 @@ mod tests { | |||
201 | assert_eq!(db.pending_transactions.read().len(), 2); | 220 | assert_eq!(db.pending_transactions.read().len(), 2); |
202 | } | 221 | } |
203 | 222 | ||
204 | /// TEST a POST request to /transaction, an endpoint that exists | 223 | /// Test a POST request to /block, a resource that exists |
224 | /// https://tools.ietf.org/html/rfc7231#section-6.3.2 | ||
225 | /// Should accept the json request, create | ||
226 | /// the block | ||
227 | #[tokio::test] | ||
228 | async fn post_block_201() { | ||
229 | let db = mocked_db(); | ||
230 | let filter = consensus_routes(db.clone()); | ||
231 | |||
232 | let res = warp::test::request() | ||
233 | .method("POST") | ||
234 | .json(&mocked_block()) | ||
235 | .path("/block") | ||
236 | .reply(&filter) | ||
237 | .await; | ||
238 | |||
239 | assert_eq!(res.status(), StatusCode::CREATED); | ||
240 | assert_eq!( | ||
241 | *db.blockchain.read().hash, | ||
242 | "c7d053f3e5b056ba948db3f5c0d30408fb0c29a328a0c3c1cf435fb68d700000".to_owned() | ||
243 | ); | ||
244 | } | ||
245 | |||
246 | /// Test a POST request to /block, a resource that exists | ||
247 | /// https://tools.ietf.org/html/rfc7231#section-6.3.2 | ||
248 | /// Should reject the block because of the wrong hash | ||
249 | #[tokio::test] | ||
250 | async fn post_block_wrong_hash() { | ||
251 | let db = mocked_db(); | ||
252 | let filter = consensus_routes(db.clone()); | ||
253 | |||
254 | let res = warp::test::request() | ||
255 | .method("POST") | ||
256 | .json(&mocked_wrong_block()) | ||
257 | .path("/block") | ||
258 | .reply(&filter) | ||
259 | .await; | ||
260 | |||
261 | assert_eq!(res.status(), StatusCode::BAD_REQUEST); | ||
262 | } | ||
263 | |||
264 | /// Test a POST request to /register, an endpoint that exists | ||
205 | /// https://tools.ietf.org/html/rfc7231#section-6.3.2 | 265 | /// https://tools.ietf.org/html/rfc7231#section-6.3.2 |
206 | /// Should accept the json request, create a new user and | 266 | /// Should accept the json request, create a new user and |
207 | /// add it to the user hashmap in the db | 267 | /// add it to the user hashmap in the db |
@@ -221,9 +281,10 @@ mod tests { | |||
221 | assert_eq!(res.status(), StatusCode::CREATED); | 281 | assert_eq!(res.status(), StatusCode::CREATED); |
222 | assert_eq!(db.users.read().len(), 1); | 282 | assert_eq!(db.users.read().len(), 1); |
223 | } | 283 | } |
224 | /// TEST a POST request to /transaction, an endpoint that exists | 284 | |
285 | /// Test a POST request to /transaction, an endpoint that exists | ||
225 | /// https://tools.ietf.org/html/rfc7231#section-6.3.2 | 286 | /// https://tools.ietf.org/html/rfc7231#section-6.3.2 |
226 | /// Should NOT accept the json request | 287 | /// Should NOT accept the json request as the user is unpriviliged |
227 | #[tokio::test] | 288 | #[tokio::test] |
228 | async fn post_register_unpriviliged_user() { | 289 | async fn post_register_unpriviliged_user() { |
229 | let db = mocked_db(); | 290 | let db = mocked_db(); |
@@ -261,6 +322,5 @@ mod tests { | |||
261 | } | 322 | } |
262 | } | 323 | } |
263 | 324 | ||
264 | // TODO: POST block test <09-04-21, yigit> // | ||
265 | // TODO: POST block without correct transactions test <09-04-21, yigit> // | 325 | // TODO: POST block without correct transactions test <09-04-21, yigit> // |
266 | // TODO: POST transaction while that source has pending transaction test <09-04-21, yigit> // | 326 | // TODO: POST transaction while that source has pending transaction test <09-04-21, yigit> // |
diff --git a/src/schema.rs b/src/schema.rs index 909b5cd..98291d7 100644 --- a/src/schema.rs +++ b/src/schema.rs | |||
@@ -62,17 +62,25 @@ pub struct Block { | |||
62 | // somewhere | 62 | // somewhere |
63 | // I want to keep this as a String vector because it makes things easier elsewhere | 63 | // I want to keep this as a String vector because it makes things easier elsewhere |
64 | pub transaction_list: Vec<String>, // hashes of the transactions (or just "source" for now) | 64 | pub transaction_list: Vec<String>, // hashes of the transactions (or just "source" for now) |
65 | pub nonce: String, | 65 | pub nonce: u32, |
66 | pub timestamp: NaiveDateTime, | 66 | pub timestamp: NaiveDateTime, |
67 | pub hash: String, // future proof'd baby | 67 | pub hash: String, // future proof'd baby |
68 | } | 68 | } |
69 | 69 | ||
70 | /// For prototyping and letting serde handle everything json | ||
71 | #[derive(Serialize, Deserialize, Debug)] | ||
72 | pub struct NakedBlock { | ||
73 | pub transaction_list: Vec<String>, | ||
74 | pub nonce: u32, | ||
75 | pub timestamp: NaiveDateTime, | ||
76 | } | ||
77 | |||
70 | impl Block { | 78 | impl Block { |
71 | /// Genesis block | 79 | /// Genesis block |
72 | pub fn new() -> Block { | 80 | pub fn new() -> Block { |
73 | Block { | 81 | Block { |
74 | transaction_list: vec![], | 82 | transaction_list: vec![], |
75 | nonce: String::from(""), | 83 | nonce: 0, |
76 | timestamp: NaiveDate::from_ymd(2021, 04, 11).and_hms(20, 45, 00), | 84 | timestamp: NaiveDate::from_ymd(2021, 04, 11).and_hms(20, 45, 00), |
77 | hash: String::from(""), | 85 | hash: String::from(""), |
78 | } | 86 | } |