From 84d9c14a17e864058527981e3388cef148827c11 Mon Sep 17 00:00:00 2001 From: Yigit Sever Date: Wed, 7 Apr 2021 04:33:45 +0300 Subject: Implement Block GET/PUT with new schema - `Arc`+`Mutex` is replaced by `parking_lot::RwLock,` decoupled Read+Write and ability to upgrade read locks into write locks if needed - Schema has changed, `Db` is now a struct that implements `new()` to return a new instance of itself, pros/cons listed in code but tl;dr blockchain and pending transactions are separate now - `custom_filters` now supports extracting Block json and Transaction json in separate functions too - /block GET and PUT implemented, `Blocks` currently have one check (transactions appear in pending transaction) - debug is working after something, dunno how I fixed it --- src/handlers.rs | 94 +++++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 71 insertions(+), 23 deletions(-) (limited to 'src/handlers.rs') 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 @@ -// API handlers, the ends of each filter chain - -use log::debug; +/// API handlers, the ends of each filter chain +use log::debug; // this is more useful than debug! learn how to use this +use parking_lot::RwLockUpgradableReadGuard; use std::convert::Infallible; use warp::{http::StatusCode, reply}; -use crate::schema::{Db, Transaction}; // `Block` coming later +use crate::schema::{Block, Db, Transaction}; + +/// GET /transaction +/// Returns JSON array of transactions +/// Cannot fail +pub async fn list_transactions(db: Db) -> Result { + debug!("list all transactions"); + let mut result = Vec::new(); + + let transactions = db.pending_transactions.read(); + // let transactions = transactions.clone().into_iter().collect(); + + for (_, value) in transactions.iter() { + result.push(value) + } + + Ok(reply::with_status(reply::json(&result), StatusCode::OK)) +} + +/// GET /block +/// Returns JSON array of blocks +/// Cannot fail +/// Mostly around for debug purposes +pub async fn list_blocks(db: Db) -> Result { + debug!("list all blocks"); + + let mut result = Vec::new(); + let blocks = db.blockchain.read(); + + for block in blocks.iter() { + result.push(block); + } -// PROPOSE Transaction -// POST /transaction + Ok(reply::with_status(reply::json(&result), StatusCode::OK)) +} + +/// POST /transaction +/// Pushes a new transaction for pending transaction pool +/// Can reject the transaction proposal +/// TODO: when is a new transaction rejected <07-04-21, yigit> // pub async fn propose_transaction( new_transaction: Transaction, db: Db, ) -> Result { debug!("new transaction request {:?}", new_transaction); - let mut transactions = db.lock().await; + // let mut transactions = db.lock().await; + let mut transactions = db.pending_transactions.write(); - transactions.push(new_transaction); + transactions.insert(new_transaction.source.to_owned(), new_transaction); Ok(StatusCode::CREATED) } -// GET Transaction List -// GET /transaction -// Returns JSON array of transactions -// Cannot fail? -pub async fn list_transactions(db: Db) -> Result { - debug!("list all transactions"); +/// POST /block +/// Proposes a new block for the next round +/// Can reject the block +pub async fn propose_block(new_block: Block, db: Db) -> Result { + debug!("new block request {:?}", new_block); - let transactions = db.lock().await; + // https://blog.logrocket.com/create-an-async-crud-web-service-in-rust-with-warp/ (this has + // error.rs, error struct, looks very clean) - let transactions: Vec = transactions.clone().into_iter().collect(); + let pending_transactions = db.pending_transactions.upgradable_read(); + let blockchain = db.blockchain.upgradable_read(); - Ok(reply::with_status( - reply::json(&transactions), - StatusCode::OK, - )) -} + // TODO: check 1, new_block.transaction_list from pending_transactions pool? <07-04-21, yigit> // + for transaction_hash in new_block.transaction_list.iter() { + if !pending_transactions.contains_key(transaction_hash) { + return Ok(StatusCode::BAD_REQUEST); + } + } -// PROPOSE Block -// POST /block + // TODO: check 2, block hash (\w nonce) asserts $hash_condition? <07-04-21, yigit> // + // assume it is for now + + let mut blockchain = RwLockUpgradableReadGuard::upgrade(blockchain); + blockchain.push(new_block); + + let mut pending_transactions = RwLockUpgradableReadGuard::upgrade(pending_transactions); + pending_transactions.clear(); + + Ok(StatusCode::CREATED) +} // `GET /games` // Returns JSON array of todos -- cgit v1.2.3-70-g09d2