.Net Core实现区块链初探
區(qū)塊鏈這么火,咱也跟個風(fēng)。
?
一、前言
最近,銀行總行關(guān)于數(shù)字貨幣即將推出的消息頻傳,把BTC也帶得來了一波反彈。
借著這個風(fēng),我們也研究一下區(qū)塊鏈。
?
通常大家說到區(qū)塊鏈,實(shí)際包括兩部分概念:
第一個概念,就是狹義上的區(qū)塊鏈。聽起來很高大上又很復(fù)雜,但追根到底,它就是一種加密應(yīng)用。
提起加密,我們腦袋里會顯現(xiàn)出:DES、3DES、AES、RSA、DSA、SHA-1、MD5……很多很多。
狹義的區(qū)塊鏈,其實(shí)就是使用這些加密技術(shù)而形成的一種應(yīng)用。
這個應(yīng)用又分為兩個部分:
區(qū)塊
區(qū)塊就是存放數(shù)據(jù)的一個獨(dú)立空間。
不好理解?舉個例子:我們在紙上寫個作文,寫了好幾篇。那每一篇紙上,都會有一些我們寫的內(nèi)容。這個內(nèi)容,就是數(shù)據(jù)。而這張紙,就是一個區(qū)塊。
所以,區(qū)塊就是放某些數(shù)據(jù)的一個特定的獨(dú)立的空間。
根據(jù)需要,一個數(shù)據(jù)可以放在一個區(qū)塊上,也可以放在多個區(qū)塊上。同時,一個區(qū)塊可以只存放一個數(shù)據(jù),也可以存放很多個數(shù)據(jù)。這兒不需要太糾結(jié)怎么放,自己決定就好。區(qū)塊鏈關(guān)注的是數(shù)據(jù)的存放方式,而不是數(shù)據(jù)本身。
鏈
鏈這個概念更簡單,就是把上面說的區(qū)塊,用一個鏈表記錄下來。
既然說到鏈表,就能想到,在鏈表上記錄的區(qū)塊,是有次序的。此外,最重要的是,鏈里的每一個區(qū)塊,在記錄數(shù)據(jù)的同時,也同時記錄了他的前一個區(qū)塊的信息(在區(qū)塊鏈里,稱之為指紋)。
換句話說就是,每個區(qū)塊里,都記錄著這個區(qū)塊前邊所有區(qū)塊的信息,同時,每個區(qū)塊,都對這個區(qū)塊后邊的所有區(qū)塊產(chǎn)生影響。
?
這樣的設(shè)計,會形成這樣的效果:當(dāng)改變一個區(qū)塊的數(shù)據(jù)時,需要同時把這個區(qū)塊后邊所有區(qū)塊的指紋信息全部進(jìn)行同步更新。如果僅僅只改變這個區(qū)塊本身的內(nèi)容,那后邊的區(qū)塊會很容易通過指紋來驗(yàn)證這個區(qū)塊非法和無效。
第二個概念,是分布式存儲
上面區(qū)塊鏈的概念中,在數(shù)據(jù)保存上有一個漏洞:如果一個非法用戶真的把一個區(qū)塊以及這個區(qū)塊后邊的所有區(qū)塊都修改了,那他就改變了這個區(qū)塊鏈里保存的數(shù)據(jù)。怎么破?
一個有效的方式,就是分布式存儲。把這樣一個鏈,存放在很多個地方,每個地方都有這個鏈的一個副本。系統(tǒng)驗(yàn)證一個區(qū)塊是否合法,除了驗(yàn)證鏈的合法性外,還需要驗(yàn)證這個區(qū)塊在各處保存的副本是否一致。系統(tǒng)認(rèn)可超過半數(shù)一致的區(qū)塊為合法區(qū)塊。
這樣,非法用戶如果想改變一個區(qū)塊的數(shù)據(jù),不僅需要修改這個鏈,同時還需要把這個鏈在各處的副本中半數(shù)以上的記錄也修改了。當(dāng)這個副本的數(shù)量很大時,這將變成一個不可能完成的任務(wù)。
?
當(dāng)然,在互聯(lián)網(wǎng)上,安全永遠(yuǎn)是相對的。去年幣圈最大的事件,就是真的有一幫子黑客,利用廉價的服務(wù)器,造出了超過半數(shù)的區(qū)塊鏈副本,然后修改區(qū)塊數(shù)據(jù),并讓這些超過半數(shù)的副本認(rèn)可并覆蓋了正常的區(qū)塊鏈數(shù)據(jù),從而盜取了大量的數(shù)字幣并拋售。
這是題外話。
?
區(qū)塊鏈的概念就說到這里。
今天的代碼,我們僅研究區(qū)塊鏈的原理和方法。分布式存儲,有興趣的話,可以研究一下P2P的種子結(jié)構(gòu)和下載原理,路數(shù)是一樣的。
下面上代碼。
二、開發(fā)環(huán)境&基礎(chǔ)工程
這個Demo的開發(fā)環(huán)境是:Mac + VS Code + Dotnet Core 3.1.2。
$?dotnet?--info .NET?Core?SDK?(reflecting?any?global.json):Version:???3.1.201Commit:????b1768b4ae7Runtime?Environment:OS?Name:?????Mac?OS?XOS?Version:??10.15OS?Platform:?DarwinRID:?????????osx.10.15-x64Base?Path:???/usr/local/share/dotnet/sdk/3.1.201/Host?(useful?for?support):Version:?3.1.3Commit:??4a9f85e9f8.NET?Core?SDKs?installed:3.1.201?[/usr/local/share/dotnet/sdk].NET?Core?runtimes?installed:Microsoft.AspNetCore.App?3.1.3?[/usr/local/share/dotnet/shared/Microsoft.AspNetCore.App]Microsoft.NETCore.App?3.1.3?[/usr/local/share/dotnet/shared/Microsoft.NETCore.App]?
首先,在這個環(huán)境下建立工程:
創(chuàng)建Solution
這次,我們用Console創(chuàng)建工程
基礎(chǔ)工程搭建完成。
三、創(chuàng)建區(qū)塊Model
在工程下面,創(chuàng)建一個目錄Models,并在目錄下建立類Block.cs:
public?class?Block {public?DateTimeOffset?time_stamp?{?get;?set;?}public?object?data?{?get;?set;?}public?string?pre_hash?{?get;?set;?}public?string?hash?{?get;?set;?}public?string?nonce?{?get;?set;?} }解釋一下各個字段:
time_stamp:時間戳,也就是這個區(qū)塊的創(chuàng)建時間
data:數(shù)據(jù),可以是任意類型,是我們要用區(qū)塊鏈來保存的數(shù)據(jù)
pre_hash:前一個區(qū)塊的hash值
hash:當(dāng)前區(qū)塊的hash值
nonce:隨機(jī)數(shù)
在這幾個字段中,真正在區(qū)塊鏈中起作用的是后面三個字段:pre_hash、hash、nonce。
在計算中,hash值是由這個區(qū)塊的pre_hash、data、time_stamp、nonce四個字段共同計算產(chǎn)生。
這樣做,一方面,我們通過hash值可以驗(yàn)證保存的數(shù)據(jù)data,同時,也把前一個區(qū)塊的hash信息保存到了這個區(qū)塊中。
nonce字段在這個demo中,實(shí)際意義不大,但在實(shí)際項(xiàng)目中,卻有它的實(shí)用價值。比方BTC中,要求hash值有特定的格式(至少前8個字節(jié)全是0),需要通過改變nonce的值,來得到這樣的hash。又因?yàn)閔ash無法逆向計算,所以只能用窮舉法修改nonce,一個一個計算并測試hash,這個過程叫WK,
四、創(chuàng)建鏈
有了區(qū)塊model,創(chuàng)建鏈很簡單。
我們創(chuàng)建一個BlockChains類,并在里面用SortedList建立一個鏈。
public?class?BlockChains {private?static?SortedList<int,?Block>?_block_chains?=?new?SortedList<int,?Block>(); }鏈也建完了。
后面,我們會在這個鏈中實(shí)現(xiàn)對于區(qū)塊鏈的各種處理方法。
五、往鏈中增加區(qū)塊
下面我們在BlockChains類中寫一個往鏈中增加區(qū)塊的方法:
private?static?string?_hash_zero?=?"Initialize_Hash_By_WangPlus";public?bool?addBlockData(object?data) {Block?new_block?=?new?Block(){time_stamp?=?DateTimeOffset.Now,data?=?data,nonce?=?$"{_random.Next(9999):D4}",};new_block.pre_hash?=?_block_chains.Count?<=?0???_hash_zero?:?_block_chains.Last().Value.hash;new_block.hash?=?calculateHash(new_block);_block_chains.Add(_block_chains.Count?+?1,?new_block);return?true; } private?string?calculateHash(Block?block) {if?(block?==?null)return?string.Empty;string?data_json?=?JsonConvert.SerializeObject(block.data,?Formatting.None);string?block_string?=?$"{block.time_stamp.Ticks.ToString()}|{block.pre_hash}|{data_json}|{block.nonce}";var?block_hash?=?new?SHA256Managed().ComputeHash(Encoding.UTF8.GetBytes(block_string));return?Convert.ToBase64String(block_hash); }在這個實(shí)現(xiàn)的方法中,
第一個區(qū)塊需要特殊處理,因?yàn)樗膒re_hash不存在,所以我們給了一個默認(rèn)的串。
計算hash時,我們把區(qū)塊的time_stamp、pre_hash、data、nonce全都包含在里面了。
六、驗(yàn)證區(qū)塊
也是一個方法,加在BlockChains中:
public?bool?isBlockValid(int?index) {if?(index?<=?0?||?index?>?_block_chains.Count)return?false;if?((index?>?1?&&?_block_chains[index].pre_hash?!=?_block_chains[index?-?1].hash)?||?(index?==?1?&&?_block_chains[index].pre_hash?!=?_hash_zero))return?false;if?(_block_chains[index].hash?!=?calculateHash(index))return?false;return?true; } private?string?calculateHash(int?index) {return?calculateHash(_block_chains[index]); }這個Demo中,沒有實(shí)現(xiàn)分布存儲,所以驗(yàn)證區(qū)塊的部分,我們只做了簡單驗(yàn)證:驗(yàn)證當(dāng)前區(qū)塊和前一個區(qū)塊的hash是否匹配。
?
做到這兒,這個簡單的區(qū)塊鏈Demo就完成了。
七、總結(jié)和思考
上面是一個簡單的區(qū)塊鏈應(yīng)用中,區(qū)塊鏈概念的實(shí)現(xiàn)。
在實(shí)際應(yīng)用中,我們需要理解以下內(nèi)容:
區(qū)塊鏈?zhǔn)且粋€加密技術(shù),它本身跟數(shù)據(jù)無關(guān);
區(qū)塊鏈在形成后,是一個只讀鏈,就是說在通常情況下,我們不會從一個鏈中修改或刪除一個區(qū)塊。因?yàn)檫@會導(dǎo)致后續(xù)所有區(qū)塊的修改,這個代價很大;
因?yàn)閰^(qū)塊不可更改,所以區(qū)塊中存儲的數(shù)據(jù)也不可更改。如果保存的數(shù)據(jù)有錯,通常是采用類似記帳的方式,用反沖記錄去消除這個錯誤,而不是修改區(qū)塊鏈;
區(qū)塊鏈應(yīng)用中,在安全級別要求比較高的情況下,應(yīng)該把開發(fā)重點(diǎn)放在分布存儲上面。
上面Demo的代碼已傳到Github。
代碼地址:https://github.com/humornif/Demo-Code/tree/master/0010/demo
?
(全文完)
點(diǎn)「在看」,讓更多人因你而受益
↘ ?↘ ?↘
總結(jié)
以上是生活随笔為你收集整理的.Net Core实现区块链初探的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: 使用 Windows Terminal
- 下一篇: 微软开源 Tye 项目,可简化微服务开发
