Phần 2: Tạo ra công nghệ đào tiền ảo
Sơ hở của Blockchain hiện tại Tiếp nối phần một, ta đã tìm hiểu về công nghệ Blockchain, về tính phân tán và minh bạch của nó. Ta cũng thấy là công nghệ vừa tạo ra có nhược điểm là rất dễ bị hack. Bởi vì ta có được giao dịch cuối cùng trong chuỗi, thì lần theo dấu vết lần lượt các Hash của ...
Sơ hở của Blockchain hiện tại
Tiếp nối phần một, ta đã tìm hiểu về công nghệ Blockchain, về tính phân tán và minh bạch của nó.
Ta cũng thấy là công nghệ vừa tạo ra có nhược điểm là rất dễ bị hack. Bởi vì ta có được giao dịch cuối cùng trong chuỗi, thì lần theo dấu vết lần lượt các Hash của từng phần tử, ta sẽ xâu chuỗi lại được toàn bộ mảng Blockchain. Việc chỉnh sửa bằng cách tính toán lại toàn bộ Hash cho khớp và đồng bộ lúc này chỉ cần vài động tác và data sẽ nghiễm nhiên là toàn vẹn ở tất cả các máy trong mạng ngang hàng.
Có bạn sẽ bảo là có thuật toán để check MangBlock ở máy mình và MangBlock được tải về từ mạng P2P để xem sự khác nhau trước khi đồng bộ. Đúng là có thuật toán đó. Nhưng thuật toán này lại ưu tiên mảng nào "dài hơn" lại là mảng được cân nhắc là mảng đúng. Do đó nó không đủ mạnh để giải quyết vấn nạn hack.
Có một cách hay hơn để ngăn chặn việc này. Đó là giới hạn thời gian Hash được một Blockchain. Ta phải tăng độ khó của thuật toán Hash lên để Hash được một chuỗi sẽ cần rất nhiều thời gian. Điều này cũng có nghĩa là phải sau một thời gian nhất định mới có thể thêm mới 1 Block vào hệ thống. Ví dụ đồng tiền BitCoin thì quy định, sau mỗi 10 phút mới cho phép một bản ghi mới được thêm vào.
Làm điều này để làm gì?
- Ngăn chặn hệ thống Blockchain bị SPAM, liên tục có người thêm mới giao dịch giả vào hệ thống. Dẫn đến Blockchain bị DDOS, và có thể sập. Dữ liệu thật thì bị lấy đi.
- Ngăn chặn việc làm giả hệ thống, vì thời gian hacker Hash được 100 bản ghi sẽ bằng 100x10 phút = 1000 phút. Do đó hắn sẽ không dễ dàng clone toàn bộ hệ thống và Hash ra mã mới.
Khi một người dùng muốn thêm mới một bản ghi vào hệ thống, người đó phải chứng tỏ mình thực sự muốn giao dịch. Và để chứng minh điều đó anh ta cần bỏ tài nguyên của máy ra để tính toán Hash, và sau một thời gian nhất định, anh ta sẽ đăng ký thành công bản ghi nối tiếp (chain) vào Blockchain. Quá trình này người ta gọi là Proof-Of-Work.
Proof of Work
Ta hãy thử minh họa bằng cách sửa đổi file Class Block như sau:
/*=== ĐÂY LÀ CLASS MÔ TẢ CẤU TRÚC CỦA MỘT BLOCK. MỘT PHẦN TỬ CỦA BLOCKCHAIN ===*/ class Block { constructor(NgayGioTao, DuLieu, HashTruocDo = ') { //Để tạo ra một Block chúng ta cần truyền vào các tham số như sau: this.NgayGioTao = NgayGioTao; //Ngày tháng hiện tại tạo ra Block này this.DuLieu = DuLieu; //Dữ liệu sẽ được lưu trong BLock này. Nó có thể là bất cứ cái gì, từ String, Array, Object JSON... this.HashTruocDo = HashTruocDo; //Lưu trữ Hash của Block ngay trước Block này. Vì các Block sẽ được nối lại thành chuỗi (mảng). this.Hash = this.TinhToanHash(); //Mã hóa toàn bộ nội dung của BLock này theo thuật toán SHA256 và lưu lại vào chính Block này. this.GiaTriTuTang = 0; //THÊM VÀO Giá trị tự tăng của Block } TinhToanHash() { //Hàm mã hóa nội dung của toàn bộ Block. Do đó ta cần lấy toàn bộ các thuộc tính của Block đưa vào SHA256 để mã hóa ra một chuỗi. return CryptoJS.SHA256(this.HashTruocDo + this.NgayTao + JSON.stringify(this.DuLieu) + this.GiaTriTuTang) //Chỗ này có thêm GiaTriTuTang .toString(); //chú ý: JSON.stringify(this.DuLieu) sẽ convert biến Object this.DuLieu thành chuỗi } //thay đổi hàm TaoBlock thành hàm DaoBlock DaoBlock(DoKho) { while (this.Hash.substring(0, DoKho) !== Array(DoKho + 1).join("0")) { //Kiểm tra xem giá trị Hash hiện tại đã đạt đủ số 0 ở đầu tiên như yêu vầu về độ khó đặt ra chưa. Lặp đi lặp lại hàm cho đến khi tìm được giá trị Hash đáp ứng yêu cầu. this.GiaTriTuTang++; //Tăng giá trị trong Block lên, để Hash mỗi lần sẽ nhận được một giá trị khác nhau. Nếu Hash không có 2 hoặc n số 0 ở đầu thì sẽ không đạt yêu cầu và phải tiếp tục Hash cái khác. this.Hash = this.TinhToanHash(); //Tính toán lại Hash của toàn bộ Block ứng với lần tăng này. } console.log("Đã đào xong Block: " + this.Hash); //Nếu đã tìm được Hash thì ta coi đấy là một lần "đào" (hashing) thành công. } }
Trong class Block ta thêm vào một GiaTriTuTang, đây là một biến được dùng khi tính toán Hash.
Vì ta cần phải tăng độ khó mỗi khi Hash, hàm TinhToanHash vẫn không đổi, tuy nhiên ta tạo ra một thuật toán đơn giản, đó là không chấp nhận mã Hash tạo ra không đáp ứng yêu cầu. Yêu cầu của ta ở đây là mã Hash phải bắt đầu bằng 2 hoặc 3 hoặc 4 thậm chí 5 số "0" liên tiếp ở đầu.
Vì thuật toán SHA256 không bao giờ thay đổi đầu ra đối với 1 chuỗi đầu vào, bắt buộc phải thay đổi chuỗi đầu vào để tìm ra được Hash ở đầu ra thỏa mãn.
Do đó ta viết một hàm gọi là DaoBlock để lặp đi lặp lại quá trình "đào" cái mã Hash cho Block hiện tại. Và việc đào này có độ khó phụ thuộc vào biến DoKho. Nếu tăng số chữ số 0 liên tiếp lên thì cần lặp khá lâu mới tìm được chuỗi Hash ưng ý.
Ví dụ:
- DoKho = 2 thì cần 0.001s là tìm đc Hash có 2 chữ số 0 liền nhau ở đầu.
- DoKho = 3 thì cần 0.5s là tìm đc Hash có 3 chữ số 0 liền nhau ở đầu.
- DoKho = 4 thì cần 3s là tìm đc Hash có 4 chữ số 0 liền nhau ở đầu.
- DoKho = 5 thì cần 20s là tìm đc Hash có 5 chữ số 0 liền nhau ở đầu.
Đối với đồng 'tiền ảo BitCoin, thì độ khó của thuật toán được điều chỉnh để làm sao với mỗi 10 phút sẽ có một mã Hash ra đời. Dĩ nhiên là thuật toán của BitCoin không cùi bắp như thuật toán ở đây. Nhưng các bạn đã hình dung ra nó rồi đấy.
Proof-Of-Work còn được viết tắt là PoW. Khái niệm PoW được áp dụng vào Blockchain tương tự như cơ chế chống SPAM và DDOS 1 trang web bằng ReCapcha, người dùng muốn chứng thực mình không phải robot tự động thì phải bỏ công ra ngồi gõ một chuỗi ký tự lạ.
Giờ ta sửa lại class Blockchain để đưa thuật toán "Đào' Block vào:
/*=== ĐÂY LÀ CLASS MÔ TẢ CẤU TRÚC CỦA MỘT BLOCKCHAIN. LÀ MỘT MẢNG CÁC BLOCK ===*/ class Blockchain { constructor() { //Cấu trúc của Blockchain như sau this.MangBlock = []; //Tạo ra một mảng rỗng để chứa các Block. this.MangBlock.push(new Block("01/01/2018", "Genesis Block", "0")); //Tạo phần tử đầu tiên của Blockchain. Đây thường được gọi là Genesis Block, hay chính là "phần tử khởi tạo". Các phần tử tiếp theo sẽ nối tiếp vào phần tử này. this.DoKho = 5; //Thêm độ khó cho Blockchain; } PhanTuCuoiCung() { return this.MangBlock[this.MangBlock.length - 1]; //Lấy ra phần tử cuối cùng của Blockchain } TaoMoiBlock(newBlock) { //Hàm dùng để thêm mới một Block vào Blockchain. newBlock.HashTruocDo = this.PhanTuCuoiCung().Hash; //Lấy Hash của phần tử cuối cùng của mảng và lưu vào HasTruocDo của phần tử này //newBlock.Hash = newBlock.TinhToanHash(); //Lúc này ta không tính toán Hash đơn thuần nữa mà phải "đào" thì mới có Hash cho Block mới. newBlock.DaoBlock(this.DoKho); this.MangBlock.push(newBlock); //Nối phần tử newBlock vào làm phần tử cuối cùng của mảng Blockchain sau khi đã "đào" được. } KiemTraTinhToanVen() { for (let i = 1; i < this.MangBlock.length; i++) { const BlockHienTai = this.MangBlock[i]; //Lấy ra phần tử ở vị trí hiện tại const BlockTruocDo = this.MangBlock[i - 1]; //Lấy ra phần tử ở ngay trước vị trí hiện tại if (BlockHienTai.Hash !== BlockHienTai.TinhToanHash()) { //Kiểm tra lại Hash của toàn bộ Block hiện tại và Hash đã lưu xem có trùng nhau không. return false; //Nếu không trùng tức là Dữ liệu trong Block hiện tạiđã bị chỉnh sửa, hàm KiemTraToanVen sẽ trả về false luôn. } if (BlockHienTai.HashTruocDo !== BlockTruocDo.Hash) { //Lấy Hash hiện tại và Hash phần tử trước đó đã lưu xem có trùng nhau không. return false; //Nếu không trùng tức là Hash của Block hiện tại đã bị chỉnh sửa, hàm KiemTraToanVen sẽ trả về false luôn. } } return true; //Nếu kiểm tra hết toàn bộ trong vòng For mà không vấn đề gì thì tức là Blockchain vẫn toàn vẹn, chưa bị sửa đổi. } }
Ta cần tạo một biến this.DoKho trong Blockchain. Sau đó ta gọi newBlock.DaoBlock(this.DoKho); để mỗi khi tạo mới Block, ta phải đào mới có mã Hash cho nó.
Giờ thì test thôi nào. Hãy chạy thử LINK_DEMO dưới đây và nhớ bật F12 để xem console.log() ở tab Console ở màn hình Chrome Dev Tools.
Khi chạy ta thấy trình duyệt bị đơ một lúc, và một lúc sau mới hiện ra các giao dịch. Cửa sổ console sẽ cho thấy các mã Hash sau khi đào được.
Các bạn có thể xem DEMO tại link này: LINK_DEMO
Download file example2.html tại đây: LINK_DOWNLOAD
Có bạn đã hỏi tôi chỗ này:
Có vẻ như Blockchain và Tiền ảo (Cryptocurrency) thường đi cùng với nhau?
Đúng là như vậy. Blockchain không thể sống thiếu Cryptocurrency và Cryptocurrency cũng không thể sống mà không có Blockchain, như thể sinh ra đã là của nhau vậy. Blockchain nếu không có quá trình đào tiền ảo bằng các thuật toán Proof-Of-Work thì sẽ không có gì hấp dẫn người dùng, và quá ít người dùng trong hệ thống cùng đào sẽ dẫn đến 1 Hacker có máy tính đủ mạnh có thể đánh bại tất cả. Do đó một công ty nào đó muốn sử dụng Blockchain để làm cơ sở dữ liệu lưu trữ, họ phải liên tục tạo ra sự cạnh tranh và sự hấp dẫn cho những người tham gia xây dựng CSDL Blockchain đó.
Tuy nhiên nhiều đồng tiền ảo hiện nay đã có sự lo ngại là đến một giai đoạn thoái trào, phong trào đào tiền ảo sẽ nguội bớt, và người ta không cắm máy để đào nữa vì phần thưởng ít dần. Lúc này Proof-Of-Work không còn là liều thuốc mạnh. Người ta đang thay thế bằng một thứ mới, đó là Proof-Of-Stake.
Proof-Of-Stake
Proof-Of-Stake (viết tắt là PoS) ra đời vì 2 lý do:
- Người dùng dần dần mất đi hứng thú đào tiền ảo vì nó dần đi đến giới hạn không thể đào tiếp nữa. Và vì quá nhiều Blockchain + Tiền ảo mới ra đời, người dùng sẽ đổ xô đi đào đồng tiền mới, bỏ rơi đồng tiền cũ.
- Phong trào đào tiền ảo ngày nay đã dẫn đến sự lãng phí điện năng và công suất máy tính vào việc duy nhất là chạy SHA265 lấy mã Hash. Điều này là hệ lụy không đáng có chỉ vì mục đích bảo vệ một chuỗi BlockChain. Giả sử hàng nghìn loại Blockchain mới ra đời thì phải bao nhiêu phần cứng và điện năng mới đủ để bảo vệ và tấn công nó.
PoW sinh ra là để ngăn chặn việc SPAM Blockchain, và cũng chống hack. Vậy thì cách làm của PoS như sau:
- Những người tham gia vào mạng lưới Blockchain không còn gọi là Thợ đào mỏ (Miners) nữa mà được gọi là Nhân viên kiểm soát (Validators)
- Nhân viên lúc này sẽ phải đánh cược, khi chèn một Block vào Blockchain, anh ta phải hi sinh một ít tiền ảo đang sở hữu ở ví của mình vào đó. Nhiều người cùng chèn Block. Và người nào chịu hi sinh nhiều nhất sẽ là người chiến thắng, chèn được Block thành công và nhận được tiền phí mà mỗi giao dịch đã bỏ ra trả cho người đào.
Điều này có nghĩa là người đào sẽ đánh cược để có được tiền ảo?
Như này thì người nào càng giàu thì sẽ càng giàu nhanh. Người mới tham gia hệ thống chưa có đồng nào trong tay thì làm sao mà kiếm được lợi nhuận đây?
Thực tế thì PoS đang trong quá trình chế tạo và còn nhiều ý tưởng của nó chưa được kiểm chứng hết. Đồng tiền Ethereum dự kiến đến 2019 sẽ đưa PoS vào hệ thống thay cho PoW. Chúng ta hãy chờ xem sao.
Kết luận
Như vậy ta đã áp dụng thành công thuật toán ĐÀO cho Blockchain của mình. Tuy nhiên đây không phải Đào BitCoin mà chỉ là Đào BLock.
Để có thể ứng dụng Blockchain này và tạo ra một đồng tiền ảo BitCoin của riêng mình, ta cần phải tạo ra được "Phần Thưởng" cho người đào Hash. Đó chính là tiền ảo, một dạng tiền thưởng cho người bỏ công ra đào Hash.
Vì mã Hash là giới hạn bởi độ dài số ký tự. Do đó đến một lúc nào đó sẽ không còn tìm được mã Hash nào thỏa mãn yêu cầu đặt ra nữa. Đó chính là điểm mấu chốt tạo ra giá trị của đồng tiền ảo. Người nào bỏ công ra tìm Hash, sẽ nhận được Tiền ảo. Và chúng ta cũng sẽ tạo ra một Ví tiền ảo để có thể gửi và nhận BitCoin sau khi đã đào xong.
Để tự mình tạo ra một đồng tiền ảo của riêng mình, sử dụng HTML và Javascript, mời các bạn đón đọc phần 3 của Series này nhé.
Ghi chú: Các thuật ngữ chuyên ngành tiếng Anh các bạn có thể biết để tham khảo và đọc tài liệu cho rõ hơn như sau:
- DaoBlock trong blockchain thì hàm này thường có tên là Mining hoặc MineBlock
- GiaTriTuTang trong blockchain thì biến này thường có tên là nonce
- NgayGioTao trong blockchain thì biến này thường có tên là timestamp
- KiemTraTinhToanVen trong blockchain thì hàm này thường có tên là Validate hoặc Accept