Smart contracts - Khi niềm tin trở lại (P1: Introdution)

Lời nói đầu

Xin chào các bạn, để tiếp tục loạt bài về blockchain, hôm nay mình xin nói về smart contract và các khái niệm, công cụ xoay quanh Smart contracts trên nền tảng ethereum. Nếu bạn nào chưa biết ethereum là gì, có thể tham khảo bài viết Ethereum, một nền tảng Blockchain đầy triển vọng!. Như các bạn đã biết, trong ethereum có 2 loại account là: Externally Owned Accounts (EOAs) và contract accounts. EOAs được kiểm soát bởi các phần mềm ngoài, chẳng hạn như các wallet application, nó nằm ngoài ethereum. Contract accounts được kiểm soát bởi phần mềm chạy trong máy ảo ethereum (EVM). Cả 2 loại tài khoản đều được xác định bởi 1 địa chỉ ethereum. Trong phạm vi bài viết này chúng ta sẽ thảo luận về loại thứ 2, contract accounts và các phần mềm kiểm soát smart contracts.
Để hiểu được bài viết này, yêu cầu các bạn cần có những kiến thức cơ bản về blockchain, ethereum, key, address, account, transaction ...

Smart contract là cái nồi gì vậy?

Theo dòng lịch sử chúng ta sẽ thấy công nghệ đã thay đổi rất nhiều thứ, kể cả nhận thức của mỗi chúng ta. Các công nghệ mới được sinh ra và dần dần thay thế các công nghệ đã trở nên lạc hậu. Bắt đầu kỉ nguyên của internet, niềm tin luôn là 1 thứ gì đó khá xa xỉ khi các tổ chức, cá nhân bắt tay, giao tiếp với nhau trên mạng internet. Đứng trước bài toán đó, vào những năm 1990, nhà mật mã học Nick Szabo đã đưa ra 1 khái niệm hoàn toàn mới là smart contracts.
Smart contracts tạm dịch là các hợp đồng thông minh, được định nghĩa là một tập hợp các lời hứa, được quy định dưới dạng kĩ thuật số, bao gồm các giao thức đảm bảo các bên thực hiện các lời hứa khác nhau. Xét về khía cạnh Computer programs thì hợp đồng thông minh đơn giản là các chương trình máy tính, từ hợp đồng không có ý nghĩa pháp lý trong ngữ cảnh này. Một khi hợp đồng được triển khai, mã của hợp đồng không thể được thay đổi. Không giống như các phần mềm truyền thống, các duy nhất để sửa đổi một hợp đồng là triển khai một hợp đồng mới =)).
Mặc dù khái niệm smart contracts đã có từ khá lâu nhưng mãi đến sau này, khi công nghệ blockchain xuất hiện. Chúng ta mới có thể hiện thực hóa được các ý tưởng này.
Trong ethereum, các hợp đồng thông minh và các ngữ cảnh của nó được kiểm soát và thực thi trên máy ảo EVM.

Vòng đời của smart contract

Các Smart contract thường được viết bởi các ngôn ngữ lập trình bậc cao, ví dụ như Solidity. Nhưng để chạy, chúng bắt buộc phải được biên dịch ra low-level bytecode để chạy trên máy ảo EVM. Sau khi được biên dịch, chúng được deploy lên Ethereum blockchain với 1 transaction tới 1 contract-creation address. Mỗi một hợp đồng được xác định bởi một địa chỉ ethereum. Địa chỉ này có thể được sử dụng trong các transaction với tư cách người gửi, người nhận hoặc để gọi các chức năng của hợp đồng.
Chú ý, các smart contract chỉ được chạy khi chúng được gọi bởi 1 transaction, tất cả các smart contract trong ethereum được thực hiện bởi 1 transaction được khởi xướng từ 1 EOAs (Externally Owned Accounts).
Transaction là atomic, vậy nên bất kể 1 transaction có gọi bao nhiêu hợp đồng đi chăng nữa, trạng thái của các hợp đồng sẽ thay đổi nếu transaction thành công, nếu transaction thất bại, toàn bộ mọi thứ sẽ được rolled back như thể transaction chưa bao giờ được gọi. Tuy nhiên transaction không thành công vẫn được lưu trữ trên blockchain và có thể sẽ khấu trừ gas cost vào tài khoản phát sinh transaction nhưng không có tác động nào lên trạng thái của hợp đồng.
Không thể thay đổi mã của hợp đồng nhưng chúng ta có thể xóa chúng khỏi blockchain. Để thực hiện xóa chúng, chúng ta sử dụng EVM opcode SELFDESTRUCT, opcode này sẽ remove contract ra khỏi blockchain. Hoạt động này có gas cost là âm, do đó khuyến khích việc giải phóng trạng thái lưu trữ. Xóa hợp đồng theo cách này sẽ không xóa transaction history của hợp đồng vì nó đã được lưu trữ trong blockchain nhưng nó sẽ loại bỏ trạng thái của hợp đồng ở tất cả các khối trong tương lai.

Introdution to Ethereum high-level languages

EVM là một máy tính mô phỏng chạy một dạng mã máy đặc biệt gọi là mã bytecode EVM. Mặc dù có thể lập trình các hợp đồng thông minh trực tiếp bằng bytecode. EVM bytecode rất khó sử dụng và khó cho lập trình viên đọc và hiểu. Do đó, hầu hết các nhà phát triển ethereum sử dụng 1 ngôn ngữ lập trình cao hơn để viết các chương trình smart contract và sau đó compile chúng ra bytecode. Mặc dù bất kỳ ngôn ngữ lập trình bậc cao nào cũng có thể được điều chỉnh để viết các hợp đồng thông minh nhưng do đặc điểm hoạt động trong môi trường thực thi hạn chế và tối giản (EVM), nơi hầu như tất cả các giao diện người dùng thông thường, giao diện hệ điều hành và giao diện phần cứng đều bị thiếu nên sẽ là dễ dàng hơn nếu xây dựng 1 ngôn ngữ viết smart contract tối giản, từ đầu hơn là thay đổi các ngôn ngữ có sẵn để phù hợp viết các smart contract.
Việc viết smart contract sẽ làm thay đổi tư duy của các lập trình viên, vì đơn giản là không có chỗ cho sai lầm, mọi lầm đều phải trả giá bằng tiền bạc (ether). Dưới đây là 1 số ngôn ngữ lập trình dùng để viết smart contract:

  • LLL

Một ngôn ngữ lập trình hàm. Là ngôn ngữ lập trình bậc cao đầu tiên cho Ethereum smart contract, hiếm khi được sử dụng ngày nay.

  • Serpent

Một ngôn ngữ lập trình thủ tục với cú pháp tương tự Python được tạo ra bởi Vitalik Buterin, ít khi được sử dụng

  • Solidity

Ngôn ngữ lập trình thủ tục với cú pháp tương tự JavaScript, C++ hoặc java. Ngôn ngữ phổ biến nhất và thường được sử dụng để viết các hợp đồng thông minh được tạo ra bởi Gavin Wood.

  • Vyper

Một ngôn ngữ được phát triển gần đây, tương tự Serpent với cú pháp giống Python, hướng đến sự gần gũi với Python hơn là Serpent nhưng không phải để thay thế Serpent. Nó lại được tạo ra bởi Vitalik Buterin.

  • Bamboo

Một ngôn ngữ mới được phát triển, chịu ảnh hưởng bởi Erlang với explicit state transistions và không có các luồng lặp. Nó hướng tới việc giảm side effect và tăng khả năng audit smart contract. Ngôn ngữ này rất mới và chưa được sử dụng nhiều.

Như các bạn thấy ở trên, có rất nhiều ngôn ngữ để bạn lựa chọn viết smart contract tuy nhiên do Solidity là ngôn ngữ phổ biến nhất và mình cũng sử dụng ngôn ngữ này nên trong phần tiếp theo của bài viết, chúng ta sẽ đề cập đến ngôn ngữ này.

Xây dựng smart contract với Solidity

alt text
Khái niệm trên Wikipedia

Solidity is a "contract-oriented" programming language for writing smart contracts. It is used for implementing smart contracts on various blockchain platforms. It was developed by Gavin Wood, Christian Reitwiessner, Alex Beregszaszi, Liana Husikyan, Yoichi Hirai and several former Ethereum core contributors to enable writing smart contracts on blockchain platforms such as Ethereum.

Solidity được phát triển và hiện đang được duy trì bởi một nhóm các nhà phát triển. Chi tiết tham khảo link github.
Sản phẩm chính của dự án solidity là Solidity Compiler (solc) dùng để compile mã solidity sang EVM bytecode hoặc ABI (Application Binary Interface).

Download and install

Với bất kì ngôn ngữ biên dịch nào, việc đầu tiên chúng ta cần làm là cài đặt trình biên dịch.
Cài đặt solc trên ubuntu:
$ sudo add-apt-repository ppa:ethereum/ethereum
$ sudo apt update
$ sudo apt install solc
KIểm tra version:
$ solc --version
solc, the solidity compiler commandline interface
Version: 0.4.21+commit.dfe3193c.Linux.g++

Development environment

Trong phạm vi bài viết mình sử dụng Visual Studio Code editor và solc command-line.

Hello world program

Và đây là chương trình hello world thần thánh :v
pragma solidity ^0.4.21;
contract HelloWorld {
}

Trong đoạn chương trình trên "pragma solidity ^0.4.21" là 1 chỉ thị version của trình biên dịch solidity cho smart contract.
Bác nào từng làm việc với C++ thì chẳng xa lạ gì với từ khóa này. Cụ thể khi compile HelloWorld contract ở trên, trình biên dịch sẽ báo lỗi nếu version compiler là trước 0.4.21 và từ 0.5.0 trở đi (do số thứ 3 thay đổi theo các bản vá, số thứ 2 đại diện cho các thay đổi lớn và có thể dẫn đến sự khác biệt lớn giữa các version) .

Using Solidity

Chúng ta thường thấy các mẩu quảng cáo trên truyền hình với đoạn kết: "Đọc kĩ hướng dẫn sử dụng trước khi dùng". Solidity là 1 thuốc thử liều cao với những khái niệm và tư duy hoàn toàn mới trong programing. Nó phát triển khá nhanh vậy nên cách tốt nhất là các bạn nên đọc hết toàn bộ phần tài liệu về ngôn ngữ này ở đây:
https://solidity.readthedocs.io/en/latest/
Bài viết này của mình chỉ tóm tắt những điểm cơ bản của ngôn ngữ này. Thực ra mình cũng không có thời gian để viết lại toàn bộ và cũng không có hứng thú khi viết về cú pháp của một ngôn ngữ lập trình (có tài liệu rồi thì viết lại làm gì =)) ). Mình nêu ra các khía cạnh của ngôn ngữ này chỉ nhằm mục đích duy nhất là các bạn có thể theo dõi các bài viết sau thôi :v

Data types

1 số kiểu dữ liệu cơ bản trong solidity:

boolean (bool):

true hoặc false, toán tử có thể sử dụng ! (not), && (and), || (or), == (equal), != (not equal).

integer (int/uint)uin

Từ int8/uint8 (8 bit) đến int256/uint256 (256 bit) với số bit là bội của 8. Nếu viết uint/int thì trình biên dịch sẽ mặc định hiểu là uint256/int256.

fixed point (fixed/ufixed)

Chưa support hoàn toàn ở thời điểm hiện tại.

address

Kích thước 20 byte, dùng để lưu thông tin ethereum address.

byte array (fixed)

byte1, byte2, byte3 ... byte32.

byte array (dynamic)

Dynamic size arrays of bytes, được định nghĩ kiểu bytes hoặc string.

enum

struct

mapping

Cặp key => value, tương tự std::map trong C++.

time units

seconds, minutes, hours, days, weeks, years. 1 years = 365 days.

ether units

wei, finney, szabo and ether.

Contract definition

Trong Solidity mọi thứ đều xoanh quanh hợp đồng, cũng tương tự như các ngôn ngữ hướng đối tượng (đối tượng cụ thể ở đây là hợp đồng). Tương như lý thuyết về OOP thì trong Contract cũng bao gồm thuộc tính (state variables) và các phương thức (methods). Ngoài khái niệm Contract, Solidity cũng cung cấp 2 đối tượng khác tương tự Contract bao gồm:

interface

Đặc tả cấu trúc của hợp đồng, bao gồm các hàm mà không có thân hàm, không xa lạ với giới lập trình viên nên có lẽ không cần giải thích nhiều.

library

Deploy 1 lần và được sử dụng bởi các hợp đồng khác thông qua DELEGATECALL.

Thuộc tính

Ví dụ:
contract A {
mapping (uint => address) public data
}
Mức độ truy cập public, private, internal (không có external).
Trong Contract A ở trên data là 1 state variable, mức độ truy cập public, mặc định solidity sẽ tạo 1 getter function data() trả về data (không bao giờ truy cập trực tiếp được vào thuộc tính).
Các vùng lưu trữ có storage, memory, calldata.

Phương thức

Các hàm được định nghĩa với cú pháp như sau:
function FunctionName([parameters]) [public|private|internal|external] [pure|constant|view|payable] [modifiers] [returns (<return types>)] {
// define
}

Ví dụ 1 function:
function buyToken(address _beneficiary) public payable {
}

FunctionName

Tên function, được sử dụng để gọi từ 1 transaction, 1 hợp đồng khác hoặc trong cùng 1 hợp đồng.

parameters

public

Đại diện cho mức độ truy cập, có thể gọi hàm từ trong hoặc ngoài hợp đồng (internal hoặc external).

external

Giống public nhưng nếu muốn gọi từ bên trong hợp đồng phải dùng từ khóa this.

internal

Chỉ có thể gọi từ bên trong hợp đồng và các hợp đồng kế thừa nó.

private

Chỉ có thể gọi từ chính hợp đồng đó.

Chú ý: Tất cả các từ khóa trên chỉ ảnh hưởng đến khả năng gọi hàm, bất kì dữ liệu hoặc hàm nào trong hợp đồng đều hiển thị trên blockchain công khai (kể cả private cũng được nhìn thấy).

constant/view

Hàm không thay đổi trạng thái của hợp đồng. Các hành động sau đây được coi là làm thay đổi trạng thái của hợp đồng:

  • Writing to state variables.
  • Emitting events.
  • Creating other contracts.
  • Using selfdestruct.
  • Sending Ether via calls.
  • Calling any function not marked view or pure.
  • Using low-level calls.
  • Using inline assembly that contains certain opcodes.

Từ khóa constant alias tới view (dự kiến support từ bản 0.5.0).

pure

Hàm không đọc hoặc thay đổi trạng thái của hợp đồng. Các hành động sau sẽ vi phạm định nghĩa pure function:

  • Reading from state variables.
  • Accessing this.balance or .balance.
  • Accessing any of the members of block, tx, msg (with the exception of msg.sig and msg.data).
  • Calling any function not marked pure.
  • Using inline assembly that contains certain opcodes.

payable

Hàm chấp nhận nhận ether. Các hàm không phải payable sẽ từ chối các khoản thanh toán, trừ khi chúng bắt nguồn từ coinbase hoặc đích đến của SELFDESTRUCT. Trong những trường hợp này, một Contract không thể ngăn chặn các khoản thành toán đến (do thiết kế của EVM).

Fallback function

Hàm không có tên hàm, không có tham số truyền vào và cũng không có giá trị trả về. Hàm này được thực thi khi không có hàm nào khớp với lời gọi hàm đến contract. Thường được sử dụng khi gửi ether đến Contract (không gọi hàm nào), để nhận ether thì các phương thức này được đánh dấu là payable.
Ví dụ:
function () public payable {
// buy token
buyTokens(msg.sender);
}

Function modifiers

Dùng kể kiểm soát các hành vi của hàm. Ví dụ:
modifier onlyOwner {
require(msg.sender == owner);
_ ;
}
function destroy() public onlyOwner {
selfdestruct(owner);
}

Trong đoạn code trên, phần thân hàm của destroy() sẽ được mở rộng bằng thân hàm của modifier, kí tự _ sẽ là phần khai báo thân hàm của function destroy(). Nội dung hàm destroy bây giờ sẽ được hiểu như thế này:
function destroy() public onlyOwner {
require(msg.sender == owner);
selfdestruct(owner);
}

Chú ý việc đặt vị trí của kí tự _ trong modifier sẽ ảnh hưởng đến hàm sử dụng nó.

contructor và selfdestruct

Cú pháp khai báo contructor:
contructor() {
// define contructor
}

Cú pháp này support từ v0.4.22, các version sớm hơn thì khai báo contructor như khai báo function có tên trùng với Contract.
Hàm hủy thì ta có thể xem ở ngay phần bên trên, khi gọi selfdestruct, hợp đồng sẽ bị hủy.

Ngoài ra Solidty cũng support overload.

Tính kế thừa của Contract

Solidity hỗ trợ đa kế thừa. Cú pháp:
contract Children is Parent1, Parent2 {
}

Thứ tự kế thừa là quan trọng trong Solidity, như khai báo ở trên Parent2 sẽ override Parent1.
Trong Solidity cũng có khái niệm abstract contract. có ít nhất 1 phương thức chưa được định nghĩa. Các contract kế thừa nó phải định nghĩa những phương thức này. Do support đa kế thừa nên Solidity cũng mắc phải diamond problem:
alt text
Solidity sử dụng thuật toán "C3 Linearization" để giải quyết vấn đề này.

Event

Solidity support khái niệm event. Chắc cũng ko xa lạ với giới lập trình nên mình không giải thích nhiều. Sử dụng emit để bắn event sẽ clear hơn và phân biệt event với lời gọi hàm. Chú ý event không có thân hàm và được handle thông qua thư viện web3.js.

Error handling

Support assert, require and revert.

Others

Ban đầu mình định viết khá nhiều thứ về solidity nhưng nhận thấy có viết cả ngày cũng không hết được nên mình khuyên các bạn nên đọc toàn bộ Solidity Doc.

Lời kết

Cảm ơn các bạn đã đọc đến đây, sẽ có nhiều bạn hẳn khá bổi rối là viết xong smart contract thì hình thù nó như thế nào? test nó kiểu gì? deploy như thế nào ? ... và cái các bạn mong đợi là 1 cái nhìn trực quan. Vậy thì còn chần chừ gì nữa, hãy nhanh tay follow để theo dõi các loạt bài tiếp theo của mình :v

Tài liệu tham khảo

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

Lưu Xuân Trọng

2 bài viết.
9 người follow
Kipalog
{{userFollowed ? 'Following' : 'Follow'}}
Cùng một tác giả
White
12 4
Lời nói đầu Trong thời gian qua, với cơn sốt về giá trị của các đồng tiền ảo mà nổi bật là Bitcoin, chắc chẳn mọi người cũng dần quen thuộc với thu...
Lưu Xuân Trọng viết hơn 1 năm trước
12 4
Bài viết liên quan
White
11 5
Tạm xóa
Giaosucan viết hơn 1 năm trước
11 5
White
10 2
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...
Trần Mỹ viết hơn 1 năm trước
10 2
{{like_count}}

kipalog

{{ comment_count }}

bình luận

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


White
{{userFollowed ? 'Following' : 'Follow'}}
2 bài viết.
9 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á!