use crate::Database;
use axum::extract::{Path, Query};
use axum::{Extension, Json};
use chrono::NaiveDateTime;
use futures::StreamExt;
use serde::{Deserialize, Serialize};
use std::ptr::hash;
#[derive(Serialize)]
pub struct BlockList {
hash: String,
height: i64,
version: i32,
timestamp: NaiveDateTime,
bits: i32,
nonce: u32,
difficulty: i64,
tx_count: i64,
}
pub async fn list(Extension(database): Extension<Database>) -> Json<Vec<BlockList>> {
let database = database.get().await.unwrap();
let blocks = crate::database::blocks::fetch_latest_blocks(&database, 5)
.await
.unwrap();
Json(
blocks
.into_iter()
.map(|(mut block, tx_count)| {
block.hash.reverse();
BlockList {
hash: hex::encode(block.hash),
height: block.height,
version: block.version,
timestamp: block.timestamp,
bits: block.bits,
nonce: block.nonce,
difficulty: block.difficulty,
tx_count,
}
})
.collect(),
)
}
#[derive(Serialize)]
pub struct GetResponse {
tx_count: i64,
#[serde(flatten)]
block: Block,
}
#[derive(Serialize)]
pub struct Block {
height: i64,
version: i32,
size: i32,
merkle_root_hash: String,
timestamp: NaiveDateTime,
bits: i32,
nonce: u32,
difficulty: i64,
transactions: Vec<Transaction>,
hash: String,
}
#[derive(Serialize)]
pub struct Transaction {
hash: String,
version: i32,
lock_time: i32,
weight: i64,
coinbase: bool,
replace_by_fee: bool,
inputs: Vec<TransactionInput>,
outputs: Vec<TransactionOutput>,
}
#[derive(Serialize)]
pub struct TransactionInput {
previous_output: Option<TransactionOutput>,
script: String,
}
impl From<crate::database::transactions::TransactionInput> for TransactionInput {
fn from(txi: crate::database::transactions::TransactionInput) -> Self {
Self {
previous_output: txi.previous_output_tx.map(Into::into),
script: txi.script,
}
}
}
#[derive(Serialize)]
pub struct TransactionOutput {
value: i64,
script: String,
unspendable: bool,
address: Option<String>,
}
impl From<crate::database::transactions::TransactionOutput> for TransactionOutput {
fn from(txo: crate::database::transactions::TransactionOutput) -> Self {
Self {
value: txo.value,
script: txo.script,
unspendable: txo.unspendable,
address: txo.address,
}
}
}
#[derive(Deserialize)]
pub struct HandleQuery {
#[serde(default)]
offset: u32,
}
pub async fn handle(
Extension(database): Extension<Database>,
Path(height): Path<i64>,
Query(query): Query<HandleQuery>,
) -> Json<GetResponse> {
let database = database.get().await.unwrap();
let offset = i64::from(query.offset);
let limit = 30;
let mut block = crate::database::blocks::fetch_block_by_height(&database, height)
.await
.unwrap()
.unwrap();
let (count, transactions) = crate::database::transactions::fetch_transactions_for_block(
&database, block.id, limit, offset,
)
.await
.unwrap();
block.hash.reverse();
let block = Block {
hash: hex::encode(block.hash),
height: block.height,
version: block.version,
size: block.size,
merkle_root_hash: hex::encode(block.merkle_root_hash),
timestamp: block.timestamp,
bits: block.bits,
nonce: block.nonce,
difficulty: block.difficulty,
transactions: transactions
.into_iter()
.map(|mut tx| {
tx.hash.reverse();
Transaction {
hash: hex::encode(tx.hash),
version: tx.version,
lock_time: tx.lock_time,
weight: tx.weight,
coinbase: tx.coinbase,
replace_by_fee: tx.replace_by_fee,
inputs: tx.inputs.0.into_iter().map(Into::into).collect(),
outputs: tx.outputs.0.into_iter().map(Into::into).collect(),
}
})
.collect(),
};
Json(GetResponse {
tx_count: count,
block,
})
}