如何使用 Rust 從頭構(gòu)建一個(gè)區(qū)塊鏈

如何使用 Rust 從頭構(gòu)建一個(gè)區(qū)塊鏈

英文原文鏈接 https://coinsbench.com/how-to-build-a-blockchain-from-scratch-in-rust-9cedb59f8897

2021年對(duì)加密貨幣、NFT和去中心化應(yīng)用程序(DAPPs)來(lái)說(shuō)是重要的一年,2022年將更重要。區(qū)塊鏈?zhǔn)撬羞@些技術(shù)背后的底層技術(shù)。

區(qū)塊鏈技術(shù)有潛力改變我們生活的幾乎每一個(gè)方面,包括金融行業(yè)蒸其、旅游和出行、基礎(chǔ)設(shè)施库快、醫(yī)療保健摸袁、公共部門、零售缺谴、農(nóng)業(yè)和采礦但惶、教育耳鸯、通信、娛樂等膀曾。

世界上每個(gè)我崇拜的聰明人都有一個(gè)原因县爬。他們明白這是第四次工業(yè)革命的驅(qū)動(dòng)力: 蒸汽機(jī)、電力添谊,然后是微芯片——第四次是區(qū)塊鏈和加密貨幣财喳。 —— 布洛克 皮爾斯(Brock Pierce)

什么是區(qū)塊鏈?

區(qū)塊鏈?zhǔn)强琰c(diǎn)對(duì)點(diǎn)網(wǎng)絡(luò)的去中心化交易賬本斩狱,您也可以將區(qū)塊鏈看作是不可變的去中心化數(shù)據(jù)庫(kù)耳高。一個(gè)區(qū)塊鏈可以從根本上分解為幾個(gè)組件,如節(jié)點(diǎn)所踊、交易泌枪、區(qū)塊、鏈和共識(shí)協(xié)議(工作證明秕岛、權(quán)益證明碌燕、歷史證明)。

如果你像我一樣继薛,喜歡通過(guò)實(shí)戰(zhàn)來(lái)學(xué)習(xí)修壕。那么本文通過(guò)使用Rust構(gòu)建一個(gè)區(qū)塊鏈,會(huì)讓你對(duì)區(qū)塊鏈如何工作的有個(gè)基本概念遏考。

聽起來(lái)還不錯(cuò)是吧慈鸠?那讓我們開始吧。

現(xiàn)在開始

讓我們從創(chuàng)建一個(gè)新的Rust項(xiàng)目開始:

cargo +nightly new blockchain

然后切換到你剛創(chuàng)建的目錄中:

cd blockchain

然后為構(gòu)建區(qū)塊鏈添加必要的依賴包:

[dependencies]
chrono = "0.4"
serde = { version = "1.0.106", features = ["derive"] }
serde_json = "1.0"
sha2 = "0.10.0"

下一步灌具,創(chuàng)建 models 目錄來(lái)保存你的區(qū)塊鏈的大部分邏輯青团。目錄中添加兩個(gè)文件 blockchain.rsblock.rs

兩個(gè)文件中引入下面的依賴包并保存他們:

// Blockchain.rs
use chrono::prelude::*;
// internal module
use super::block::Block;
// Block.rs
use super::blockchain::Blockchain;
use chrono::prelude::*;
use sha2::{Sha256, Digest};
use serde::{Deserialize, Serialize};

可能你已經(jīng)注意到在 blockchain.rs 文件中引入了 use super::block::Block;咖楣, 這里我們只是引入了 block.rs 文件中的結(jié)構(gòu)體壶冒,不用擔(dān)心后面我會(huì)解釋。

在引入必要的依賴包之后截歉,讓我們?cè)?blockchain.rs 文件中定義一個(gè) Blocks 類型:

type Blocks = Vec<Block>;

下一步,在 blockchain.rs 中創(chuàng)建 Blockchain 類型烟零,并添加一個(gè)空的實(shí)現(xiàn):

// Blockchain 代表區(qū)塊鏈的結(jié)構(gòu)體
#[derive(Debug)]
pub struct Blockchain {
    // 添加到鏈中的第一個(gè)區(qū)塊
    pub genesis_block: Block,
    // 存儲(chǔ)區(qū)塊
    pub chain: Blocks,
    // 驗(yàn)證一個(gè)區(qū)塊需要的最小工作量
    pub difficulty: usize,
}

impl Blockchain {}

下一步瘪松, 在 block.rs 文件中定義 Block 類型,并添加空的實(shí)現(xiàn):

// Block 代表區(qū)塊鏈中的區(qū)塊結(jié)構(gòu)體
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Block {
    // 保存的當(dāng)前區(qū)塊的索引
    pub index: u64,
    // 當(dāng)前區(qū)塊的創(chuàng)建時(shí)間
    pub timeStamp: u64,
    // 區(qū)塊的工作證明
    pub proof_of_work: u64,
    // 前一個(gè)區(qū)塊哈希
    pub previous_hash: String,
    // 當(dāng)前區(qū)塊哈希
    pub hash: String
}

impl Block {}

創(chuàng)建創(chuàng)世區(qū)塊

創(chuàng)世區(qū)塊是區(qū)塊鏈中創(chuàng)建的第一個(gè)區(qū)塊锨阿。接下來(lái)創(chuàng)建一個(gè)函數(shù)可以為我們的區(qū)塊鏈生成一個(gè)創(chuàng)世區(qū)塊宵睦,并返回一個(gè)新的 Blockchain 類型。

blockchain.rs 中添加我們的 Blockchain 實(shí)現(xiàn)墅诡,代碼如下:

imple Blockchain {
    pub fn new(difficulty: usize) -> Self {
        // 鏈中的第一個(gè)塊
        let mut genesis_block = Block {
            index: 0,
            timestamp: Utc::now().timestamp_millis() as u64,
            proof_of_work: u64::default(),
            previous_hash: String::default(),
            hash: String::default()
        };
        // 從創(chuàng)世鏈開始創(chuàng)建鏈
        let mut chain = Vec::new();
        chain.push(genesis_block.clone());
  
        // 創(chuàng)建一個(gè)區(qū)塊鏈實(shí)例
        let blockchain = Blockchain {
            genesis_block,
            chain,
            difficulty
        };
        blockchain
    }
}

上面的代碼主要實(shí)現(xiàn)了這些功能:

  • 創(chuàng)建我們的 genesis_block 實(shí)例
  • 將我們創(chuàng)建的 genesis_block 添加到 Blockchain 類型的鏈中
  • 返回一個(gè) Blockchain 類型的實(shí)例

在我們創(chuàng)建的 genesis_block 實(shí)例中壳嚎,注意到我們?cè)O(shè)置 previous_hash 的值為空字符串(String::default()),這是因?yàn)閯?chuàng)世區(qū)塊是區(qū)塊鏈中的第一個(gè)區(qū)塊所以不存在上一個(gè)區(qū)塊。

還要注意烟馅,我們將 genesis_block 的哈希值設(shè)為一個(gè)空字符串("")说庭,這是因?yàn)槲覀冞€沒有為我們的創(chuàng)世區(qū)塊計(jì)算哈希值。

為區(qū)塊生成哈希值

哈希是根據(jù)當(dāng)前區(qū)塊的信息加密生成的郑趁。

block.rs 文件中為我們的區(qū)塊實(shí)現(xiàn)添加 calculate_hash() 函數(shù):

// 計(jì)算區(qū)塊哈希
pub fn calculate_hash(&self) -> String {
    let mut block_data = self.clone();
    block_data.hash = String::default();
    let serialized_block_data = serde_json::to_string(&block_data).unwrap();

    // 計(jì)算生成 SHA-256 哈希值
    let mut hasher = Sha256::new();
    hasher.update(serialized_block_data);
    let result = hasher.finalize();
    format!("{:x}", result)
}

上面的代碼中刊驴,實(shí)現(xiàn)了如下功能:

  • 區(qū)塊數(shù)據(jù)轉(zhuǎn)為JSON格式
  • 使用 SHA256 加密算法計(jì)算區(qū)塊數(shù)據(jù)的哈希
  • 返回16進(jìn)制格式的哈希結(jié)果

創(chuàng)建一個(gè)新的區(qū)塊

很棒!我們已經(jīng)實(shí)現(xiàn)了創(chuàng)建創(chuàng)世區(qū)塊和計(jì)算區(qū)塊哈希的功能寡润。

現(xiàn)在讓我們?cè)?blockchain.rs 文件中給 Blockchain 類型的實(shí)現(xiàn)添加創(chuàng)建新區(qū)塊的功能:

pub fn add_block(&mut self, nonce: String) {
    let new_block = Block::new(
        self.chain.len() as u64,
        nonce,
        self.chain[&self.chain.len() - 1].previous_hash.clone()
    );
    new_block.mine(self.clone());
    self.chain.push(new_block.clone());
    println!("New block added to chain -> {:?}", new_block);
}

這里我們做了如下操作:

  • 添加了 add_block 函數(shù)捆憎,形參是 &mut self(Blockchain 類型的實(shí)例)
  • 創(chuàng)建 Block 類型的實(shí)例
  • 使用 Block 類型的挖礦函數(shù)挖崛出一個(gè)區(qū)塊哈希
  • 將新區(qū)塊添加到區(qū)塊鏈中

接下來(lái)在 block.rs 文件中給 Block 類型實(shí)現(xiàn)添加如下代碼:

// 創(chuàng)建一個(gè)新區(qū)塊,會(huì)自動(dòng)計(jì)算并設(shè)置哈希
pub fn new(
    index: u64,
    previous_hash: String,
) -> Self {
    // 當(dāng)前要?jiǎng)?chuàng)建的區(qū)塊
    let mut block = Block {
        index: 0,
        timestamp: Utc::now().timestamp_millis() as u64,
        proof_of_work: u64::default(),
        previous_hash: String::default(),
        hash: String::default(),
    };

    block
}

這里做了如下操作:

  • 添加 new() 函數(shù)接收兩個(gè)參數(shù) index 和 previous_hash
  • 創(chuàng)建 Block 類型的實(shí)例
  • 為我們的區(qū)塊生成區(qū)塊哈希
  • 最后返回 Block 類型的實(shí)例

挖崛新區(qū)塊

我們已經(jīng)成功實(shí)現(xiàn)了創(chuàng)建一個(gè)新區(qū)塊梭纹。

讓我們繼續(xù)添加功能來(lái)挖崛新區(qū)塊躲惰。挖掘新區(qū)塊的過(guò)程包括生成一個(gè)以指定個(gè)數(shù)的0開頭的SHA256哈希,這將是挖掘新區(qū)塊時(shí)礦工必須解決的挖掘難度变抽。

接下來(lái)在 Block 類型的實(shí)現(xiàn)中添加一個(gè)新函數(shù)

// 挖崛區(qū)塊哈希
pub fn mine(&mut self, blockchain: Blockchain) {
    loop {
        if !self.hash.starts_with(&"0".repeat(blockchain.difficulty)) {
            self.proof_of_work += 1;
            self.hash = self.generate_block_hash();
        } else {
            break;
        }
    }
}

干得漂亮础拨,目前為止我們已經(jīng)實(shí)現(xiàn)了我們的區(qū)塊鏈,現(xiàn)在讓我們測(cè)試它瞬沦。

讓我們?cè)?models 目錄中新增 mod.rs 文件太伊,并寫入如下代碼:

pub mod block;
pub mod blockchain;

這里主要是將我們?cè)缧r(shí)候添加的 blockchain.rsblock.rs 文件在 main.rs 文件中可以公開訪問(wèn)。

現(xiàn)在給 main.rs 文件添加如下代碼:

mod models;

fn main() {
    let difficulty = 1;
    let mut blockchain = models::blockchain::Blockchain::new(difficulty);
    models::blockchain::Blockchain::add_block(&mut blockchain);
}

小結(jié)一下

通過(guò)本文你已經(jīng)了解了如何使用 rust 從頭創(chuàng)建一個(gè)簡(jiǎn)單的區(qū)塊鏈逛钻。

我希望您喜歡閱讀本文僚焦,您可以在這里獲得這個(gè)Rust區(qū)塊鏈的完整源代碼。

任何問(wèn)題歡迎留言評(píng)論曙痘。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末芳悲,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子边坤,更是在濱河造成了極大的恐慌名扛,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,718評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件茧痒,死亡現(xiàn)場(chǎng)離奇詭異肮韧,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)旺订,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,683評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門弄企,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人区拳,你說(shuō)我怎么就攤上這事拘领。” “怎么了樱调?”我有些...
    開封第一講書人閱讀 158,207評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵约素,是天一觀的道長(zhǎng)届良。 經(jīng)常有香客問(wèn)我,道長(zhǎng)圣猎,這世上最難降的妖魔是什么士葫? 我笑而不...
    開封第一講書人閱讀 56,755評(píng)論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮样漆,結(jié)果婚禮上为障,老公的妹妹穿的比我還像新娘。我一直安慰自己放祟,他們只是感情好鳍怨,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,862評(píng)論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著跪妥,像睡著了一般鞋喇。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上眉撵,一...
    開封第一講書人閱讀 50,050評(píng)論 1 291
  • 那天侦香,我揣著相機(jī)與錄音,去河邊找鬼纽疟。 笑死罐韩,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的污朽。 我是一名探鬼主播散吵,決...
    沈念sama閱讀 39,136評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼蟆肆!你這毒婦竟也來(lái)了矾睦?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,882評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤炎功,失蹤者是張志新(化名)和其女友劉穎枚冗,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蛇损,經(jīng)...
    沈念sama閱讀 44,330評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡赁温,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,651評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了淤齐。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片束世。...
    茶點(diǎn)故事閱讀 38,789評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡沉帮,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情偎行,我是刑警寧澤,帶...
    沈念sama閱讀 34,477評(píng)論 4 333
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響矗漾,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜虑稼,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,135評(píng)論 3 317
  • 文/蒙蒙 一啦桌、第九天 我趴在偏房一處隱蔽的房頂上張望且改。 院中可真熱鬧,春花似錦慨蓝、人聲如沸弧满。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,864評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)吉执。三九已至戳玫,卻和暖如春蜡秽,著一層夾襖步出監(jiān)牢的瞬間试浙,已是汗流浹背寞蚌。 一陣腳步聲響...
    開封第一講書人閱讀 32,099評(píng)論 1 267
  • 我被黑心中介騙來(lái)泰國(guó)打工田巴, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人挟秤。 一個(gè)月前我還...
    沈念sama閱讀 46,598評(píng)論 2 362
  • 正文 我出身青樓壹哺,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親艘刚。 傳聞我的和親對(duì)象是個(gè)殘疾皇子管宵,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,697評(píng)論 2 351

推薦閱讀更多精彩內(nèi)容