Hướng dẫn lập trình Smart Contract cơ bản trên nền tảng Ethereum
Để lập trình smart contract trên Ethereum, bạn cần hiểu ba lớp kiến thức: nền tảng Ethereum hoạt động thế nào (EVM, tài khoản, giao dịch, gas), ngôn ngữ Solidity dùng để viết hợp đồng, và các chuẩn chung như ERC-20, ERC-721 mà hệ sinh thái dựa vào. Bài này tập trung vào phần nền tảng và cấu trúc ngôn ngữ, giúp bạn đọc hiểu một hợp đồng trước khi tự tay viết. Phần thực hành từng bước được trình bày trong bài thực hành viết và triển khai smart contract đầu tiên.
Smart contract là gì, theo nghĩa kỹ thuật
Smart contract là chương trình được lưu và chạy trên blockchain. Trên Ethereum, nó là một tài khoản đặc biệt có mã (bytecode) và vùng lưu trữ riêng. Bất kỳ ai cũng có thể gửi giao dịch gọi hàm của hợp đồng; mọi nút trong mạng chạy cùng đoạn mã đó và phải đi đến cùng kết quả. Vì vậy smart contract có tính tất định: không đọc file, không gọi API Internet, không có số ngẫu nhiên thật. Dữ liệu bên ngoài phải được đưa vào qua oracle.
Gọi là "hợp đồng" vì nó thực thi các điều khoản một cách tự động: nếu điều kiện A thỏa thì chuyển tài sản B, mà không cần bên trung gian tin cậy.
Ethereum Virtual Machine (EVM)
EVM là máy ảo thực thi bytecode của hợp đồng. Mã Solidity được trình biên dịch thành bytecode EVM trước khi triển khai. Nhiều blockchain khác như BNB Chain, Polygon PoS, Avalanche C-Chain và hầu hết mạng Layer 2 của Ethereum đều tương thích EVM, nên kiến thức bạn học có thể dùng trên nhiều mạng.
Hai loại tài khoản
| Loại | Điều khiển bởi | Có mã | Khởi tạo giao dịch |
|---|---|---|---|
| Tài khoản sở hữu bên ngoài (EOA) | Khóa riêng của người dùng | Không | Có |
| Tài khoản hợp đồng | Mã của chính nó | Có | Không tự khởi tạo, chỉ phản hồi khi được gọi |
Mọi chuỗi hành động trên Ethereum đều bắt đầu từ một giao dịch do EOA ký. Hợp đồng có thể gọi hợp đồng khác trong quá trình xử lý, nhưng không tự "thức dậy". Chuẩn account abstraction như ERC-4337 đang làm mờ ranh giới này bằng ví hợp đồng thông minh, nhưng nguyên tắc cơ bản vẫn giữ nguyên.
Gas: chi phí của tính toán
Mỗi phép toán trong EVM tiêu tốn một lượng gas cố định. Người gửi giao dịch trả phí bằng ETH tương ứng với lượng gas đã dùng nhân với giá gas. Từ nâng cấp London (EIP-1559), phí gồm phí cơ bản bị đốt và phí ưu tiên trả cho người xác thực. Gas có hai vai trò: ngăn vòng lặp vô hạn làm tắc mạng và định giá tài nguyên tính toán.
Với lập trình viên, gas ảnh hưởng trực tiếp đến thiết kế. Ghi vào bộ nhớ lưu trữ (storage) là thao tác đắt nhất; đọc rẻ hơn ghi; tính toán trong bộ nhớ tạm (memory) rẻ hơn nhiều. Vì vậy hợp đồng tốt chỉ lưu trên chuỗi những gì thật sự cần. Đây cũng là lý do các giải pháp mở rộng được phát triển, như phân tích trong bài giải pháp Layer 2.
Cấu trúc một hợp đồng Solidity
Một file Solidity thường gồm các phần sau, theo thứ tự:
- Giấy phép: dòng chú thích SPDX khai báo giấy phép mã nguồn, ví dụ MIT.
- Pragma: khai báo phiên bản trình biên dịch, ví dụ pragma solidity ^0.8.20. Nên dùng phiên bản 0.8 trở lên để có kiểm tra tràn số tự động.
- Import: nhập thư viện như OpenZeppelin.
- Khai báo contract: tương tự khai báo lớp trong lập trình hướng đối tượng, có thể kế thừa hợp đồng khác.
- Biến trạng thái: dữ liệu lưu vĩnh viễn trên chuỗi.
- Sự kiện (event): nhật ký phát ra để ứng dụng bên ngoài theo dõi.
- Modifier: điều kiện dùng lại được gắn vào hàm, ví dụ chỉ chủ sở hữu.
- Constructor: chạy một lần khi triển khai.
- Hàm: logic chính.
Những khái niệm Solidity cần nắm
Kiểu dữ liệu
- uint256, int256: số nguyên không dấu và có dấu. Solidity không có số thực; tiền tệ được biểu diễn bằng đơn vị nhỏ nhất (wei với ETH, 1 ETH bằng 10^18 wei).
- address: địa chỉ 20 byte của tài khoản.
- bool, bytes32, string.
- mapping: bảng băm khóa-giá trị, ví dụ ánh xạ địa chỉ sang số dư. Không duyệt được danh sách khóa.
- struct và mảng.
Vị trí dữ liệu
storage là dữ liệu lưu vĩnh viễn, memory là dữ liệu tạm trong một lần gọi, calldata là dữ liệu đầu vào chỉ đọc. Chọn sai vị trí ảnh hưởng cả chi phí lẫn tính đúng đắn.
Phạm vi hiển thị của hàm
public gọi được từ mọi nơi, external chỉ gọi từ bên ngoài, internal trong hợp đồng và hợp đồng con, private chỉ trong hợp đồng. Lưu ý "private" chỉ giới hạn truy cập từ mã; dữ liệu trên blockchain vẫn có thể đọc được bởi bất kỳ ai.
Bộ chỉ định trạng thái
Hàm view chỉ đọc trạng thái, pure không đọc không ghi; gọi chúng từ bên ngoài không tốn phí giao dịch. Hàm payable mới nhận được ETH kèm theo.
Biến toàn cục
msg.sender là địa chỉ gọi hàm, msg.value là lượng ETH gửi kèm, block.timestamp là thời gian của khối. Tránh dùng tx.origin để xác thực vì dễ bị lừa qua hợp đồng trung gian.
Xử lý lỗi
require kiểm tra điều kiện đầu vào và hoàn tác giao dịch nếu sai; revert kèm custom error giúp tiết kiệm gas và rõ nghĩa; assert dùng cho bất biến nội bộ không bao giờ được sai. Khi giao dịch bị hoàn tác, mọi thay đổi trạng thái bị hủy nhưng gas đã dùng vẫn mất.
Các chuẩn ERC quan trọng
- ERC-20: token có thể thay thế, gồm các hàm như chuyển, cấp quyền chi tiêu, truy vấn số dư.
- ERC-721: token không thể thay thế (NFT), mỗi token có định danh riêng.
- ERC-1155: chuẩn đa token, quản lý nhiều loại token trong một hợp đồng.
Tuân theo chuẩn giúp hợp đồng của bạn tương thích với ví, sàn và ứng dụng khác. Bạn có thể xem cách ERC-721 được dùng trong thực tế ở bài NFT là gì và cách tạo, giao dịch.
Vòng đời của hợp đồng
- Viết mã Solidity và kiểm thử cục bộ.
- Biên dịch thành bytecode và ABI (mô tả giao diện để ứng dụng gọi hàm).
- Triển khai bằng một giao dịch đặc biệt; hợp đồng nhận một địa chỉ.
- Xác minh mã nguồn trên trình khám phá khối để người dùng đọc được.
- Người dùng và ứng dụng tương tác qua ABI.
Sau khi triển khai, mã không thể sửa. Muốn thay đổi logic, bạn phải triển khai hợp đồng mới hoặc thiết kế sẵn mẫu proxy nâng cấp được, kèm theo rủi ro riêng.
Lộ trình học gợi ý
- Nắm khái niệm blockchain và Ethereum ở mức người dùng: ví, giao dịch, phí gas, mạng thử nghiệm.
- Học cú pháp Solidity qua tài liệu chính thức và Solidity by Example.
- Đọc mã OpenZeppelin Contracts để học cách viết chuẩn mực.
- Thực hành với Remix, sau đó chuyển sang Hardhat hoặc Foundry.
- Học bảo mật song song, không đợi đến cuối.
Câu hỏi thường gặp
Có cần biết lập trình trước khi học Solidity không?
Nên có nền tảng lập trình cơ bản, nhất là với ngôn ngữ như JavaScript hoặc C-family vì cú pháp Solidity khá giống. Người hoàn toàn mới vẫn học được nhưng sẽ phải học song song cả tư duy lập trình lẫn đặc thù blockchain.
Ngoài Solidity còn ngôn ngữ nào viết smart contract trên Ethereum?
Vyper là ngôn ngữ có cú pháp gần Python, chú trọng sự đơn giản và dễ kiểm tra. Ngoài ra có Yul, ngôn ngữ trung gian cấp thấp dùng để tối ưu. Các blockchain không dùng EVM như Solana dùng Rust, Aptos và Sui dùng Move.
Triển khai smart contract tốn bao nhiêu?
Phí phụ thuộc kích thước và độ phức tạp của hợp đồng cùng giá gas tại thời điểm triển khai, nên biến động rất lớn. Trên mạng thử nghiệm, bạn dùng ETH thử miễn phí; trên mạng Layer 2, chi phí thường thấp hơn nhiều so với mạng chính Ethereum.
Dữ liệu private trong smart contract có bí mật không?
Không. Từ khóa private chỉ ngăn hợp đồng khác truy cập qua mã, còn mọi dữ liệu lưu trên blockchain công khai đều có thể đọc trực tiếp từ storage. Không bao giờ lưu mật khẩu hay thông tin nhạy cảm dạng thô trên chuỗi.
Bài liên quan

Bảo mật Smart Contract: Những lỗ hổng phổ biến cần tránh
Tổng hợp lỗ hổng smart contract phổ biến như reentrancy, kiểm soát truy cập, thao túng oracle, front-running, cùng thực hành phòng tránh và quy trình kiểm toán.

DAO (Decentralized Autonomous Organization) vận hành như thế nào?
DAO vận hành thế nào: smart contract quản trị, token biểu quyết, quy trình đề xuất, kho bạc chung, các mô hình bỏ phiếu, rủi ro và vấn đề pháp lý cần biết.

Hướng dẫn lập trình Smart Contract cơ bản trên Ethereum
Thực hành viết smart contract đầu tiên: dựng môi trường với Remix và Hardhat, viết hợp đồng quỹ đóng góp, kiểm thử, triển khai lên mạng thử nghiệm Sepolia.

Kiến trúc Web3 khác biệt thế nào so với Web2 truyền thống
Web3 thay đổi gì với người dùng so với Web2: danh tính, quyền sở hữu dữ liệu và tài sản, mô hình kinh doanh, trải nghiệm và rủi ro khi tự quản lý ví.