LapTrinhBlockchain

Chia sẻ kiến thức về Lập Trình Blockchain

Kiến thức lập trình, Lập trình Blockchain, Lập trình Công cụ, Lập trình NodeJs

Tìm hiểu lập trình trên Hedera, một số vấn đề mà Dev quen Ethereum gặp phải

Chia sẻ bài viết
0
(0)

Hedera được đánh giá là một trong những nền tảng DLT (Distributed Ledger Technology) tiên tiến nhất, được quản lý bởi Hội đồng quản trị Hedera – gồm các tập đoàn và tổ chức lớn trên toàn cầu. Điểm đặc biệt của Hedera là việc sử dụng thuật toán đồng thuận độc quyền mang tên Hashgraph, mang lại khả năng mở rộng vượt trội, tốc độ nhanh chóng và tính minh bạch.

Gần đây tôi chú ý tới mạng lưới Hedera này và bắt đầu tìm hiểu. Tôi quen làm việc với các blockchain dạng EVM giống như Ethereum hơn, khi sang mạng Hedera, mặc dù có hỗ trợ EVM nhưng có nhiều chỗ vướng mắc cần phải chú ý.

Tìm hiểu về Hedera

Đầu tiên chúng ta tìm hiểu sơ bộ về Hedera trước khi đi sâu hơn về mảng lập trình để tương tác với blockchain này.

Hedera là gì?

Hedera là một mạng sổ cái phân tán công khai (public distributed ledger) sử dụng thuật toán đồng thuận Hashgraph, không phải blockchain truyền thống. Điểm cốt lõi:

  • Không dùng cấu trúc block nối chuỗi mà theo cấu trúc DAG
  • Không cần miner.
  • Đồng thuận dựa trên cơ chế gossip about gossip + virtual voting.
  • Token gốc: HBAR.
  • Được quản trị bởi Governing Council gồm các tập đoàn lớn (Google, IBM, Boeing, LG, v.v.).

Một số thông số kỹ thuật nổi bật của dự án:

  • Cơ chế đồng thuận (Consensus): Hashgraph (aBFT)
  • Trạng thái cuối cùng (Finality): ~3-5 giây
  • TPS lý thuyết: 10,000+
  • Năng lượng tiêu thụ: Rất thấp
  • Smart contract: EVM compatiable
  • Cấu trúc: DAG (Không phải dạng chain)

Mặc dù dự án đã có từ lâu với FDV hơn $4.4B nhưng kiểm tra hệ sinh thái Defi qua Defillama thấy khá nhỏ với TVL chỉ có khoảng $56M. Mặc dù vậy Hedera có điểm mạnh riêng so với các blockchain khác thì:

  • Bitcoin ưu tiên bao mật và phi tập trung tuyệt đối
  • Ethereum thì mạnh về hệ sinh thái
  • Solana thiên về DeFi tốc độ cao
  • Aptos/Sui thì tập trung vào thực thi hợp đồng thông minh có khả năng mở rộng
  • Còn Hedera thì tập trung vào kết quả lớp đồng thuận mạng, tập trung vào hiệu năng cao với chi phí thấp, tập trung vào quản trị có kiểm soát do đó dễ tiếp cập với các doanh nghiệp.

Hedera cũng có nhiều nhược điểm như Quản trị tập trung, không mở hoàn toàn như Ethereum, hệ sinh thái Defi rất yếu.

Cơ chế hoạt động của Hashgraph

Chúng ta đi sâu hơn cơ chế của Hashgraph. Chúng ta đi vào một số vấn đề như sau:

Cấu trúc dữ liệu: Event DAG

Hashgraph không tạo block. Thay vào đó, mỗi node tạo ra một event. Một event gồm:

  • Danh sách transaction
  • Hash của event trước đó do chính node tạo (self-parent)
  • Hash của event gần nhất nó nhận từ node khác (other-parent)
  • Timestamp

Vì mỗi event trỏ đến 2 event trước → tạo thành một Directed Acyclic Graph (DAG). Do đó mà: Không có chuỗi block, Không có miner leader, Không có block proposal.

Gossip About Gossip

Hedera có cơ chế lan truyền dữ liệu như sau:

  1. Node A chọn ngẫu nhiên node B
  2. A gửi cho B:
    • Các transaction chưa biết
    • Toàn bộ metadata về ai đã nói chuyện với ai

Vì mỗi event có thông tin self-parent và other-parent nên toàn bộ lịch sử lan truyền được mã hóa trong DAG.

Điều đặc biệt: Mỗi node cuối cùng sẽ có cùng một DAG đầy đủ (trừ khi có Byzantine).

Virtual Voting

Đây là điểm sáng tạo nhất của Hedera. Trong blockchain truyền thống Node phải gửi vote thật nên tốn băng thông mạng và cần nhiều thông điệp hơn bình thường với message complexity O(n²). Trong Hashgraph, vì mọi node đều biết toàn bộ DAG, nên họ có thể tự mô phỏng việc vote của node khác, mà không cần gửi vote thật.

Cách xác định thư tự: Hashgraph chia event thành:

  • Bước 1: Chia Round
    Một event thuộc round R nếu nó “strongly sees” ≥ 2/3 node của round trước . “Strongly see” = có đường đi trong DAG đến event của node đó.
  • Bước 2: Xác định Famous Witness
    Witness = event đầu tiên của một node trong round. Nodes sẽ “vote ảo” để xác định witness nào là famous. Toàn bộ quá trình diễn ra mà không gửi vote thực tế. Quy trình:
    • Round r witness vote cho round r-1 witness
    • Vote được truyền qua các round tiếp theo
    • Khi ≥ 2/3 đồng thuận → witness được đánh dấu famous
  • Bước 3: Finality
    Khi một event được Seen bởi đủ famous witness → Nó được consensus timestamp → Thứ tự được chốt vĩnh viễn → Không fork → Xác định trạng thái Finality

Phân tích độ phức tạp và hiệu năng

Chúng ta sẽ đánh giá ở một số tiêu chí như sau:

  • Message complexity
    • Traditional BFT: O(n²) message voting
    • Hashgraph: Chỉ O(n log n) do gossip random
  • Latency
    • Thường 3–5 giây
    • Phụ thuộc tốc độ gossip lan toàn mạng
  • Throughput
    • Cao vì:
      • Không có block size bottleneck
      • Không có leader serialization
    • Nhưng:
      • Execution layer không song song mạnh như Solana/Aptos
      • Smart contract vẫn EVM-based
    • Hedera có cơ chế Consensus nhanh nhưng không đồng nghĩa với execution nhanh.

So sánh kiến trúc với Blockchain truyền thống

Thành phầnBlockchainHashgraph
Data structureChainDAG
BlockCóKhông
LeaderCóKhông
Vote messageCóKhông
ForkCó thểKhông
FinalityProbabilistic / deterministicDeterministic

Điểm yếu kỹ thuật của Hashgraph

  1. Toàn bộ node phải giữ toàn bộ DAG => Do đó bộ nhớ tăng nhanh và không dễ cho việc sharding
  2. Không thực sự permissionless => Khi có số lượng node tham gia lớn (Chẳng hạn 10,000 nodes) thì Gossip complexity sẽ bùng nổ => Nên Hedera phải dùng mô hình Council.
  3. Không tối ưu cho MEV & DeFi: Nguyên nhân là bởi
    • Thứ tự giao dịch phụ thuộc timestamp trung bình
    • Không có cơ chế builder / proposer
    • Nên với arbitrage tốc độ cao thì Hashgraph không phải là môi trường tối ưu => Tay to không có lợi thế thì nhỏ lẻ có cơ hội

Một số điểm lưu ý khi bắt đầu lập trình tương tác với mạng Hedera

Cần hiểu rõ bạn đang dùng lớp nào của Hedera

Hedera có 3 lớp dịch vụ chính:

  1. Hedera Token Service (HTS)
  2. Hedera Consensus Service (HCS)
  3. Smart Contract Service (EVM)

Nhiều dev bên Ethereum vào Hedera và chỉ dùng Smart Contract, bỏ qua HTS, trong khi HTS nhanh hơn, rẻ hơn và chuẩn hơn. Ví dụ:

  • Mint token → Fùng HTS tốt hơn ERC-20
  • NFT → HTS native NFT tốt hơn ERC-721

Mô hình tài khoản khác Ethereum

Hedera có mô hình tài khoản (Account Model) khác so với Ethereum. Cụ thể:

  • Trên Ethereum:
    • Account = address
    • Có private key
  • Trên Hedera:
    • Account ID dạng: 0.0.x
    • Key structure có thể phức tạp:
      • Multi-key
      • Threshold key
      • Key list

Tức là:

  • Quản lý khóa (Key management) phức tạp hơn
  • Phân quyền có thể thiết kế ngay từ account layer
  • Phí và signature khác EVM

Phí giao dịch

Cơ chế phí trên Hedera và Ethereum cũng khác nhau. Cụ thể:

  • Ethereum: Cơ chế đấu giá Gas (Gas auction) => Phí biến động
  • Hedera: Phí cố định (Dựa theo USD) => Phí này thấp

Đây là điểm quan trọng khi cần xây dựng bot.

Smart Contract Execution giới hạn gì?

Mặc dù EVM compatible, nhưng:

  • Không phải mọi opcode đều tối ưu
  • Không có ecosystem tooling phong phú như Ethereum
  • Debug tool còn hạn chế
  • Không có Foundry-level maturity

Do đó chúng ta cần:

  • Test kỹ trên testnet
  • Kiểm tra compatibility library
  • Không giả định mọi thứ giống Ethereum

State & Storage Cost

Hedera tính phí storage khác Ethereum. Trên Ethereum, nơi gas storage rất đắt đỏ, nếu bạn lưu nhiều dữ liệu on-chain, thiết kế contract phức tạp thì cần tối ưu state size. Hedera rẻ nhưng vẫn nên tối ưu.

Một số điểm cần lưu ý với Hedera EVM

Trước đây tôi làm việc nhiều với Evm, và khi làm việc với Hedera Evm, tôi thấy có một số điểm khác có thể ảnh hưởng để nghiệp vụ của bạn:

  • Vấn đề trùng nonce: Trên Evm sẽ không bao giờ có 2 giao dịch trùng nonce, nhưng trên Hedera Evm thì có thể. Ví dụ hai giao dịch sau đều cùng 1 Ethereum Nonce 709: 0.0.995584@1772215243.223562314 và 0.0.995584@1772215267.134637524 => Tôi không để ý vấn đề này dẫn đến xử lý sai gây ra hiện tượng lặp transaction.
  • Vấn đề cấp quyền sử dụng token cho một spender: Trên Hedera Evm, bạn không thể cấp quyền sử dụng lượng không giới hạn (Unlimited) cho một spender, mà bạn chỉ có thế cấp quyền với số lượng tối đa bằng tổng cung của token đó => Bạn không để ý vấn đề này bạn sẽ mất nhiều phí để thực hiện cấp quyền mà không hiểu sao giao dịch cứ lỗi hoài.
  • Việc ánh xa account EVM sang account trên Hedera: Hedera có EVM, nhưng account model KHÔNG giống Ethereum. Account trên Hedera có dạng 0.0.x trong khi đó account EVM có dạng 0xabc nên để dùng được account EVM trên mạng lưới Hedera ta phải thực hiện ánh xạ EVM account sang Hedera account.
  • Chú ý trường value thực hiện giao dịch Hedera Evm: Như chúng ta biết thì HBAR có decimals=8 trong khi trên Evm thì đơn vị nhỏ nhất là wei ứng với ETH có decimals=18 => Do đó khi truyền lượng ví dụ 1.5 HBAR thông qua trường value thì bạn phải sử dụng 1.5*10^18 chứ không phải 1.5*10^8

Lập trình tương tác với mạng Hedera gốc

Chi tiết bạn nên đọc tài liệu chính thức của Hedera “Hedera Native Developers“, Hedera Playground và một số ví dụ mẫu trên Hedera. Để lập trình tương tác với mạng Hedera gốc, chúng ta sẽ sử dụng Hedera SDK, SDK này hỗ trợ các ngôn ngữ: Java, Javascript và Go. Trong bài viết này tôi sử dụng Hedera SDK với ngôn ngữ Javascript thông qua thư viện @hashgraph/sdk.

Tài khoản Operator: Tài khoản để thực hiện giao dịch

Đầu tiên chúng ta cần phải có một tài khoản Hedera trước đã. Chúng ta nên sử dụng ví HashPack dể tạo tài khoản trên mạng lưới Hedera gốc, nhớ tạo một tài khoản trên Testnet và một tài khoản trên Mainnet để tiện cho việc thao tác.

Sau khi có tài khoản thì chúng ta cần có một ít token HBAR để có thể bắtđầu thực hiện thao tác:

  • Trên Testnet: Vào trang Hedera Faucet để nhận 100 HBAR mỗi ngày, hỗ trợ cả địa chỉ Hedera gốc và địa chỉ dạng EVM. Nếu bạn cần số lượng HBAR lớn bạn có thể đăng ký qua trang https://portal.hedera.com/register
  • Trên Mainnet:
    • Cách đơn giản nhất là mua một ít HBAR trên các sàn tập trung như Binance, Mexc, Bybit, Okx… rồi rút về địa chỉ đã tạo ở trên.
    • Nếu bạn có ví ethereum với điểm trên Human Passport trên 20 điểm, thì bạn có thể vào trang này https://faucet.hashport.network, rồi nhập địa chỉ ví Ethereum, đâu đó được nhận 2 HBAR thì phải.

Bây giờ chúng ta lấy địa chỉ và private key của tài khoản, lưu vào tệp .env với nội dung tin như sau:

OPERATOR_ACCOUNT_ID = 0.0.xxxxxxxx
OPERATOR_PRIVATE_KEY = yyyyyyyyyyyyyyyyyyyyyyyyy

Nhớ ưu tiên sử dụng tài khoản Testnet trước cho an toàn. Khi mọi thứ chạy hoàn hảo trên Testnet hãy chuyển sang sử dụng tài khoản Mainnet.

Tạo đối tượng Client: Đối tượng cơ bản sử dụng cho tất cả các thao tác sau này

Bây giờ chúng ta sẽ tạo đối tượng Client, đối tượng này nắm giữ tài khoản operator. Mã nguồn được đóng gói trong hàm initClient() để tái sử dụng trong các phần tiếp theo:

require('dotenv').config();
const hashgraph = require("@hashgraph/sdk");

function initClient(useForMainnet=false) {
    let client = null;
    if (useForMainnet) client = hashgraph.Client.forMainnet();
    else client = hashgraph.Client.forTestnet();
    let operatorAccountId = hashgraph.AccountId.fromString(process.env.OPERATOR_ACCOUNT_ID);
    let operatorAccountPk = hashgraph.PrivateKey.fromString(process.env.OPERATOR_PRIVATE_KEY);
    client.setOperator(operatorAccountId, operatorAccountPk);
    return client;
}

Hiển thị thông tin tài khoản và số dư tài khoản

Phần này chúng ta sẽ hiển thị thông tin tài khoản bao gồm địa chỉ evm, số dư HBAR và số dư các token khác.

// ...

// Show account info
async function showAccountInfo(client, accountId) {
    const accountInfo =  await new hashgraph.AccountInfoQuery()
        .setAccountId(accountId)
        .execute(client);
    console.log("Account Info:");
    console.log(`    AccountId  : ${accountId.toString()}`);
    console.log(`    Evm Address: 0x${accountInfo.contractAccountId}`);
    console.log(`    HBAR Balance: ${accountInfo.balance.toString()}`);
    console.log(`    Account Memo: ${accountInfo.accountMemo}`);
    console.log(`    Owned Nfts: ${accountInfo.ownedNfts.toString()}`);
    console.log(`    Ethereum Nonce: ${accountInfo.ethereumNonce.toString()}`);
    console.log(`    ...`);
}

async function showAccountBalance(client, accountId) {
    let balanceInfo = await new hashgraph.AccountBalanceQuery()
        .setAccountId(accountId)
        .execute(client);
    console.log("Balance Info:");
    console.log(`    AccountId  : ${accountId.toString()}`);
    console.log(`    HBAR Balance: ${balanceInfo.hbars.toString()}`);
    let tokens = JSON.parse(balanceInfo.tokens.toString());
    let tokenIds = Object.keys(tokens);
    console.log(`    Tokens Balance (${tokenIds.length})`);
    tokenIds.forEach(tokenId => {
        let tokenBalance = balanceInfo.tokens.get(tokenId);
        let tokenDecimals = balanceInfo.tokenDecimals.get(tokenId);
        let balance = Number(tokenBalance.toString())/10**Number(tokenDecimals.toString());
        console.log(`        ${tokenId}: ${balance}`);
    });
}

// Test function
async function test() {
    let client = initClient();
    await showAccountInfo(client, "0.0.1293");
    await showAccountBalance(client, "0.0.1293");
}
test();

Kết quả hiển thị như sau:

Bài viết này có hữu ích với bạn?

Kích vào một biểu tượng ngôi sao để đánh giá bài viết!

Xếp hạng trung bình 0 / 5. Số phiếu: 0

Bài viết chưa có đánh giá! Hãy là người đầu tiên đánh giá bài viết này.

Trả lời

Giao diện bởi Anders Norén