Tạo ứng dụng blockchain đầu tiên với C#

Thông qua bài viết này mình sẽ hướng dẫn các bạn làm quen và hiểu thêm về công nghệ Blockchain
.
Mục đích
– Tạo hệ thống Blockchain đơn giản nhất.
– Tạo hệ thống mining (poor of work) đơn giản.
– Khám phá thêm về Blockchain.
Kiến thức cần chuẩn bị: OOP, biết 1 ngôn ngữ hướng đội tượng.
Ok giờ xắn tay vào việc nào
Making the Blockchain.
Một blockchain
là danh sách, chuỗi các khối (A blockchain is just a chain/list of blocks). Mỗi block
trong blockchain
sẽ chứa chữ ký số của nó, chữ ký số của khối trước nó và dữ liệu của khối (dữ liệu giao dịch là một ví dụ).
Hash = Digital Signature.
Mỗi khối không chỉ chứa mã hash của khối trước nó mà nó còn chứa mã hash của chính nó, được tính toán dựa trên mã hash của khối trước nó. Nếu dữ liệu khối trước đó bị thay đổi (khối A), việc này dẫn tới thay đổi mã hash của khối A, do mã hash được tính toán dựa trên data này. Việc này dẫn tới sự thay đổi mã hash của tất cả các khối trong chuỗi. Việc tính toán và so sánh giúp chúng ta phát hiện ra bất kì sự thay đổi nào trong blockchain.
Điều này có nghĩa là gì? – Nghĩa là khi thay đổi dữ liệu của 1 block
thì sẽ dẫn tới thay đổi dữ liệu của rất rất nhiều block
, và dãn tới thay đổi chain
(break the chain).
Giờ chúng ta sẽ thừ bắt đầu xây dựng một hệ thống Blockchain
đơn giản.
Tạo project
đặt tên là NoobChain
Thêm class Block để xây dựng blockchain
class Block { public String hash; public String previousHash; private String data; // Trong ví dụ này chúng ta chỉ lưu data là một thông báo. private long timeStamp; //Block Constructor. public Block(String data, String previousHash) { this.data = data; this.previousHash = previousHash; this.timeStamp = DatetimeHandle.GetTime(); } }
Như bạn thấy Block
cơ bản của chúng ta chứa một chuỗi hash
sẽ dùng để lưu chữ kí số. Một biến previousHash
để lưu hash
của khối trước nó, và dữ liệu của khối.
Bước tiếp theo chúng ta sẽ tiến hành tạo chữ ký số.
Tạo lớp HashSha256
, áp dụng thuật toán sha256 để sinh chuỗi, với nội dung như sau:
class HashSha256 { public override string Hash(string strInput) { try { var crypt = new System.Security.Cryptography.SHA256Managed(); var hash = new System.Text.StringBuilder(); byte[] crypto = crypt.ComputeHash(Encoding.UTF8.GetBytes(strInput)); foreach (byte theByte in crypto) { hash.Append(theByte.ToString("x2")); } return hash.ToString(); } catch (Exception e) { throw e; } } }
Sau đó quay trờ lại lớp Block
thêm và hàm tính mã hash
public String CalculateHash() { HashSha256 sha256 = new HashSha256(); String calculatedhash = sha256.Hash( previousHash + timeStamp.ToString() data); return calculatedhash; }
.. và thêm hàm này vào contructor
của lớp Block
public Block(String data, String previousHash) { this.data = data; this.previousHash = previousHash; this.timeStamp = DatetimeHandle.GetTime(); this.hash = CalculateHash(); // thêm hàm này vào cuối để chắc chắn các dữ liệu khác được init trước khi gọi hàm }
Ok, giờ chúng ta thử kiểm tra lại công việc vừa làm xem…
Trong hàm Main
của class program.cs
chúng ta sẽ viết đoạn code để hiển thị chuỗi hash
Khối đầu tiên được gọi là genesis block
, và vì nó không có khối phía trước nên ta sẽ gán previousHash
của nó bằng 0
class Program { static void Main(string[] args) { Block genesisBlock = new Block("Hi im the first block", "0"); Console.WriteLine("Hash for block 1 : " + genesisBlock.hash); Block secondBlock = new Block("Yo im the second block", genesisBlock.hash); Console.WriteLine("Hash for block 2 : " + secondBlock.hash); Block thirdBlock = new Block("Hey im the third block", secondBlock.hash); Console.WriteLine("Hash for block 3 : " + thirdBlock.hash); Console.ReadLine(); } }
Output của chúng ta sẽ là 3 mã hash
Mỗi block
giờ sẽ chứa chữ kí số được xây dựng trên thông tin của nó và chữ ký số của khối phía trước.
Để giống với khái niệm blockchain
hơn, ta sẽ lưu trữ các block
này trong List
Chỉnh sửa file program.cs
như sau:
class Program { public static List<Block> blockchain = new List<Block>(); static void Main(string[] args) { blockchain.add(new Block("Hi im the first block", "0")); blockchain.add(new Block("Yo im the second block",blockchain.ElementAt(blockchain.size()-1).hash)); blockchain.add(new Block("Hey im the third block",blockchain.ElementAt(blockchain.size()-1).hash)); string printBlockChain = new System.Web.Script.Serialization.JavaScriptSerializer().Serialize(blockchain); Console.WriteLine(printBlockChain); Console.ReadLine(); } }
Để sử dụng được JavaScriptSerializer thì các bạn làm như sau
Right click
References
and doAdd Reference
, then fromAssemblies->Framework
selectSystem.Web.Extensions
Chạy lại ứng dụng và xem kết quả thử nhé mọi người
Kiểm tra tính toàn vẹn của blockchain.
Chúng ta sẽ viết phương thức IsChainValid()
kiểu boolean
trong file program.cs
. Phương thức nãy sẽ loop qua tất cả các block
trong chain
và so sánh các chuỗi hash
. Phương thức này sẽ cần kiểm tra biến hash
so sánh nó với chuỗi hash
được tính toán, và chỗi hash
ở khối trước so sánh với biến previousHash
. Uhm, nghe có vẻ phức tạp, thử nhìn code xem có dễ hiểu hơn không nào.
public static Boolean IsChainValid() { Block currentBlock; Block previousBlock; //loop through blockchain to check hashes: for (int i = 1; i < blockchain.Count; i++) { currentBlock = blockchain.ElementAt(i); previousBlock = blockchain.ElementAt(i - 1); //compare registered hash and calculated hash: if (!currentBlock.hash.Equals(currentBlock.CalculateHash())) { Console.WriteLine("Current Hashes not equal"); return false; } //compare previous hash and registered previous hash if (!previousBlock.hash.Equals(currentBlock.previousHash)) { Console.WriteLine("Previous Hashes not equal"); return false; } } return true; }
Bất kì một thay đổi nào với mỗi block phương thức này sẽ trả về false.
Trên mạng lưới bitcoin, các nodes chia sẻ các blockchain
và chuỗi hợp lệ dài nhất sẽ được châp nhận bởi hệ thống. Vậy nếu một hacker giả mạo một khối và tạo nên chuỗi blockchain mới cho mạng thì sao. Điều này là bất khả thi, vì sao? Giả sử hacker có thể xâm nhập và thay đổi một khối dữ liệu, điều này dẫn tới các dữ liệu tiếp theo của khối này cũng bị thay đổi. Vì vậy cần rất nhiều thời gian và sức mạnh tính toán để hacker có thể vượt hơn được so với sức mạnh tính toán của các thành viên còn lại trong hệ thống khi kết hợp.

Lets start mining blocks!!!
Chúng ta sẽ yêu cầu minner
tiến hành đào-coin
bằng cách bắt họ phải thử các biến khác nhau trong block
cho đến khi chuỗi hash
bắt đầu với giá trị 0
. Tại sao lại là 0
?. Bạn có thể quy ước là bất cứ giá trị gì, tùy thuộc vào genesis hash
của bạn. Trong trường hợp này chúng ta chọn 0
.
Tiếp theo chúng ta thêm biến nonce trong hàm CalculateHash()
, và thêm hàm MineBlock()
như sau:
class Block { public String hash; public String previousHash; private String data; //our data will be a simple message. private long timeStamp; //as number of milliseconds since 1/1/1970. private int nonce = 0; //Block Constructor. public Block(String data, String previousHash) { this.data = data; this.previousHash = previousHash; this.timeStamp = DatetimeHandle.GetTime(); this.hash = CalculateHash(); } public String CalculateHash() { HashSha256 sha256 = new HashSha256(); String calculatedhash = sha256.Hash( previousHash + timeStamp.ToString() + nonce.ToString() + data); return calculatedhash; } public void MineBlock(int difficulty) { var str = new String(new char[difficulty]); String target = new String(new char[difficulty]).Replace('\0', '0'); //Create a string with difficulty * "0" while (!hash.Substring(0, difficulty).Equals(target)) { nonce++; hash = CalculateHash(); } Console.WriteLine("Block Mined!!! : " + hash); } }
Phương thức MineBlock()
truyền vào tham số difficulty
kiểu int
để quy định độ khó của thuật toán. Các bạn có thể thay đổi tham số này để kiểm tra tốc độ đào-coin
khi chạy chương trình. Ở ví dụ này mình khuyến khích các bạn đặt ở mức 4-6
cho việc testing
. Ex, Hiện tại độ khó của Litecoin
là khoảng 442,592
, khá kinh khủng.
Chúng ta thêm biến difficulty
vào lớp program.cs:
public static int difficulty = 5;
Tiếp đó chúng ta cập nhật lớp program.cs
, gọi hàm MineBlock()
cho mỗi block
mới. Phương thức IsChainValid()
cũng được gọi sau khi đào
được coin :D.
class Program { public static List<Block> blockchain = new List<Block>(); public static int difficulty = 5; static void Main(string[] args) { blockchain.Add(new Block("Hi im the first block", "0")); Console.WriteLine("Trying to Mine block 1... "); blockchain.ElementAt(0).MineBlock(difficulty); blockchain.Add(new Block("Yo im the second block", blockchain.ElementAt(blockchain.Count - 1).hash)); Console.WriteLine("Trying to Mine block 2... "); blockchain.ElementAt(blockchain.Count - 1).MineBlock(difficulty); blockchain.Add(new Block("Hey im the third block", blockchain.ElementAt(blockchain.Count - 1).hash)); Console.WriteLine("Trying to Mine block 3... "); blockchain.ElementAt(blockchain.Count - 1).MineBlock(difficulty); Console.WriteLine("\nBlockchain is Valid: " + IsChainValid()); string printBlockChain = new System.Web.Script.Serialization.JavaScriptSerializer().Serialize(blockchain); Console.WriteLine(printBlockChain); Console.ReadLine(); } public static Boolean IsChainValid() { Block currentBlock; Block previousBlock; //loop through blockchain to check hashes: for (int i = 1; i < blockchain.Count; i++) { currentBlock = blockchain.ElementAt(i); previousBlock = blockchain.ElementAt(i - 1); //compare registered hash and calculated hash: if (!currentBlock.hash.Equals(currentBlock.CalculateHash())) { Console.WriteLine("Current Hashes not equal"); return false; } //compare previous hash and registered previous hash if (!previousBlock.hash.Equals(currentBlock.previousHash)) { Console.WriteLine("Previous Hashes not equal"); return false; } } return true; } }
Chạy thử và xem kết quả nhé

Kết
Một blockchain giả mạo sẽ không thể bắt kịp chuỗi dài hơn và hợp lệ trừ khi chúng có tốc độ tính toán lớn hơn tất cả các nút khác trong mạng của bạn kết hợp. Một máy tính lượng tử trong tương lai hay gì đó (người ngoài hành tinh?)
Demo
https://github.com/kumochan/Blockchain-Sample-01
Leave a Comment