那曲檬骨新材料有限公司

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

如何使用Rust從零開發區塊鏈

jf_wN0SrCdH ? 來源:Rust語言中文社區 ? 2024-01-22 13:58 ? 次閱讀

在這一系列的文章中,我將向你展示如何使用 Rust 語言從零開始編寫一個區塊鏈。這些文章并不是為了想學習智能合約編程的人,而是為了理解區塊鏈的底層知識 - 區塊、鏈、鍵值數據庫、網絡、共識機制等的人而準備的。如果你想學習區塊鏈的底層知識,這就是你要找的地方。

我已經在區塊鏈領域工作了幾年,從一開始就計劃寫這一系列的文章來學習區塊鏈。但直到現在,我才有足夠的時間來做這件事。我主要熟悉 Substrate 框架,從其文檔站點學到了很多知識,從核心概念到如何使用它來開發應用。所以我建議你如果有時間的話,去閱讀那些文檔,他們官方還有關于它的課程,你可以在這里找到信息:Polkadot Academy。國內的話,OneBlock+社區在做免費的Substrate培訓課程,你可以在這里找到最新一期(2023.12)報名鏈接。

Substrate 是一個功能齊全的區塊鏈框架,它非常強大。但它也很復雜,難以深入理解,所以我開設這個系列,幫助那些想要深入了解區塊鏈內部的開發者

Rust 無疑是編寫區塊鏈的首選,它也是我最喜歡的編程語言。如果你還沒有接觸過它,你應該去試試。

好的,讓我們開始吧。

什么是區塊?它是區塊鏈的基本單位。在我們的例子中,它只是一個 Rust 結構體。我們可以這樣定義它:

structBlock{
header:BlockHeader,
body:BlockBody,
}

區塊由兩部分組成:BlockHeader 和 BlockBody。每種類型的定義如下:

BlockHeader

structBlockHeader{
hash:String,
height:u64,
prev_hash:String,
timestamp:u64,
}

BlockBody

typeBlockBody=Vec;

區塊的Body部分是一個普通的字符串向量,而頭部看起來更有趣。在所有的字段中,prev_hash 是最有趣的,它存儲了前一個區塊的哈希字段值,我們將在這篇文章后面的鏈部分討論它。

height 字段表示這個區塊的序列號,新的區塊被添加到區塊鏈中時,高度會遞增。

timestamp 字段表示創建這個區塊時的 Unix 時間戳。所以它與你正在使用的本地機器有關。

而 hash 字段存儲了這個區塊的哈希值。我們會問:如何計算這個區塊的哈希值?因為哈希字段是這個結構體的一部分,所以簡單地序列化這個結構體是行不通的。我們需要在做計算時從其他字段中排除這個字段。所以算法看起來像這樣:

fncalc_block_hash(height:u64,prev_hash:&str,timestamp:u64,body:&Vec)->String{

letconcated_str=vec![
height.to_string(),
prev_hash.to_string(),
timestamp.to_string(),
body.concat(),
]
.concat();

letmuthasher=Sha256::new();
hasher.update(concated_str.as_bytes());
hex::encode(hasher.finalize().as_slice())
}

我們不會教授如何編寫 Rust 代碼的細節,相反,我們主要會描述如何設計它的思路流程。

在這里,我們按照 height, prev_hash, timestamp, body 的順序連接這個區塊的元素。由于 body 是一個向量,我們應該首先連接它。一旦字符串連接完成,我們使用 Sha256 對其進行哈希計算。這一步創建了一個 32 字節的 u8 數組:[u8; 32]。然后我們使用 hex 將其編碼為長度為 64 的字符串,這代表了這個區塊的哈希。

你會注意到,我們將 prev_hash 值作為這個區塊的哈希的來源之一。這非常重要,你可能會想知道我們為什么要這么做。

我們可以按照以下方式測試這個算法:

#[test]
fntest_block_hash(){
letblock1=Block::new(10,"aaabbbcccdddeeefff".to_string(),vec![]);
letblock2=Block::new(10,"aaabbbcccdddeeefff".to_string(),vec![]);
assert_eq!(block1.header.height,block2.header.height);
assert_eq!(block1.header.prev_hash,block2.header.prev_hash);
//XXX:havelittleprobabilitytofail
assert_eq!(block1.header.timestamp,block2.header.timestamp);
//XXX:havelittleprobabilitytofail
assert_eq!(block1.header.hash,block2.header.hash);

assert_eq!(block1.body,block2.body);
}

什么是鏈?你可以想象一條項鏈或者一條鐵鏈。在我們的例子中,鏈是一個抽象的概念,每個區塊都存儲了前一個區塊的哈希字段值。就這樣,你看,沒有復雜的地方。

在這個鏈中,每個區塊只關心前一個區塊,而不關心其他區塊。所以它是一個相對簡單的結構。

但我們即將遇到一個問題:第一個區塊怎么辦?它之前沒有區塊。

是的,對于這個邊緣情況,我們需要為 hash 字段設置一個預定義的值。由于這個特殊情況,區塊鏈的第一個區塊通常被稱為 創世(Genesis) 區塊。

這就是整個區塊鏈的樣子:

b156688c-b8c3-11ee-8b88-92fbcf53809c.png

隨著時間的推移,這個結構將無限擴展(或增長)。

區塊鏈管理器

我們需要一個管理器來管理區塊鏈。現在它非常簡單,只包含一個區塊的向量。

#[derive(Debug)]
structBlockChain{
blocks:Vec,
}

并在其上實現一些方法:

implBlockChain{
fnnew()->Self{
BlockChain{blocks:vec![]}
}

fngenesis()->Block{
lettxs=vec!["Thebigbrotheriswatchingyou.".to_string()];
Block::new(0,"1984,GeorgeOrwell".to_string(),txs)
}

fnadd_block(&mutself,block:Block){
self.blocks.push(block);
}
}

現在我們可以使用這個管理器來構建一個區塊鏈:

fnmain(){

letmutblockchain=BlockChain::new();
letgenesis_block=BlockChain::genesis();
letprev_hash=genesis_block.header.hash.clone();
blockchain.add_block(genesis_block);

letb1=Block::new(1,prev_hash,vec![]);
letprev_hash=b1.header.hash.clone();
blockchain.add_block(b1);

letb2=Block::new(2,prev_hash,vec![]);
letprev_hash=b2.header.hash.clone();
blockchain.add_block(b2);

letb3=Block::new(3,prev_hash,vec![]);
letprev_hash=b3.header.hash.clone();
blockchain.add_block(b3);

letb4=Block::new(4,prev_hash,vec![]);
letprev_hash=b4.header.hash.clone();
blockchain.add_block(b4);

letb5=Block::new(5,prev_hash,vec![]);
//letprev_hash=b5.header.hash.clone();
blockchain.add_block(b5);

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

它將打印出來類似下面的東西:

mike@alberta:~/works/blockchainworks/vintage$cargorun
Compilingvintagev0.1.0(/home/mike/works/blockchainworks/vintage)
Finisheddev[unoptimized+debuginfo]target(s)in0.22s
Running`target/debug/vintage`
BlockChain{
blocks:[
Block{
header:BlockHeader{
hash:"96cf34aa91e070ddf95eb9e0e8616b24e2f326c80d5fa9746e8dd8f0bec730d6",
height:0,
prev_hash:"1984,GeorgeOrwell",
timestamp:1705649594,
},
body:[
"Thebigbrotheriswatchingyou.",
],
},
Block{
header:BlockHeader{
hash:"0dd52ac54a9d621c47688f7920cd9eaee18ffe0cca3c83e124b8f78cef8999e5",
height:1,
prev_hash:"96cf34aa91e070ddf95eb9e0e8616b24e2f326c80d5fa9746e8dd8f0bec730d6",
timestamp:1705649594,
},
body:[],
},
Block{
header:BlockHeader{
hash:"61e95ab151cfa41c2a74cb076c33511ddf71f45dab0571f5f2db89df7ebc64cf",
height:2,
prev_hash:"0dd52ac54a9d621c47688f7920cd9eaee18ffe0cca3c83e124b8f78cef8999e5",
timestamp:1705649594,
},
body:[],
},
Block{
header:BlockHeader{
hash:"dde009c56c1b02d41fec8271e5f990e9b33c84a2cf044de6fc33e96605f90458",
height:3,
prev_hash:"61e95ab151cfa41c2a74cb076c33511ddf71f45dab0571f5f2db89df7ebc64cf",
timestamp:1705649594,
},
body:[],
},
Block{
header:BlockHeader{
hash:"f8cd3ab5f6ccc864515635878498e2e26b63b4fbf4dbc60ea3649e859b4a7d27",
height:4,
prev_hash:"dde009c56c1b02d41fec8271e5f990e9b33c84a2cf044de6fc33e96605f90458",
timestamp:1705649594,
},
body:[],
},
Block{
header:BlockHeader{
hash:"4415f4993729459f5ff07c7c963890f1d9210d5241f5203b9179c8d3db6e9dac",
height:5,
prev_hash:"f8cd3ab5f6ccc864515635878498e2e26b63b4fbf4dbc60ea3649e859b4a7d27",
timestamp:1705649594,
},
body:[],
},
],
}

我們做到了,它已經是一個區塊鏈了。

如何持久化

到目前為止,我們只是將區塊鏈保存在計算機的內存中,所以如果我們現在關閉計算機,區塊鏈將一無所有。我們最好將整個鏈存儲在我們的計算機上。

一般來說,人們會使用鍵值數據庫(kv db)來存儲區塊鏈。為什么使用 kv db 而不是文件或 SQL db 呢?因為它簡單且高效。

在我們的例子中,我們將使用 redb 作為我們的存儲后端。根據其官方網站,Redb 是一個簡單、便攜、高性能、ACID、嵌入式鍵值存儲,完全用 Rust 編寫,并受到 lmdb 的啟發。

接下來,我們需要設計一個存儲模式。有以下幾點:

使用兩個表:blocks 表用于開發/生產模式,blocks_fortest 表用于測試模式;

每個區塊都作為 redb 中的一個鍵值元素存儲,其中鍵是區塊的哈希字段值,值是區塊的完全序列化字符串。

我們需要一個指針指向最后一個區塊。'指向'實際上意味著持有區塊的哈希值。我們可以使用這個指針從數據庫中重構整個鏈(內存表示)。

我們還保持了 height 和區塊的 hash 之間的映射關系。

然后我們需要將一個 db 實例注入到 BlockChain 管理器結構中。

#[derive(Debug)]
structBlockChain{
blocks:Vec,
db:Db,
}

基于這個管理器實例,我們可以按照以下方式實現一個持久化方法:

fnpersist_block_to_table(

&mutself,
table:TableDefinition<&str,?&str>,
block:&Block,
)->Result<()>{
letheight=&block.header.height;
lethash=&block.header.hash;
letcontent=serde_json::to_string(&block)?;

//storehash->blockpair
self.db.write_block_table(table,&hash,&content)?;
//storeheight->hashpair
self.db
.write_block_table(table,&height.to_string(),&hash)?;
//storethelbp->hashpair(lastblockpointertohash)
self.db
.write_block_table(table,LAST_BLOCK_POINTER,&hash)?;

Ok(())
}

其中,我們使用 serde 框架并使用 serde_json 將整個 block 結構體序列化為字符串(json 格式)。如你所見,我們存儲了 3 對鍵值對:

hash -> 序列化的區塊字符串

height -> 區塊哈希

lbp (最后一個區塊的指針) -> 區塊哈希

我們可以像這樣從數據庫中檢索一個 Block:

fnretrieve_block_by_hash_from_table(

&self,
table:TableDefinition<&str,?&str>,
hash:&str,
)->Result>{
letcontent=self.db.read_block_table(table,hash)?;
info!("{:?}",content);
ifletSome(content)=content{
letb:Block=serde_json::from_str(&content)?;
Ok(Some(b))
}else{
Ok(None)
}
}

我們使用 serde_json::from_str() 來反序列化原始字符串。

接下來,我們需要弄清楚如何從數據庫中重新構建一個正確的區塊鏈。我們可以使用一個迭代來做這個,首先獲取最后一個區塊,然后獲取最后一個區塊的前一個區塊,依此類推。我們可以看看代碼:

fnpopulate_from_db_table(&mutself,table:TableDefinition<&str,?&str>)->Result<()>{

//findlastblockhashfromdb
letlast_block_hash=self.db.read_block_table(table,LAST_BLOCK_POINTER)?;
iflast_block_hash.is_none(){
returnOk(());
}
letlast_block_hash=last_block_hash.unwrap();

//retrievelastblock
letblock=self.retrieve_block_by_hash_from_table(table,&last_block_hash)?;
ifblock.is_none(){
returnOk(());
}
letblock=block.unwrap();
letmutprev_hash=block.header.prev_hash.clone();

letmutblocks:Vec=vec![block];
//iteratetooldblockesbyprev_hash
whileprev_hash!=GENESIS_PREV_HASH{
letblock=self.retrieve_block_by_hash_from_table(table,&prev_hash)?;
ifblock.is_none(){
returnOk(());
}
letblock=block.unwrap();
prev_hash=block.header.prev_hash.clone();

blocks.insert(0,block);
}

//contructaninstanceofblockchain
self.blocks=blocks;

Ok(())
}

我們可以像這樣使用這個 API:

letmutblockchain=BlockChain::new();

blockchain
.populate_from_db()
.expect("errorwhenpopulatefromdb");

然后可以測試它:

#[test]
fntest_store_block_and_restore_block(){
letmutblockchain=BlockChain::new_to_table(TABLE_BLOCKS_FORTEST);

//initialization
letgenesis_block=BlockChain::genesis();
letprev_hash=genesis_block.header.hash.clone();
blockchain.add_block_to_table(TABLE_BLOCKS_FORTEST,genesis_block);

letb1=Block::new(1,prev_hash,vec![]);
letprev_hash=b1.header.hash.clone();
blockchain.add_block_to_table(TABLE_BLOCKS_FORTEST,b1);

letb2=Block::new(2,prev_hash,vec![]);
blockchain.add_block_to_table(TABLE_BLOCKS_FORTEST,b2);

letblock_vec=blockchain.blocks.clone();

blockchain
.populate_from_db_table(TABLE_BLOCKS_FORTEST)
.expect("errorwhenpopulatefromdb");

_=blockchain.db.drop_table(TABLE_BLOCKS_FORTEST);

for(i,block)inblock_vec.into_iter().enumerate(){
letblock_tmp=blockchain.blocks[i].clone();
assert_eq!(block,block_tmp);
}
}

在我們的代碼中,使用 anyhow 來幫助管理各種錯誤,感謝這個漂亮的 crate,它使我們的生活更加輕松。

到目前為止,我們的區塊鏈已經具有了持久化的能力,不再擔心會丟失數據。我們已經到達了偉大征程的第一個里程碑。

審核編輯:黃飛

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 源代碼
    +關注

    關注

    96

    文章

    2946

    瀏覽量

    66951
  • 區塊鏈
    +關注

    關注

    111

    文章

    15563

    瀏覽量

    106691
  • Rust
    +關注

    關注

    1

    文章

    230

    瀏覽量

    6664

原文標題:使用Rust從零開發區塊鏈 01

文章出處:【微信號:Rust語言中文社區,微信公眾號:Rust語言中文社區】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    社區看區塊發展

    在其基礎上創建社群與組織,構成了一個相對開放的的生態系統。 區塊技術正是起源于這樣的網絡社區組織。2008年11月1日,一個自稱中本聰(Satoshi Nakamoto)的人在一個隱秘的密碼學討論組上貼出
    發表于 01-04 13:32

    什么是區塊 區塊有什么用

    的分布式賬本數據庫,沒有中心,數據存儲的每個節點都會同步復制整個賬本,信息透明難以篡改。  近幾年,越來越多的機構開始重視并參與區塊技術研發。最初的比特幣、以太坊,到各種類型的區塊
    發表于 03-26 11:31

    區塊在商業方面的應用如何

    的步伐將提速,而隨著應用范圍金融向非金融領域加速擴展,區塊將逐漸成為未來互聯網的重要組成部分,為打造價值網絡奠定重要基石。源中瑞平臺主要針對的領域有產品購買、定制開發、需求發布這三
    發表于 07-14 11:31

    區塊將改革供應

    團隊攜手研發出區塊應用系統,它對于整個供應的權益有以下幾點:1) 對于生產者:通過消費者對商品的購買數據以及售商的銷售業績來推動生產者的進步,通過生產者之間的競爭來推動發展,拓展
    發表于 08-08 11:11

    區塊軟件開發公司談區塊在供應金融場景中的應用

    `<p>  區塊技術開發公司:區塊應用軟件開發
    發表于 11-21 10:54

    區塊軟件開發公司談未來區塊的主要應用方向

    。在其他社交平臺上總是會收到類似的廣告窗口,因為區塊應用程序的數據隱私是對壟斷的大型數據平臺的可恥銷售。區塊應用技術在社會領域的作用是將社會網絡的控制
    發表于 11-22 16:54

    區塊將如何優化產業

    )使用區塊分布式記賬的特點的運用開發,包括身份驗證、證明、交易所、比特幣、云存儲等;  2)依據區塊的去中心化系統
    發表于 12-13 15:19

    區塊技術開發公司談區塊在酒業方面的應用

    假冒偽劣的行為,追查一切侵權行為的根源。利用區塊技術,消費者不再能購買假酒,制造商可以以最小的成本解決假酒的問題。隨著區塊技術與實體經濟的日益融合,我們可以共同
    發表于 12-14 11:41

    區塊對我們的生活有什么影響

    今天的信息圖表HIVE區塊技術向我們展示,它讓我們得以一窺區塊技術在金融世界之外的潛力。區塊
    發表于 07-10 04:20

    區塊+全球50個案例看區塊的應用與未來》高清pdf

    開發區塊電商平臺158第二節 區塊農業存在的問題160第十章 區塊醫療衛生163第一節 
    發表于 03-13 00:42

    區塊錢包軟件開發,區塊錢包源碼搭建

    區塊錢包的鑰匙誰也沒法幫我們找回錢包。區塊錢包軟件開發,區塊
    發表于 05-26 16:30

    什么是區塊區塊都有哪些應用?

    什么是區塊區塊未來的應用前景怎樣?
    發表于 06-28 09:20

    馬來西亞9家銀行聯手在區塊做文章_開發區塊貿易融資應用程序

    馬來西亞:9家銀行聯手在區塊做文章,開發區塊貿易融資應用程序? 3月24日,馬來西亞本地九家本地銀行已經宣布聯手合作,在區塊
    發表于 04-03 15:39 ?1223次閱讀

    開發區塊交易所如何挑選有技術實力的區塊開發公司

    開發區塊交易所該如何挑選有技術實力的區塊開發公司,源中瑞Dave區塊
    發表于 11-30 09:25 ?973次閱讀

    區塊場外OTC交易所源碼開發區塊交易所源碼

    區塊場外OTC交易所源碼開發區塊交易所源碼有需要需要開發區塊錢包系統包括(
    發表于 02-18 16:04 ?633次閱讀
    百家乐官网澳门路规则算法| 百家乐有秘技吗| 网上现金棋牌游戏| 百家乐正网| 百家乐官网必胜绝技| 澳门百家乐官网实战视频| 百家乐官网破解分| 全讯网百家乐官网的玩法技巧和规则 | 百家乐官网平注常赢玩法技巧 | 大发888游戏充值| 波音网址| 百家乐官网大路小路| 百合百家乐官网的玩法技巧和规则 | 菲律宾百家乐游戏| 瑞丰备用网址| 松江区| 百家乐官网奥| 桃源县| 澳门百家乐娱乐城开户| 威尼斯人娱乐项目| 皇朝娱乐城| 威尼斯人娱乐城返佣| 蓝盾百家乐官网代理| 百家乐事电影| 百家乐官网破解秘籍| 百家乐投注杀手| 车险| 平注打百家乐的方法| 网上百家乐官网怎么破解| 诺贝尔百家乐的玩法技巧和规则 | 百家乐路单之我见| 真人百家乐官网软件云南景 | 百家乐统计软件| 百家乐官网社区| 赌博中百家乐官网什么意思| 百家乐官网牌路分析仪| 大发888提款速度快吗| 百家乐技术交流群| 百家乐官网玩法皇冠现金网| 大发888扑克官方下载| 单张百家乐论坛|