aboutsummaryrefslogtreecommitdiffstats
path: root/src/handlers.rs
blob: 89905a32e0e4aa4c9b7ebd5dd3552e82c2d42b74 (plain)
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
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
/// 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::{Block, Db, Transaction};

/// GET /transaction
/// Returns JSON array of transactions
/// Cannot fail
pub async fn list_transactions(db: Db) -> Result<impl warp::Reply, Infallible> {
    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<impl warp::Reply, Infallible> {
    debug!("list all blocks");

    let mut result = Vec::new();
    let blocks = db.blockchain.read();

    for block in blocks.iter() {
        result.push(block);
    }

    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<impl warp::Reply, warp::Rejection> {
    debug!("new transaction request {:?}", new_transaction);

    // let mut transactions = db.lock().await;
    let mut transactions = db.pending_transactions.write();

    transactions.insert(new_transaction.source.to_owned(), new_transaction);

    Ok(StatusCode::CREATED)
}

/// POST /transaction, authenticated
/// The transaction arrived in this method has been authored by the public key in the source
pub async fn propose_authenticated_transaction(
    header: HeaderMap<HeaderName, HeaderValue>,
    new_transaction: Transaction,
    db: Db,
) -> Result<impl warp::Reply, warp::Rejection> {

    // auth logic
    debug!("new transaction request {:?}", new_transaction);

    // let mut transactions = db.lock().await;
    let mut transactions = db.pending_transactions.write();

    transactions.insert(new_transaction.source.to_owned(), new_transaction);

    Ok(StatusCode::CREATED)
}


/// 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<impl warp::Reply, warp::Rejection> {
    debug!("new block request {:?}", new_block);

    // https://blog.logrocket.com/create-an-async-crud-web-service-in-rust-with-warp/ (this has
    // error.rs, error struct, looks very clean)

    let pending_transactions = db.pending_transactions.upgradable_read();
    let blockchain = db.blockchain.upgradable_read();

    // 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);
        }
    }

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