use ed25519_dalek::{Signer, SigningKey, VerifyingKey, Signature, Verifier};
use serde::{Serialize, Deserialize};
use std::collections::HashMap;
use std::sync::{Arc, Mutex};
use crate::error::DeonError;
use log::{info, warn};
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Transaction {
pub sender: [u8; 32], pub receiver: [u8; 32], pub amount: u64,
pub nonce: u64, pub signature: Option<Vec<u8>>,
}
impl Transaction {
pub fn new(sender: [u8; 32], receiver: [u8; 32], amount: u64, nonce: u64) -> Self {
Self {
sender,
receiver,
amount,
nonce,
signature: None,
}
}
pub fn sign(&mut self, key_pair: &SigningKey) {
let msg = self.get_signable_bytes();
let signature: Signature = key_pair.sign(&msg);
self.signature = Some(signature.to_bytes().to_vec());
}
pub fn verify(&self) -> Result<(), DeonError> {
let sig_bytes = self.signature.as_ref().ok_or(DeonError::AuthFailed)?;
if sig_bytes.len() != 64 {
return Err(DeonError::AuthFailed);
}
let mut sig_arr = [0u8; 64];
sig_arr.copy_from_slice(sig_bytes);
let signature = Signature::from_bytes(&sig_arr);
let public_key = VerifyingKey::from_bytes(&self.sender)
.map_err(|_| DeonError::Crypto)?;
let msg = self.get_signable_bytes();
public_key.verify(&msg, &signature)
.map_err(|_| DeonError::AuthFailed)
}
fn get_signable_bytes(&self) -> Vec<u8> {
let mut buf = Vec::new();
buf.extend_from_slice(&self.sender);
buf.extend_from_slice(&self.receiver);
buf.extend_from_slice(&self.amount.to_be_bytes());
buf.extend_from_slice(&self.nonce.to_be_bytes());
buf
}
}
pub struct Ledger {
balances: Arc<Mutex<HashMap<[u8; 32], u64>>>,
nonces: Arc<Mutex<HashMap<[u8; 32], u64>>>,
}
impl Ledger {
pub fn new() -> Self {
Self {
balances: Arc::new(Mutex::new(HashMap::new())),
nonces: Arc::new(Mutex::new(HashMap::new())),
}
}
pub fn process_transaction(&self, tx: &Transaction) -> Result<(), DeonError> {
tx.verify()?;
let mut balances = self.balances.lock().unwrap();
let mut nonces = self.nonces.lock().unwrap();
let current_nonce = nonces.entry(tx.sender).or_insert(0);
if tx.nonce <= *current_nonce {
warn!("Replay attack detected! Tx Nonce: {}, Current: {}", tx.nonce, *current_nonce);
return Err(DeonError::AuthFailed); }
let sender_balance = balances.entry(tx.sender).or_insert(0);
if *sender_balance < tx.amount {
warn!("Insufficient funds: Has {}, Needs {}", *sender_balance, tx.amount);
return Err(DeonError::ProtocolViolation); }
*sender_balance -= tx.amount;
let receiver_balance = balances.entry(tx.receiver).or_insert(0);
*receiver_balance += tx.amount;
*current_nonce = tx.nonce;
info!("Transaction processed: {} transferred", tx.amount);
Ok(())
}
pub fn debug_mint(&self, account: [u8; 32], amount: u64) {
let mut balances = self.balances.lock().unwrap();
*balances.entry(account).or_insert(0) += amount;
}
pub fn get_balance(&self, account: &[u8; 32]) -> u64 {
let balances = self.balances.lock().unwrap();
*balances.get(account).unwrap_or(&0)
}
}
#[async_trait::async_trait]
pub trait SettlementLayer: Send + Sync {
async fn settle_batch(&self, transactions: Vec<Transaction>) -> Result<[u8; 32], DeonError>;
async fn is_finalized(&self, tx_hash: &[u8]) -> Result<bool, DeonError>;
}
pub struct MockBlockchain;
#[async_trait::async_trait]
impl SettlementLayer for MockBlockchain {
async fn settle_batch(&self, transactions: Vec<Transaction>) -> Result<[u8; 32], DeonError> {
info!("Settling {} transactions to MockBlockchain...", transactions.len());
Ok([0xEE; 32]) }
async fn is_finalized(&self, _tx_hash: &[u8]) -> Result<bool, DeonError> {
Ok(true)
}
}