Xây dựng blockchain đơn giản với golang. P4 - Wallet (Address)
Blockchain
23
Bitcoin
12
White

Trần Mỹ viết ngày 14/02/2018

Xin chào mọi người.

Đây là phần 4 trong bài viết của mình về xây dựng 1 blockchain đơn giản với ngôn ngữ Go.

Các bạn có thể có thể tham khảo 3 phần trước của mình ở đây :
Phần 1 : Cấu trúc cơ bản
Phần 2 : CLI + Network
Phần 3 : Persistent + Proof Of Work

Ở phần 3, mình đã nói về cơ chế lưu trữ dữ liệu của bitcoin và xây dựng dựa trên hình mẫu đó. Và mình cũng đã áp dụng Proof Of Work vào cơ chế đào block.

Tiếp theo đó ở phần này, mình sẽ xây dựng cơ chế tạo 1 Wallet (Ví), là phần cơ bản để tạo nên tính bảo mật của blockchain. Kết thúc bài viết, ta có thể dùng chương trình để tạo 1 wallet bitcoin cho riêng mình (Mình chưa dùng thử nhưng mình nghĩ là dùng được?). Wallet cũng là mảnh ghép cuối cùng trong bài viết để ta có thể xây dựng 1 trong những thành phần thú vị nhất của blockchain đó là Transaction ở phần sau.

Chú ý là thực tế thì private key được bảo quản rất kỹ, không hiển thị đơn giản như trong xây dựng của mình. Nhưng để đơn giản, dễ tìm hiểu thì mình cho lưu như 1 trường bình thường (đỡ tốn công viết code debug in ra màn hình)

1. Lý thuyết

1.1. Ví trong thực tế và ví trong blockchain

Trong thực tế khi nói đến ví, ta sẽ hình dung nó giống như 1 túi nhỏ chứa tiền, hoặc có thêm thẻ ngân hàng, credit card... Tức là ta sẽ cần tiền và thẻ xuất hiện trước, và sau đó là nhu cầu lưu trữ tiền xuất hiện, và ví xuất hiện.

Trong blockchain cũng gần giống như thế, ta sẽ có coin (mà thực chất chỉ là dữ liệu), và ví là khái niệm để mà ta sẽ dùng để quản lý số coin của mình.

("Coin" ở đây mình sẽ xây dựng ở phần tiếp theo Transaction và vẫn chưa xuất hiện ở phần này, vì thế nên mình muốn bạn đọc hiểu là mình xây dựng ngược "ví trước coin sau", bời vì trình bày về coin sẽ hơi phức tạp 1 chút nên mình để dành ở phần sau. Phần này mình sẽ chỉ trình bày qua. Nếu bạn có thắc mắc thì mình giải thích như trên)

Tiếp tục về khái niệm ví, trong thế giới thực, ta sẽ có nhìn nhận ví giống như 1 vật thể, trong đó có 1 tờ 10K, 2 tờ 20K VND..
Hoặc 1 cách CNTT hơn, nếu dùng cơ sở dữ liệu quan hệ, ta có thể lưu ví với 1 bảng wallets cấu trúc như sau :

id user_id coin
1 100 1.5
2 101 2.3

với user_id đại diện cho user sở hữu wallet.ó

Cả 2 hình thức trên đều có điểm chung đó là, bản thân ví không mang cơ chế bảo mật nào định dạng cho người sở hữu nó.

Trong blockchain, mình nghĩ nên chú ý 1 điểm đó là ta nên nhìn nhận ví giống như 1 cơ chế chữ ký hơn là 1 vật chứa giống như trong thế giới thực.

Một cách hình tượng, ta có thể tưởng tượng rằng mỗi block trong blockchain chứa trong nó ví dụ 1000 đồng coin, và mỗi đồng coin đó được viết kèm theo tag là tên của người sở hữu nó. Bạn thấy trong block B có 2 đồng là C1, C2 ghi kèm tag : S, tức là 2 đồng này thuộc về người sở hữu tag S này.
(Nhìn nhận này sẽ thay đổi ở phần sau, mình nghĩ đầu tiên nên hiểu như vậy thì sẽ dễ nhìn nhận hơn).

1.2. Kiểm tra số coin trong ví

Wallet trong blockchain giống như 1 cơ chế để tạo tag đó. Khi ta muốn biết mình có bao nhiêu coin trong blockchain, ta sẽ duyệt cả blockchain để thống kê số coin với tag của mình, và người khác cũng có thể làm như vậy để biết số coin của ta. Tag như vậy ta gọi là public key.

Ví dụ như trong bitcoin core, bạn có thể thấy dòng này thể hiện điều đó, với scriptPubKey mang ý nghĩa của public key và CTxOut gần giống như coin :

class CTxOut
{
public:
    CScript scriptPubKey;

1.3. Gán public key vào coin

Vậy thì ban đầu các public key được gán vào coin như thế nào?

Chúng ta sẽ nói đến cụ thể hơn ở phần sau khi đề cập đến khái niệm về Coinbase transaction. Ở phần này để hiểu 1 cách đơn giản, ta tưởng tượng rằng khi 1 miner đào được 1 block. Họ sẽ được thưởng 1 số coin tương ứng theo đặc tả của mạng lưới, và họ có quyền bất kỳ gán public key vào số coin này, và tất nhiên là họ sẽ gán public key của mình vào (hoặc là thêm người khác nữa nếu có ai đó hỗ trợ đào chung). Đó là khi coin được gán public key đầu tiên.

1.4. Giao dịch coin

Nếu bạn có tìm hiểu về bitcoin có thể bạn sẽ biết về 1 sự kiện tên là Bitcoin Pizza Day. Đó là ngày mà 1 developer (gọi tắt là L) của bitcoin core mua 2 chiếc pizza với giá 10000 bitcoin - ngày đầu tiên mà bitcoin trở nên có giá trị thương mại - và sự kiện này được nói đến như giao dịch đầu tiên của bitcoin. Bỏ qua chuyện trị giá của số bitcoin này ngày nay rất lớn thì mình sẽ lấy nó làm ví dụ về giao dịch coin ở đây.

Như vậy ta sẽ có là trước khi giao dịch này diễn ra, L đã có trong dữ liệu mạng lưới 10000 bitcoin được gán public key của mình, và người bán (S) chưa có coin nào. Và giao dịch sẽ diễn ra như sau :

  1. Giao dịch bắt đầu
  2. L sẽ chuyển toàn bộ số public key trên 10000 coin của mình sang public key của S
  3. S kiểm tra trong mạng lưới rằng tất cả các node đều đã chấp nhận sự thay đổi này
  4. S xác nhận số coin trên đã mang public key của mình, S ship 2 pizza đến cho L
  5. Giao dịch kết thúc

Nội dung của giao dịch rất đơn giản! chỉ đơn thuần là chuyển public key từ người này sang người kia. Nhưng vậy thì tại sao S không thể tự đổi public key 10000 bitcoin đó về cho mình được mà chỉ L - chủ nhân của chúng mới có thể?

Để lý giải vấn đề này, ta tưởng tượng rằng bitcoin có chế bảo mật mà khi đó mỗi coin sẽ được gắn thêm 1 ổ khóa , và ổ khóa này được tạo bằng private key. Tất các các node trong mạng lưới đều biết ổ khóa đó, nhưng không ai biết cách tạo ra và mở khóa nó trừ L.

Ở bước 2, L dùng private key của mình để tạo ra 1 cái chìa khóa k1, mà khi mở ổ khóa với k1, thì public key của coin gắn với nó sẽ chuyển sang từ public key của L sang public key của S.

Điểm thú vị trong cơ chế này, đó là mỗi chìa khóa kn mà L dùng private key của mình tạo ra thì sẽ chỉ chuyển được tag của coin sang 1 public key cố định. Tức là tất cả các node đều nhận được chìa khóa k1 này để xác nhận giao dịch trên, nhưng họ không thể dùng k1 để chuyển tag trên coin đó về public key riêng của mình (trộm). Và với đích public key khác, thì sẽ cần L tạo ra chìa khóa khác k2, k3.... kn. Trừ khi biết private key của L, người khác sẽ không thể tự tạo được số khóa trên.

Cơ chế trên được đảm bảo bởi tính chất toán học, và mỗi blockchain hiện nay có thể khác hàm sử dụng cho cơ chế này, nhưng tính chất cơ bản thì mình nghĩ vẫn như trên.

1.5. Address

Khi nói đến bitcoin hẳn các bạn đã nghe nói về address. Ta thường nói là mỗi ví sẽ có 1 địa chỉ riêng, và các bitcoin được trao đổi qua những địa chỉ này.

Về bản chất ta có thể nói address là 1 dạng chuyển đổi, được hash từ public key, do đó về mặt kỹ thuật thì ta không cần tạo ra address như là 1 phần thiết yếu của blockchain. Và thực tế trong bitcoin tồn tại song song 2 cách giao dịch đó là Pay-to-PubKey (P2PK - Chuyển tới public key) and Pay-to-PubKey-Hash (P2PKH - Chuyển tới public key được hash, tức là address).

Đối với bitcoin thì address có đặc điểm thuận lợi hơn so với public key đó là giảm được số byte của public key là 64 bytes xuống còn 24 bytes khi ta đưa vào giao dịch. Về lý do này, các bạn có thể tham khảo tạo đây

Mặc dù vậy mình cũng vẫn xây dựng address để ta có thể ánh xạ dễ dàng hơn đến bitcoin.

Mình đã từng viết 1 bài trình bày qua về cơ chế sinh private key, public key, address, các bạn có thể tham khảo tại đây

1.6. Cơ chế sinh private key, public key

Bạn có thể tham khảo cơ chế sinh trong bitcoin tại 1 bài mình đã viết tại đây đây hoặc sách mastering bitcoin để biết thêm chi tiết.

Ok vậy mình sẽ bắt đầu đi vào xây dựng.

2. Xây dựng

Cấu trúc wallet

type Wallet struct {
    PrivateKey ecdsa.PrivateKey
    PublicKey  []byte
    Address    string
}

Cấu trúc wallet của mình rất thẳng, bao gồm 3 trường quan trọng ta sẽ thường xuyên dùng đến đó là private key, public keyaddress. (Mặc dù ít nhất ta chỉ cần lưu private key, 2 trường kia có thể sinh ra từ đó, nhưng ta sẽ lưu hết cho dễ tham chiếu)

Về lý thuyết ta cũng có thể lưu slice 32 bytes (256 bit) cho private key nhưng thực tế ta sẽ lưu cấu trúc của ecdsa chuẩn bị sẵn cho dễ thao tác (Nếu không thì mỗi lần tham chiếu đến ta sẽ phải generate từ slice ra cấu trúc của ecdsa)

Private key, Public key

Ta sẽ nhìn qua về lưu trữ key của package ecdsa

// PublicKey represents an ECDSA public key.
type PublicKey struct {
    elliptic.Curve
    X, Y *big.Int
}

// PrivateKey represents a ECDSA private key.
type PrivateKey struct {
    PublicKey
    D *big.Int
}

Trong 1 bài viết trước về private key của mình tại đây, mình đã có nói về việc private key bản chất là 1 số 256 bit, thế hiện số lần nhân điểm G trên đường cong toán học. Trong cấu trúc trên, ta có thể thấy số lần đó thể hiện ở D *big.Int*, và đường cong toán học là elliptic.Curve. public key cũng tương tự thể hiện tọa độ của private key trên đường cong đó.

Trong cấu trúc private key của ecdsa cũng đã có sẵn private key rồi nhưng mình vẫn sẽ lưu ra ngoài cấu trúc riêng để tiện thao tác.

Address

Về cách sinh address từ private key và public key, bạn có thể tham khảo tại link từ bitcoin offical, implement của mình cũng nguyên theo đó chỉ khác về cách viết code với golang. Nếu bạn có thắc mắc thì có thể để lại comment, bài viết cũng đã khá dài nên mình sẽ không sẽ trình bày thêm.

alt text

Ok, xây dựng wallet coi như xong, mình sẽ trình bày tiếp 1 về thay đổi về phần này so với phần trước.

3. Một số thay đổi so với phần 3

3.1. Cung cấp CLI tạo wallet

Trong phần này có thể dùng CLI để tạo 1 wallet mới với cw (create wallet). Dưới đây là 1 ví dụ.

$ ./simplebc cw
New wallet is created successfully! Wallet is exported to : * config.json *

  ** Wallet Information **
  + Private Key (64 bytes) : 381ee77a0cb49426eac8957348e13232721bc75a9d8497e2e12d8a86bd90e4be
  + Public Key (130 bytes) : 0481f821580109904c8b9a71c1db1bf12eca86ed50e0347bbbbc6db8d6ec68909f22948d4f7011e6476e64a2d8abe8d4d6f4073d2bf6984b52c32c03f14bd273b2
  + Address (34 bytes) : 1DyReFyJKMya2nXziS5zfYRiCLKsrNfWZo

Các bạn có thể dùng kiểm tra address này trên blockchain thực tế của bitcoin xem có gì thú vị không với link
https://blockchain.info/address/{address}
(ví dụ https://blockchain.info/address/1DyReFyJKMya2nXziS5zfYRiCLKsrNfWZo)

3.2. Thêm message yêu cầu và trả về address của wallet tương ứng với node

messsage.go

    CmdReqAddress = "REQ_ADDR"
    ...
    CmdResAddress = "RES_ADDR"

Giờ đây ta có thể gửi request đến node và yêu cầu nó in ra address wallet của mình.

Phần xây dựng của mình kết thúc tại đây!

4. Tổng kết

Ở phần này, mình đã xây dựng và trình bày về cách tạo ví trong bitcoin, làm điều kiện tiên quyết để tiếp tục phần sau là 1 phần hết sức thú vị trong bitcoin đó là Transaction.

Source code : https://github.com/mytv1/blockchain_go/tree/part_4

Tham khảo :
https://jeiwan.cc/posts/building-blockchain-in-go-part-5/
https://en.bitcoin.it/wiki/Technical_background_of_version_1_Bitcoin_addresses

Bình luận


White
{{ comment.user.name }}
Bỏ hay Hay
{{comment.like_count}}
Male avatar
{{ comment_error }}
Hủy
   

Hiển thị thử

Chỉnh sửa

White

Trần Mỹ

9 bài viết.
85 người follow
Kipalog
{{userFollowed ? 'Following' : 'Follow'}}
Cùng một tác giả
White
38 9
XIn chào mọi người. Thời gian gần đây mình có tìm hiểu về blockchain và golang. Mình viết bài viết này với mục đích chia sẻ và tổng hợp những kiến...
Trần Mỹ viết 6 tháng trước
38 9
White
28 5
Xin chào mọi người. Thời gian ngắn gần đây mình có tìm hiểu 1 chút về Bitcoin và Blockchain, và để củng cố kiến thức thu nạp được mình quyết định ...
Trần Mỹ viết 9 tháng trước
28 5
White
15 1
Xin chào mọi người. Đây là phần 2 trong bài viết về xây dựng blockchain đơn giản với golang của mình. Ở (Link) mình đã trình bày về việc xây dựng...
Trần Mỹ viết 6 tháng trước
15 1
Bài viết liên quan
White
11 5
Tạm xóa
Giaosucan viết 5 tháng trước
11 5
White
38 9
XIn chào mọi người. Thời gian gần đây mình có tìm hiểu về blockchain và golang. Mình viết bài viết này với mục đích chia sẻ và tổng hợp những kiến...
Trần Mỹ viết 6 tháng trước
38 9
{{like_count}}

kipalog

{{ comment_count }}

bình luận

{{liked ? "Đã kipalog" : "Kipalog"}}


White
{{userFollowed ? 'Following' : 'Follow'}}
9 bài viết.
85 người follow

 Đầu mục bài viết

Vẫn còn nữa! x

Kipalog vẫn còn rất nhiều bài viết hay và chủ đề thú vị chờ bạn khám phá!