January 06, 2018

KCoin - Phần 1

KCoin được tạo ra với mục đích KHOA HỌC và HỌC TẬP. KCoin KHÔNG được thương mại hóa cũng như sử dụng trong thực tế. Mã nguồn của KCoin được phát hành với giấy phép mã nguồn mở MIT cho phép bất kỳ ai tham khảo cũng như sử dụng để tìm hiểu cách hoạt động của blockchain.

Tài liệu tham khảo

Mã nguồn

Mã nguồn KCoin blockchain được đặt tại github: https://github.com/nguyenkha/kcoin-blockchain

Mình là con người hơi ham hố à mà chắc gọi là quá ham hố, nói chung cũng khoái cái gì đang hot lắm. Nên sau khi có gợi ý của ông anh mình quyết định tạo ra KCoin để làm đồ án cuối kỳ cho môn CTT522 - Các công nghệ mới trong phát triển phần mềm. Xuất phát điểm thì cũng như mọi người mình hoàn toàn chưa tìm hiểu gì về cách hoạt động của một blockchain (chuỗi khối), chỉ nắm được:

  • Các transaction (giao dịch) được tập hợp trong các block (khối)

  • Một khối có tham chiếu đến khối trước đó => tương tự danh sách liên kết

  • Một khối được đưa vào hệ thống phải thỏa mãn một tiêu chí nào đó về chuỗi hash (băm) của dữ liệu trong block => tìm ra block giống như đào mỏ tìm vàng

Đó là tất cả những gì mình biết trước khi bắt tay viết ra blockchain cho KCoin. Mình học bằng cách tìm hiểu cách mà blockchain của Bitcoin hoạt động, sau đó đơn giản hóa lại để các bạn sinh viên có thể sử dụng một cách dễ dàng nhất có thể mà không bỏ mất những gì đặc trưng quan trọng. Mình dự tính viết khoảng 2-3 phần cho chủ để đề này dành cho những ai muốn tham khảo. Trong phần 1 này mình sẽ giới thiệu Giao dịch trên blockchain bằng cách sử dụng các đoạn mã nguồn minh họa bằng JavaScript. Hiện tại mình tạm thời giản lược lại sự nhất quán và thực tế mình cũng đang tìm hiểu phần này và sẽ bổ sung vào mã nguồn trong tương lai.

Cơ chế tạo giao dịch

Với ứng dụng của blockchain là một hệ thống cho phép mọi người có thể trao đổi tiền mình tạm gọi là vậy cho mọi người dễ hình dung, chúng ta có thể gọi nó là một loại tài sản (ảo) thuộc sở hữu của cá nhân nào đó: vàng, năng lượng, khí… Nhắc lại một lần nữa là tiền này không có giá trị thật, mục đích chỉ để tìm hiểu thôi. Với một hệ thống tương tự bên ngoài thực tế tương ứng chúng ta có thể xem như hoạt động một ngân hàng bao gồm: Phát hành tiền (đối với nhà chức trách), gửi tiền, rút tiền, chuyển khoản. Đối với KCoin chúng ta chỉ có 2 hoạt động: Phát hành tiền (không hợp pháp theo pháp luật hiện hành của Việt Nam), chuyển khoản. KCoin được tạo ra bằng cách thưởng cho người tạo ra các block và từ đó được chuyển cho các cá nhân khác. Tại sao như vậy mình sẽ giải thích sau. Chúng ta có thể xem hoạt động phát hành tiền là một giao dịch chuyển khoản với nguồn tiền… từ trên trời rơi xuống hay tự dưng bạn tìm được một mỏ vàng ngay dưới nhà bạn (mà thực tế bạn cũng chẳng hưởng lợi gì từ việc này đâu =]]). Tóm lại một transaction bao gồm 3 thông tin:

let transaction = {
  input: 'Nguồn tiền',
  output: 'Nơi nhận',
  value: 100
};

Tuy nhiên bitcoin được tạo ra với mục đích ẩn danh các hoạt động luân chuyển tiền giữa cá nhân, nên tiền không được chỉ đích danh là số tiền này của ai và được chuyển cho ai. Do đó, người nhận thường không được xác định cụ thể là ai mà chỉ là một đoạn mã nhằm khóa số tiền này lại nhưng vẫn phải có cách để sử dụng nó sau này, việc này giống như bạn cho tiền vào két sắt và khóa lại nhưng và giao chìa khóa cho một ai đó có quyền sử dụng nó sau này. Cơ chế này thậm chí còn chặt chẽ hơn nữa là chính bạn là người gửi tiền cũng không thể mở lại két sắt này vì khi thực hiện giao dịch là bạn đã bàn giao chìa khóa cho một người khác mà không thể lấy lại. Dĩ nhiên vẫn có thể xảy ra trường hợp là người nhận chính là bạn thì không tính nhé.

Vậy số tiền được khóa lại bằng cách nào? Với bitcoin đoạn mã này giống như một chương trình nhỏ với các toán tử và giá trị được đặt vào sao cho khi một ai đó có thể chứng minh mình chạy hết đoạn mã này mà không có lỗi gì thì là người có quyền sử dụng nó như một một nguồn tiền trong các giao dịch trong tương lai. Trong KCoin mình đơn giản hóa lại đoạn mã output này thành một chuỗi mô tả một cấu trúc dạng ADD [địa chỉ người nhận], để nói là khoản tiền này được gửi đến người sở hữu địa chỉ gọi là lockScript. Dĩ nhiên mọi người có thể mở rộng nó theo một cách nào đó mà mọi người muốn như: tới thời điểm nào đó mới sử dụng được, hay một mật khẩu cố định nào đó, hoặc thậm chí khi một sự kiện nào đó xảy ra…

let transaction = {
  input: 'Nguồn tiền',
  lockSript: 'ADD ea0a35a40a7ddb594f8e6657d340530d675999cdb94ff64cb4246635205c4ceb',
  value: 100
};

Địa chỉ trong KCoin là một chuỗi 256 bits = 32 bytes = 64 ký tự hex là kết quả của một phép tính hash sha256. Rồi, giờ tới phần quan trọng nhất là nguồn tiền ở đâu ra? Nguồn tiền có 2 dạng: một từ trên trời rơi xuống (mình sẽ nói sau), hai là từ output trước đó (và dĩ nhiên là đang bị khóa lại), bạn muốn sử dụng phải mở nó ra. Nhưng với blockchain mọi thứ đều được công khai vậy mở nó ra thì chẳng lẽ là đưa chìa khóa cho thiên hạ vô xâu xé tài sản của bạn? Haha, may mắn các nhà khoa học đã tìm ra một cách rất hay ho để chứng minh được sự sở hữu mà vẫn không cần phải công khai khóa. Bạn vẫn sử dụng nó hằng ngày ngay khi bạn duyệt web, lướt facebook hay mở bất cứ app nào trên điện thoại của bạn gọi là Mã hóa công khai. Giải thích thì dài dòng, các bạn sinh viên có thể Google hoặc học môn Mã hóa mật mã hoặc Mã hóa thông tin và ứng dụng để biết thêm. Đại loại chúng ta có bộ 2 chìa khóa: một cái công bố công khai và một cái bạn giữ bí mật. Hai chìa khóa này có sự liên hệ với nhau sao cho nếu bạn khóa bằng một khóa thì CHỈ CÓ THỂ mở bằng khóa kia và ngược lại. Với tính chất này chúng ta có thể giải quyết được vấn đề trên bằng cách như sau:

let publicKey, privateKey = generateKeyPair();
let address = sha256(publicKey);

Vậy là chúng ta có mối liên hệ private key - public key - address. Chúng ta chỉ sử dụng được số tiền output khi chúng ta sở hữu cặp khóa tương ứng với địa chỉ này. Dĩ nhiên trừ khi bạn tìm được một cặp khóa khác mà sha256(publicKey) == address.

Để sử dụng được nguồn tiền thì người sở hữu địa chỉ phải dùng private key để ký trên thông tin giao dịch sắp gửi đi giống như bạn ký trên ủy nhiệm chi để chuyển khoản để nộp cho ngân hàng thực hiện giao dịch. Mặt khác địa chỉ thực chất là dẫn xuất từ public key (rút gọn) do đó để mở được khoản output bạn phải đính kèm theo giao dịch public key nữa, việc này không ảnh hưởng đến bảo mật vì bản chất cái tên public key đã nói lên chức năng của nó. Mình có thể dùng chính public key làm địa chỉ nhận tiền nhưng mình dùng hash của nó là vì để rút ngắn nội dung đoạn mã trong giao dịch mà sẽ lưu trên blockchain cũng như thống nhất chiều dài vì public key có thể lên đến 1024bits hay hơn thế nữa.

let signature = privateKey.sign(transaction);

Khi đã có chữ ký mình sẽ bổ sung thông tin này vào transaction:

let signedTransaction = {
  input: {
    referenceOutputHash: '3c6797eb8872920de3d8c7584abf11e53f1a85c900f90bc28e761f96bb8213b6',
    unlockScript: 'PUB [publicKey] SIG [signature]'
  },
  lockSript: 'ADD ea0a35a40a7ddb594f8e6657d340530d675999cdb94ff64cb4246635205c4ceb',
  value: 100
};

referenceOutputHash chính là hash của giao dịch chứa nguồn tiền output trước đó sẽ làm input cho giao dịch chúng ta sắp tạo. Và unlockScript chứa 2 thông tin là public key và signature dùng để chứng kiểm tra công khai sha256(publicKey) == addresspublicKey.verify(transaction, signature) == true. Bitcoin quy định một nguồn tiền chỉ được sử dụng (mở khóa) một lần duy nhất, do đó nguồn tiền phải ĐƯỢC SỬ DỤNG TOÀN BỘ trong một giao dịch, dẫn đến phát sinh việc phải có thêm một output nữa để nhận tiền thối nếu không bạn sẽ mất đi số chênh lệch giữa input và output.

let signedTransaction = {
  inputs: [
    {
      referenceOutputHash: '3c6797eb8872920de3d8c7584abf11e53f1a85c900f90bc28e761f96bb8213b6',
      referenceOutputInxex: 1
      unlockScript: 'PUB [publicKey] SIG [signature]'
    }
  ],
  outputs: [
    { 
      lockSript: 'ADD ea0a35a40a7ddb594f8e6657d340530d675999cdb94ff64cb4246635205c4ceb',
      value: 100
    },
    { 
      lockSript: 'ADD fa5680ea199221aeecbc91049709c16fb32656a7fe58887e70a90a9849de2943',
      value: 9900
    }
  ]
};

Bạn thấy mình đã đổi cả input và output thành một mảng nghĩa là chúng ta có thể sử dụng nhiều nguồn tiền khác nhau để gửi cho những địa chỉ khác nhau, trong đó có tiền thối của bạn. Blockchain sẽ kiểm tra ràng buộc tổng các input >= tổng các output. referenceOutputInxex là index từ 0 của output trước đó. Một người có thể sử dụng trong input để nhận lại tiền thối, nhưng để nâng cao tính nặc danh các ứng dụng ví điện tử thường phát sinh ra các bộ địa chỉ (và khóa) mới để nhận tiền thối. Mặc dù thông tin các giao dịch là công khai nhưng nếu dùng các địa chỉ khác nhau, người khác không thể biết được tiền đi AI đến AI vì họ không biết được là một người sở hữu những địa chỉ nào. Giao dịch bên trên gửi 100 KCoin đến ea0a35... và 9900 KCoin đến fa5680.... Nghĩa là input 3c6797... phải có ít nhất phải có giá trị là 10000 KCoin, chúng ta không biết được liệu bạn gửi đi 9900 hay gửi đi 100 cho người nhận hay là gửi cho 2 người khác sau với toàn bộ số tiền trên. Một giao dịch trên thực tế bạn tìm thấy tại đây https://kcoin.club/#/blocks/4 có thể có rất nhiều input và output. Do đó nếu sử dụng một cách đúng đắn, các giao dịch trên blockchain mặc dù là công khai nhưng lại có thể ẩn đi danh tính của bạn.

Vậy là xong phần giao dịch, sau khi tạo xong bạn gửi nó lên blockchain để thông báo cho mọi người về giao dịch đó. Tạm kết ở đây, mình sẽ nói phần tiếp theo về cách mà giao dịch được xử lý trên blockchain như thế nào.