Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 74 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 11 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,25 @@ libp2p = { version = "0.55.0", features = [
# Serde
serde = { version = "^1", features = ["derive"] }
serde_json = "^1"
typetag = "0.2.20"

# Cryptography
hex = "0.4.3"
sha256 = "1.5.0"

# Utils
chrono = "0.4.40"
clap = { version = "4.5.28", features = ["derive"] }
clap_derive = "4.5.32"
dyn-clone = "1.0.17"
rand = { version = "0.8", features = ["std_rng"] }
uuid = { version = "1.15.1", features = ["serde", "v4"] }

thiserror = "2.0.12"

# Tracing
tracing = "0.1.41"
tracing-subscriber = { version = "0.3", features = ["registry", "env-filter"] }

# Node db
# rocksdb = "0.23.0"
94 changes: 94 additions & 0 deletions src/block/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
use std::fmt::{Debug, Display};

use chrono::Utc;
use dyn_clone::DynClone;
use libp2p::identity::{Keypair, SigningError};
use serde::{Deserialize, Serialize};
use sha256::digest;
use uuid::Uuid;

use crate::utils::UnixTimestamp;

pub type TransactionHash = String;
pub type BlockHash = String;

/// Represents a block.
pub struct Block {
pub header: BlockHeader,
pub transactions: Vec<Transaction>,
}

/// Represents the header of a block.
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct BlockHeader {
pub previous_block_hash: BlockHash,
pub timestamp: UnixTimestamp,
pub nonce: String,
pub transaction_hash: TransactionHash,
}

/// Represents a transaction.
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct Transaction {
signature: Option<String>,
pub(crate) timestamp: UnixTimestamp,
pub(crate) transaction: TransactionData,
}

impl Transaction {
/// Hashes the transaction in sha256 digest
fn _to_hash(&self) -> Result<String, TransactionError> {
serde_json::to_string(&self)
.map_err(TransactionError::UnableToSerializeTransaction)
.map(digest)
}

/// Encodes the transaction in hex format
pub fn to_hex(&self) -> Result<String, TransactionError> {
serde_json::to_string(&self)
.map_err(TransactionError::UnableToDeserializeTransaction)
.map(hex::encode)
}

pub fn build<T: Transactable + 'static>(
keypair: Keypair,
payload: T,
) -> Result<Self, TransactionError> {
payload.sign(&keypair)?;

Ok(Self {
signature: None,
timestamp: Utc::now().timestamp(),
transaction: TransactionData {
transaction_id: Uuid::new_v4().to_string(),
payload: Box::new(payload),
},
})
}
}

/// Transaction data. Ideally contains payload that's `Transactable`
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct TransactionData {
transaction_id: String,
payload: Box<dyn Transactable>,
}

#[typetag::serde(tag = "type")]
pub trait Transactable: Debug + Send + Sync + DynClone + Display {
// TODO: Implement the _submit method to submit the transaction to the network.
fn _submit(&self) -> Result<(), TransactionError>;
fn sign(&self, keypair: &Keypair) -> Result<(), TransactionError>;
}

dyn_clone::clone_trait_object!(Transactable);

#[derive(thiserror::Error, Debug)]
pub enum TransactionError {
#[error("Unable to serialize transaction: {0}")]
UnableToSerializeTransaction(serde_json::Error),
#[error("Unable to deserialize transaction: {0}")]
UnableToDeserializeTransaction(serde_json::Error),
#[error("Unable to sign transaction: {0}")]
SigningError(SigningError),
}
10 changes: 5 additions & 5 deletions src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,25 +10,25 @@ pub struct Args {
#[arg(short, long, default_value_t = Role::Sender)]
pub role: Role,

/// Peer's address
/// Peer's MultiAddress
#[arg(short)]
pub peer_address: Option<String>,
pub peer_mutli_address: Option<String>,

/// Bootstrap Nodes
#[arg(short)]
pub bootstrap: Option<String>,
pub bootstrap_peer_id: Option<String>,
}

#[derive(Clone, Debug, ValueEnum)]
pub enum Role {
Receiver,
BootstapNode,
Sender,
}

impl Display for Role {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match &self {
Role::Receiver => write!(f, "Receiver"),
Role::BootstapNode => write!(f, "Receiver"),
Role::Sender => write!(f, "Sender"),
}
}
Expand Down
39 changes: 30 additions & 9 deletions src/comms/message.rs
Original file line number Diff line number Diff line change
@@ -1,27 +1,48 @@
use std::fmt::Display;

use serde::Serialize;
use libp2p::identity::Keypair;
use serde::{Deserialize, Serialize};

#[derive(Debug, Serialize, PartialEq, Eq)]
use crate::block::{Transactable, TransactionError};

#[derive(Clone, Debug, Deserialize, Serialize)]
pub enum Message {
RememeberMe,
Comms(String),
Transaction(Box<dyn Transactable>),
}

#[typetag::serde]
impl Transactable for Message {
fn _submit(&self) -> Result<(), TransactionError> {
todo!()
}

fn sign(&self, keypair: &Keypair) -> Result<(), TransactionError> {
match self {
Message::Comms(chat) => keypair
.sign(chat.as_bytes())
.map_err(TransactionError::SigningError)
.map(|_| ()),
Message::Transaction(action) => keypair
.sign(action.as_ref().to_string().as_bytes())
.map_err(TransactionError::SigningError)
.map(|_| ()),
}
}
}

impl From<String> for Message {
fn from(s: String) -> Self {
match s.as_str() {
"RememeberMe" => Message::RememeberMe,
s => Message::Comms(s.to_owned()),
}
let s = s.as_str();
Message::Comms(s.to_owned())
}
}

impl Display for Message {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Message::RememeberMe => write!(f, "RememeberMe"),
Message::Comms(s) => write!(f, "{s}"),
Message::Comms(chat) => write!(f, "{chat}"),
Message::Transaction(action) => write!(f, "{action}"),
}
}
}
7 changes: 0 additions & 7 deletions src/comms/mod.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1 @@
use libp2p::{Multiaddr, PeerId};

pub mod message;

pub struct Peer {
_id: PeerId,
_addr: Multiaddr,
}
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
pub mod block;
pub mod cli;
pub mod comms;
pub mod network;
pub mod storage;
pub mod utils;

pub mod tracing {
use tracing_subscriber::{
Expand Down
3 changes: 2 additions & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,8 @@ async fn main() -> Result<(), Box<dyn Error>> {
event_runner(
swarm,
args.role,
args.peer_address,
args.peer_mutli_address,
args.bootstrap_peer_id,
Topic(topic.to_string()),
)
.await
Expand Down
Loading