feat: ✨ blockchain and block transfer
This commit is contained in:
parent
35c1207cff
commit
e7d10c46f8
6 changed files with 98 additions and 62 deletions
|
@ -5,8 +5,6 @@ use serde::{Deserialize, Serialize};
|
|||
use sha3::{Digest, Sha3_512};
|
||||
use tokio::sync::broadcast::Sender;
|
||||
|
||||
use crate::blockchain::BlockChain;
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct Block {
|
||||
pub index: u64,
|
||||
|
@ -49,10 +47,10 @@ impl Block {
|
|||
block
|
||||
}
|
||||
|
||||
pub fn mine(&mut self, blockhain: BlockChain) -> Self {
|
||||
pub fn mine(&mut self, difficulty: usize) -> Self {
|
||||
let mut hash = self.calculate_hash();
|
||||
loop {
|
||||
if !hash.starts_with(&"0".repeat(blockhain.difficulty)) {
|
||||
if !hash.starts_with(&"0".repeat(difficulty)) {
|
||||
self.proof_of_work += 1;
|
||||
hash = self.calculate_hash();
|
||||
} else {
|
||||
|
|
|
@ -34,20 +34,25 @@ impl BlockChain {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn add_block(
|
||||
pub fn create_block(
|
||||
&mut self,
|
||||
data: String,
|
||||
data: impl ToString,
|
||||
instant: Instant,
|
||||
block_data_channel_sender: Sender<Block>,
|
||||
) {
|
||||
let new_block = Block::new(
|
||||
self.chain.len() as u64,
|
||||
data,
|
||||
data.to_string(),
|
||||
self.chain[&self.chain.len() - 1].hash.clone(),
|
||||
instant,
|
||||
block_data_channel_sender,
|
||||
)
|
||||
.mine(self.clone());
|
||||
.mine(self.difficulty);
|
||||
self.chain.push(new_block);
|
||||
}
|
||||
|
||||
pub fn add_block(&mut self, mut block: Block) {
|
||||
block.mine(self.difficulty);
|
||||
self.chain.push(block);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ use futures_util::{stream::SplitStream, StreamExt};
|
|||
use tokio::net::TcpStream;
|
||||
use tokio_tungstenite::{connect_async, MaybeTlsStream, WebSocketStream};
|
||||
|
||||
use crate::ClientConfig;
|
||||
use crate::{block::Block, blockchain::BlockChain, ClientConfig};
|
||||
|
||||
pub async fn start_network(client_config: ClientConfig) {
|
||||
let ws_stream = match connect_async(format!(
|
||||
|
@ -19,38 +19,64 @@ pub async fn start_network(client_config: ClientConfig) {
|
|||
}
|
||||
|
||||
async fn sync(ws_stream_receiver: SplitStream<WebSocketStream<MaybeTlsStream<TcpStream>>>) {
|
||||
let mut ws_stream = match receive_blockchain(ws_stream_receiver).await {
|
||||
Some(ws_stream) => ws_stream,
|
||||
let (mut ws_stream, mut blockchain) = match receive_blockchain(ws_stream_receiver).await {
|
||||
Some((ws_stream, blockchain)) => (ws_stream, blockchain),
|
||||
None => return,
|
||||
};
|
||||
loop {
|
||||
ws_stream = match receive_block(ws_stream).await {
|
||||
Some(ws_stream) => ws_stream,
|
||||
let block: Block;
|
||||
(ws_stream, block) = match receive_block(ws_stream).await {
|
||||
Some((ws_stream, block)) => (ws_stream, block),
|
||||
None => return,
|
||||
}
|
||||
};
|
||||
blockchain.add_block(block);
|
||||
}
|
||||
}
|
||||
|
||||
async fn receive_blockchain(mut ws_stream_receiver: SplitStream<WebSocketStream<MaybeTlsStream<TcpStream>>>) -> Option<SplitStream<WebSocketStream<MaybeTlsStream<TcpStream>>>> {
|
||||
async fn receive_blockchain(
|
||||
mut ws_stream_receiver: SplitStream<WebSocketStream<MaybeTlsStream<TcpStream>>>,
|
||||
) -> Option<(
|
||||
SplitStream<WebSocketStream<MaybeTlsStream<TcpStream>>>,
|
||||
BlockChain,
|
||||
)> {
|
||||
match ws_stream_receiver.next().await {
|
||||
Some(message) => match message {
|
||||
Ok(message) => {
|
||||
println!("{}", message);
|
||||
Some(ws_stream_receiver)
|
||||
},
|
||||
if let tokio_tungstenite::tungstenite::Message::Text(message) = message {
|
||||
let blockchain: BlockChain = match serde_json::from_str(&message[..]) {
|
||||
Ok(blockchain) => blockchain,
|
||||
Err(_) => return None,
|
||||
};
|
||||
Some((ws_stream_receiver, blockchain))
|
||||
} else {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
Err(_) => return None,
|
||||
},
|
||||
None => return None,
|
||||
}
|
||||
}
|
||||
|
||||
async fn receive_block(mut ws_stream_receiver: SplitStream<WebSocketStream<MaybeTlsStream<TcpStream>>>) -> Option<SplitStream<WebSocketStream<MaybeTlsStream<TcpStream>>>> {
|
||||
async fn receive_block(
|
||||
mut ws_stream_receiver: SplitStream<WebSocketStream<MaybeTlsStream<TcpStream>>>,
|
||||
) -> Option<(
|
||||
SplitStream<WebSocketStream<MaybeTlsStream<TcpStream>>>,
|
||||
Block,
|
||||
)> {
|
||||
match ws_stream_receiver.next().await {
|
||||
Some(message) => match message {
|
||||
Ok(message) => {
|
||||
println!("{}", message);
|
||||
Some(ws_stream_receiver)
|
||||
},
|
||||
if let tokio_tungstenite::tungstenite::Message::Text(message) = message {
|
||||
let block: Block = match serde_json::from_str(&message[..]) {
|
||||
Ok(block) => block,
|
||||
Err(_) => return None,
|
||||
};
|
||||
Some((ws_stream_receiver, block))
|
||||
} else {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
Err(_) => return None,
|
||||
},
|
||||
None => return None,
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
use rust_blockchain::{
|
||||
blockchain::BlockChain,
|
||||
client_network, server_network,
|
||||
utils::{read_client_config, read_server_config, take_args},
|
||||
Runner,
|
||||
};
|
||||
use tokio::sync::broadcast;
|
||||
use tokio::sync::{broadcast, Mutex};
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
|
@ -28,9 +30,11 @@ async fn server() {
|
|||
|
||||
let blockchain = BlockChain::new(server_config.difficulty.into());
|
||||
let block_data_channel_sender = broadcast::channel(1).0;
|
||||
let blockhain_thread_safe = Arc::new(Mutex::new(blockchain));
|
||||
|
||||
server_network::start_network(
|
||||
server_config,
|
||||
&blockchain,
|
||||
blockhain_thread_safe,
|
||||
block_data_channel_sender.subscribe(),
|
||||
)
|
||||
.await;
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
use futures_util::{stream::SplitSink, SinkExt, StreamExt};
|
||||
use tokio::{
|
||||
net::TcpListener,
|
||||
sync::broadcast::Receiver,
|
||||
sync::{broadcast::Receiver, Mutex},
|
||||
};
|
||||
use tokio_tungstenite::{accept_async, tungstenite::Message, WebSocketStream};
|
||||
|
||||
|
@ -9,7 +11,7 @@ use crate::{block::Block, blockchain::BlockChain, ServerConfig};
|
|||
|
||||
pub async fn start_network(
|
||||
server_config: ServerConfig,
|
||||
blockchain: &BlockChain,
|
||||
blockchain_thread_safe: Arc<Mutex<BlockChain>>,
|
||||
block_data_channel_receiver: Receiver<Block>,
|
||||
) {
|
||||
let listener_socket = match TcpListener::bind(format!(
|
||||
|
@ -25,12 +27,12 @@ pub async fn start_network(
|
|||
if let Ok(connection) = listener_socket.accept().await {
|
||||
let ws_stream = match accept_async(connection.0).await {
|
||||
Ok(ws_stream) => ws_stream,
|
||||
Err(_) => return ,
|
||||
Err(_) => return,
|
||||
};
|
||||
let (ws_stream_sender, _) = ws_stream.split();
|
||||
tokio::spawn(sync(
|
||||
ws_stream_sender,
|
||||
blockchain.clone(),
|
||||
blockchain_thread_safe.clone(),
|
||||
block_data_channel_receiver.resubscribe(),
|
||||
));
|
||||
}
|
||||
|
@ -39,50 +41,51 @@ pub async fn start_network(
|
|||
|
||||
async fn sync(
|
||||
ws_stream_sender: SplitSink<WebSocketStream<tokio::net::TcpStream>, Message>,
|
||||
blockchain: BlockChain,
|
||||
block_data_channel_receiver: Receiver<Block>,
|
||||
blockchain_thread_safe: Arc<Mutex<BlockChain>>,
|
||||
mut block_data_channel_receiver: Receiver<Block>,
|
||||
) {
|
||||
let ws_stream_sender = match send_blockchain(ws_stream_sender, blockchain).await {
|
||||
let mut ws_stream_sender = match send_blockchain(ws_stream_sender, blockchain_thread_safe).await
|
||||
{
|
||||
Some(ws_stream_sender) => ws_stream_sender,
|
||||
None => return,
|
||||
};
|
||||
send_blocks(ws_stream_sender, block_data_channel_receiver).await;
|
||||
loop {
|
||||
let block = match block_data_channel_receiver.recv().await {
|
||||
Ok(block) => block,
|
||||
Err(_) => return,
|
||||
};
|
||||
ws_stream_sender = match send_block(ws_stream_sender, block).await {
|
||||
Some(ws_stream_sender) => ws_stream_sender,
|
||||
None => return,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn send_blockchain(mut ws_stream_sender: SplitSink<WebSocketStream<tokio::net::TcpStream>, Message>, blockchain: BlockChain) -> Option<SplitSink<WebSocketStream<tokio::net::TcpStream>, Message>> {
|
||||
let blockchain_data = serde_json::json!({
|
||||
"blockchain": blockchain
|
||||
})
|
||||
.to_string();
|
||||
async fn send_blockchain(
|
||||
mut ws_stream_sender: SplitSink<WebSocketStream<tokio::net::TcpStream>, Message>,
|
||||
blockchain_thread_safe: Arc<Mutex<BlockChain>>,
|
||||
) -> Option<SplitSink<WebSocketStream<tokio::net::TcpStream>, Message>> {
|
||||
let blockchain = blockchain_thread_safe.lock().await;
|
||||
let blockchain_data = serde_json::json!(*blockchain).to_string();
|
||||
match ws_stream_sender.send(blockchain_data.into()).await {
|
||||
Ok(_) => {
|
||||
match ws_stream_sender.flush().await {
|
||||
Ok(_) => Some(ws_stream_sender),
|
||||
Err(_) => None,
|
||||
}
|
||||
Ok(_) => match ws_stream_sender.flush().await {
|
||||
Ok(_) => Some(ws_stream_sender),
|
||||
Err(_) => None,
|
||||
},
|
||||
Err(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
async fn send_blocks(mut ws_stream_sender: SplitSink<WebSocketStream<tokio::net::TcpStream>, Message>, mut block_data_channel_receiver: Receiver<Block>) {
|
||||
loop {
|
||||
match block_data_channel_receiver.recv().await {
|
||||
Ok(block) => {
|
||||
let block_data = serde_json::json!({
|
||||
"block": block
|
||||
})
|
||||
.to_string();
|
||||
match ws_stream_sender.send(block_data.into()).await {
|
||||
Ok(_) => {
|
||||
if ws_stream_sender.flush().await.is_err() {
|
||||
return;
|
||||
}
|
||||
}
|
||||
Err(_) => return,
|
||||
}
|
||||
}
|
||||
Err(_) => return,
|
||||
}
|
||||
async fn send_block(
|
||||
mut ws_stream_sender: SplitSink<WebSocketStream<tokio::net::TcpStream>, Message>,
|
||||
block: Block,
|
||||
) -> Option<SplitSink<WebSocketStream<tokio::net::TcpStream>, Message>> {
|
||||
let block_data = serde_json::json!(block).to_string();
|
||||
match ws_stream_sender.send(block_data.into()).await {
|
||||
Ok(_) => match ws_stream_sender.flush().await {
|
||||
Ok(_) => Some(ws_stream_sender),
|
||||
Err(_) => None,
|
||||
},
|
||||
Err(_) => None,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@ async fn create_block() {
|
|||
let instant = Instant::now();
|
||||
let mut blockchain = BlockChain::new(1);
|
||||
let block_data_channel_sender = channel(1).0;
|
||||
BlockChain::add_block(
|
||||
BlockChain::create_block(
|
||||
&mut blockchain,
|
||||
"Ahmet Kaan Gümüş".to_string(),
|
||||
instant,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue