178 lines
6.5 KiB
Rust
178 lines
6.5 KiB
Rust
mod blockchain;
|
|
mod cli;
|
|
mod wallet;
|
|
mod network;
|
|
mod api;
|
|
|
|
use blockchain::{Blockchain, Transaction};
|
|
use clap::Parser;
|
|
use cli::{Cli, Commands};
|
|
use std::fs;
|
|
use wallet::Wallet;
|
|
|
|
const BLOCKCHAIN_FILE: &str = "blockchain.json";
|
|
|
|
#[tokio::main]
|
|
async fn main() {
|
|
let cli = Cli::parse();
|
|
|
|
let mut blockchain = load_blockchain();
|
|
|
|
match cli.command {
|
|
Commands::Wallet { atproto_did, export } => {
|
|
let wallet = Wallet::new(atproto_did);
|
|
println!("New wallet created!");
|
|
println!("Address: {}", wallet.address);
|
|
if let Some(private_key) = wallet.get_private_key_hex() {
|
|
println!("Private key: {}", private_key);
|
|
println!("IMPORTANT: Save this private key securely!");
|
|
}
|
|
if let Some(ref did) = wallet.atproto_did {
|
|
println!("ATProto DID: {}", did);
|
|
}
|
|
|
|
if let Some(path) = export {
|
|
match wallet.export_to_file(&path) {
|
|
Ok(()) => println!("Wallet exported to: {}", path),
|
|
Err(e) => println!("Failed to export wallet: {}", e),
|
|
}
|
|
}
|
|
}
|
|
|
|
Commands::Import { path } => {
|
|
match Wallet::import_from_file(&path) {
|
|
Ok(wallet) => {
|
|
println!("Wallet imported successfully!");
|
|
println!("Address: {}", wallet.address);
|
|
if let Some(ref did) = wallet.atproto_did {
|
|
println!("ATProto DID: {}", did);
|
|
}
|
|
}
|
|
Err(e) => println!("Failed to import wallet: {}", e),
|
|
}
|
|
}
|
|
|
|
Commands::Balance { address } => {
|
|
let balance = blockchain.get_balance(&address);
|
|
println!("Balance for {}: {} AIC", address, balance);
|
|
}
|
|
|
|
Commands::Send { to, amount, private_key, atproto_did } => {
|
|
match Wallet::from_private_key(&private_key, atproto_did) {
|
|
Ok(wallet) => {
|
|
let mut transaction = Transaction::new(
|
|
wallet.address.clone(),
|
|
to.clone(),
|
|
amount,
|
|
wallet.atproto_did.clone(),
|
|
);
|
|
|
|
if let Some(ref signing_key) = wallet.private_key {
|
|
transaction.sign(signing_key);
|
|
|
|
match blockchain.add_transaction(transaction) {
|
|
Ok(()) => {
|
|
save_blockchain(&blockchain);
|
|
println!("Transaction added to pending transactions");
|
|
println!("From: {}", wallet.address);
|
|
println!("To: {}", to);
|
|
println!("Amount: {} AIC", amount);
|
|
}
|
|
Err(e) => println!("Error: {}", e),
|
|
}
|
|
}
|
|
}
|
|
Err(e) => println!("Error loading wallet: {}", e),
|
|
}
|
|
}
|
|
|
|
Commands::Mine { address } => {
|
|
if blockchain.pending_transactions.is_empty() {
|
|
println!("No pending transactions to mine");
|
|
} else {
|
|
println!("Mining block...");
|
|
let pending_count = blockchain.pending_transactions.len();
|
|
blockchain.mine_pending_transactions(address.clone());
|
|
save_blockchain(&blockchain);
|
|
println!("Block mined successfully!");
|
|
println!("Transactions included: {}", pending_count);
|
|
println!("Mining reward sent to: {}", address);
|
|
}
|
|
}
|
|
|
|
Commands::Info => {
|
|
println!("Blockchain Info:");
|
|
println!("Total blocks: {}", blockchain.chain.len());
|
|
println!("Difficulty: {}", blockchain.difficulty);
|
|
println!("Mining reward: {} AIC", blockchain.mining_reward);
|
|
println!("Pending transactions: {}", blockchain.pending_transactions.len());
|
|
|
|
if let Some(latest) = blockchain.chain.last() {
|
|
println!("\nLatest block:");
|
|
println!(" Index: {}", latest.index);
|
|
println!(" Hash: {}", latest.hash);
|
|
println!(" Timestamp: {}", latest.timestamp);
|
|
println!(" Transactions: {}", latest.transactions.len());
|
|
}
|
|
}
|
|
|
|
Commands::Validate => {
|
|
if blockchain.is_valid() {
|
|
println!("Blockchain is valid ✓");
|
|
} else {
|
|
println!("Blockchain is invalid ✗");
|
|
}
|
|
}
|
|
|
|
Commands::Server { port } => {
|
|
println!("Starting API server on port {}", port);
|
|
api::run_api_server(blockchain, port).await;
|
|
}
|
|
|
|
Commands::Node { port } => {
|
|
println!("Starting P2P node on port {}", port);
|
|
let (tx, mut rx) = tokio::sync::mpsc::channel(100);
|
|
|
|
let p2p_network = network::P2PNetwork::new(tx, port).await
|
|
.expect("Failed to create P2P network");
|
|
|
|
tokio::spawn(async move {
|
|
p2p_network.run().await;
|
|
});
|
|
|
|
// Handle incoming messages
|
|
while let Some(msg) = rx.recv().await {
|
|
match msg {
|
|
network::MessageType::NewTransaction(tx) => {
|
|
println!("Received new transaction");
|
|
if let Err(e) = blockchain.add_transaction(tx) {
|
|
eprintln!("Failed to add transaction: {}", e);
|
|
}
|
|
save_blockchain(&blockchain);
|
|
}
|
|
network::MessageType::NewBlock(block) => {
|
|
println!("Received new block");
|
|
// TODO: Validate and add block
|
|
}
|
|
_ => {}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
fn load_blockchain() -> Blockchain {
|
|
if let Ok(data) = fs::read_to_string(BLOCKCHAIN_FILE) {
|
|
if let Ok(blockchain) = serde_json::from_str(&data) {
|
|
return blockchain;
|
|
}
|
|
}
|
|
Blockchain::new()
|
|
}
|
|
|
|
fn save_blockchain(blockchain: &Blockchain) {
|
|
if let Ok(data) = serde_json::to_string_pretty(blockchain) {
|
|
let _ = fs::write(BLOCKCHAIN_FILE, data);
|
|
}
|
|
}
|