Загрузка...

Building RubelRU: A Rust-Based Cryptocurrency Experiment with RSA Wallets and P2P Architect

Thread in Rust created by Нурмагомедов Aug 1, 2025. 473 views

  1. Нурмагомедов
    Что это?

    Я написал работающий блокчейн с системой RSA-кошельков, P2P-клиентом и сервером, используя чистый Rust. Цель развить это в настоящую криптовалюту, которую можно будет использовать и продавать.

    rubelru/
    ├── Cargo.toml
    ├── Cargo.lock
    ├── src/
    │ ├──
    │ ├──
    │ ├──
    │ ├── wallet_data/ # Сохранённые RSA-ключи
    │ ├── bin/
    │ │ ├── # Запуск серверной части P2P
    │ │ └── # Запуск клиентской части P2P
    │ └── P2P/
    │ ├──
    │ ├──
    │ ├──
    │ └──
    └── target/
    Что уже работает?

    Генерация RSA-кошельков, сохранение/загрузка
    Простая структура блока
    P2P-соединения (TCP-клиент и сервер)
    Сериализация/десериализация сообщений
    Возможность отправлять сообщения между клиентом и сервером

    v0.1 Генерация кошельков, P2P и простая структура блока
    v0.2 Базовая транзакционная модель, сигнатуры
    v0.3 Проверка и синхронизация блокчейна между узлами
    v0.4 GUI-кошелёк или CLI-меню
    v1.0 Публичный testnet, децентрализованная сеть
    Кого я ищу?
    Rust-разработчиков

    Разработчиков криптографии
    Сетевых инженеров (P2P, NAT traversal, WebSocket)
    UI/UX-дизайнеров для GUI или explorer
    Людей, кто просто хочет поучаствовать или протестировать

    Любая помощь, предложения, критика приветствуется.

    Code
    mod p2p;

    mod wallet;

    use std::thread;

    use std::time::{Duration, SystemTime, UNIX_EPOCH};

    use md5;

    use p2p::{client, server};

    use wallet::Wallet;

    #[derive(Debug, Clone)]

    struct Block {

    index: u64,

    timestamp: u128,

    previous_hash: String,

    hash: String,

    data: String,

    }

    /// Вычисление хеша для блока

    fn calculate_hash(index: u64, timestamp: u128, previous_hash: &str, data: &str) -> String {

    let input = format!("{}{}{}{}", index, timestamp, previous_hash, data);

    format!("{:x}", md5::compute(input))

    }

    /// Проверка валидности нового блока относительно предыдущего

    fn is_valid_new_block(new_block: &Block, previous_block: &Block) -> bool {

    new_block.index == previous_block.index + 1

    && new_block.previous_hash == previous_block.hash

    && calculate_hash(

    new_block.index,

    new_block.timestamp,

    &new_block.previous_hash,

    &new_block.data,

    ) == new_block.hash

    }

    /// Проверка всей цепочки блоков на валидность

    fn is_chain_valid(chain: &Vec<Block>) -> bool {

    (1..chain.len()).all(|i| is_valid_new_block(&chain[i], &chain[i - 1]))

    }

    /// Создание генезис-блока (первого блока)

    fn create_genesis_block() -> Block {

    let timestamp = now();

    let hash = calculate_hash(0, timestamp, "0", "Генезис-блок RubelRU");

    Block {

    index: 0,

    timestamp,

    previous_hash: "0".to_string(),

    hash,

    data: "Генезис-блок RubelRU".to_string(),

    }

    }

    /// Создание следующего блока на основе предыдущего

    fn create_next_block(previous_block: &Block, data: &str) -> Block {

    let index = previous_block.index + 1;

    let timestamp = now();

    let hash = calculate_hash(index, timestamp, &previous_block.hash, data);

    Block {

    index,

    timestamp,

    previous_hash: previous_block.hash.clone(),

    hash,

    data: data.to_string(),

    }

    }

    /// Получение текущего времени в миллисекундах

    fn now() -> u128 {

    SystemTime::now()

    .duration_since(UNIX_EPOCH)

    .expect("Проблемы с системным временем")

    .as_millis()

    }

    /// Главная функция программы RubelRU

    fn main() {

    println!(" Запуск блокчейна RubelRU...\n");

    // Кошелёк

    let wallet_folder = "wallet_data";

    let wallet = match Wallet::load_wallet(wallet_folder) {

    Ok(w) => {

    println!(" Кошелёк успешно загружен из файла.");

    w

    }

    Err(_) => {

    println!(" Создание нового кошелька...");

    let w = Wallet::new();

    w.save_wallet(wallet_folder).expect("Не удалось сохранить кошелёк.");

    println!(" Публичный ключ (base64): {}", w.get_public_key_base64());

    println!(" Приватный ключ (base64): {}", w.get_private_key_base64());

    w

    }

    };

    println!(" Кошелёк готов к использованию.");

    println!(" Публичный ключ владельца: {}", wallet.get_public_key_base64());

    // Блокчейн

    let mut blockchain = vec![create_genesis_block()];

    println!("{:#?}", blockchain[0]);

    for i in 1..=3 {

    let data = format!("Блок №{} RubelRU", i);

    let new_block = create_next_block(&blockchain[i - 1], &data);

    println!("{:#?}", new_block);

    blockchain.push(new_block);

    }

    if is_chain_valid(&blockchain) {

    println!(" Цепочка блокчейна RubelRU валидна.");

    } else {

    println!(" Цепочка блокчейна RubelRU невалидна!");

    }

    // Запуск сервера в отдельном потоке

    thread::spawn(|| {

    server::run_server("127.0.0.1:7878");

    });

    // Небольшая задержка, чтобы сервер успел стартовать

    thread::sleep(Duration::from_millis(500));

    // Отправка сообщения ноде с клиента

    client::run_client("127.0.0.1:7878");

    // Держим программу живой (бесконечный цикл сервера)

    loop {

    thread::sleep(Duration::from_secs(10));

    }

    }

    Code
    use rand::rngs::OsRng;

    use rsa::{RsaPrivateKey, RsaPublicKey};

    use rsa::pkcs8::{EncodePrivateKey, EncodePublicKey, DecodePrivateKey, DecodePublicKey};

    use base64::{engine::general_purpose, Engine as _};

    use std::fs::{self, File};

    use std::io::Read;

    pub struct Wallet {

    pub private_key: RsaPrivateKey,

    pub public_key: RsaPublicKey,

    }

    impl Wallet {

    pub fn new() -> Self {

    let mut rng = OsRng;

    let bits = 2048;

    let private_key = RsaPrivateKey::new(&mut rng, bits).expect("Не удалось создать приватный ключ");

    let public_key = RsaPublicKey::from(&private_key);

    Wallet { private_key, public_key }

    }

    pub fn get_public_key_base64(&self) -> String {

    let pem = self.public_key.to_public_key_pem(rsa::pkcs8::LineEnding::LF).unwrap();

    general_purpose::STANDARD.encode(pem)

    }

    pub fn get_private_key_base64(&self) -> String {

    let pem = self.private_key.to_pkcs8_pem(rsa::pkcs8::LineEnding::LF).unwrap();

    general_purpose::STANDARD.encode(pem)

    }

    pub fn save_wallet(&self, folder_path: &str) -> std::io::Result<()> {

    fs::create_dir_all(folder_path)?;

    let priv_pem = self.private_key.to_pkcs8_pem(rsa::pkcs8::LineEnding::LF).unwrap();

    let pub_pem = self.public_key.to_public_key_pem(rsa::pkcs8::LineEnding::LF).unwrap();

    let priv_path = format!("{}/private_key.pem", folder_path);

    let pub_path = format!("{}/public_key.pem", folder_path);

    fs::write(priv_path, priv_pem)?;

    fs::write(pub_path, pub_pem)?;

    Ok(())

    }

    pub fn load_wallet(folder_path: &str) -> std::io::Result<Wallet> {

    let priv_path = format!("{}/private_key.pem", folder_path);

    let pub_path = format!("{}/public_key.pem", folder_path);

    let mut priv_pem = String::new();

    let mut pub_pem = String::new();

    File::open(priv_path)?.read_to_string(&mut priv_pem)?;

    File::open(pub_path)?.read_to_string(&mut pub_pem)?;

    let private_key = RsaPrivateKey::from_pkcs8_pem(&priv_pem).unwrap();

    let public_key = RsaPublicKey::from_public_key_pem(&pub_pem).unwrap();

    Ok(Wallet { private_key, public_key })

    }

    }

    Code
    use serde::{Serialize, Deserialize};

    #[derive(Serialize, Deserialize, Debug)]

    pub enum P2PMessage {

    Text(String),

    Ping,

    Pong,

    RequestChain,

    ResponseChain(Vec<String>), // Позже заменить на Vec<Block>

    NewBlock(String), // Позже заменить на Block

    }

    Code
    use std::net::TcpStream;

    use std::io::Write;

    use serde_json;

    use crate::p2p::message::P2PMessage;

    /// Отправка сообщения другому узлу

    pub fn send_to_node(addr: &str, message: &str) {

    if let Ok(mut stream) = TcpStream::connect(addr) {

    let msg = P2PMessage::Text(message.to_string());

    let json = serde_json::to_string(&msg).unwrap();

    stream.write_all(json.as_bytes()).unwrap();

    println!(" Сообщение отправлено на {}", addr);

    } else {

    eprintln!(" Не удалось подключиться к {}", addr);

    }

    }

    /// Основная функция клиента для начальной отправки сообщения

    pub fn run_client(addr: &str) {

    send_to_node(addr, "Привет, узел RubelRU!");

    }

    Code
    use std::net::{TcpListener, TcpStream};

    use std::io::Read;

    use serde_json;

    use crate::p2p::message::P2PMessage;

    use std::thread;

    fn handle_connection(mut stream: TcpStream) {

    let mut buffer = [0; 1024];

    if let Ok(size) = stream.read(&mut buffer) {

    if let Ok(msg_str) = std::str::from_utf8(&buffer[..size]) {

    if let Ok(msg) = serde_json::from_str::<P2PMessage>(msg_str) {

    match msg {

    P2PMessage::Ping => {

    println!(" Получен Ping от {}", stream.peer_addr().unwrap());

    }

    P2PMessage::RequestChain => {

    println!(" Запрос цепочки от {}", stream.peer_addr().unwrap());

    }

    other => {

    println!(" Прочие сообщения: {:?}", other);

    }

    }

    }

    }

    }

    }

    /// Основная функция запуска P2P сервера

    pub fn run_server(address: &str) {

    let listener = TcpListener::bind(address).expect(" Не удалось привязаться к адресу");

    println!(" P2P сервер RubelRU запущен на {}", address);

    for stream in listener.incoming() {

    match stream {

    Ok(stream) => {

    println!(" Входящее соединение от: {}", stream.peer_addr().unwrap());

    thread::spawn(move || {

    handle_connection(stream);

    });

    }

    Err(e) => {

    eprintln!(" Ошибка при получении соединения: {}", e);

    }

    }

    }

    }

    Code
    use rubelru::p2p::server;

    fn main() {

    server::run_server("127.0.0.1:7878");

    }

    Code
    use rubelru::p2p::client;

    fn main() {

    client::run_client("127.0.0.1:7878");

    }

    Контакт
    Пишите в личку или здесь в теме.


    > Этот проект начался как эксперимент, но я действительно хочу сделать из него настоящую криптовалюту — лёгкую, понятную и открытую для всех.
     
  2. K1p1k
    K1p1k Dec 27, 2025 46 Jul 1, 2022
    Прикольно, но в России крипта не легализирована
     
    1. oiiaioiiao
      avatarK1p1k, но и не нелегальна))
Loading...