
Lập trình PyCardano: Truy vấn dữ liệu Blockchain – Khám phá UTxO và Tài sản
Chào mừng các bạn quay trở lại với series Lập trình PyCardano! Ở bài viết trước, chúng ta đã tạo thành công một chiếc ví (Wallet) và quản lý Mnemonic an toàn. Tuy nhiên, nếu bây giờ bạn chạy code kiểm tra, kết quả trả về sẽ là một con số 0 tròn trĩnh.
Để bài học hôm nay trở nên thú vị và thực tế hơn, chúng ta sẽ bắt tay vào việc “bơm” một ít tiền thử nghiệm (Test ADA) vào ví, sau đó sử dụng Python để truy vấn trực tiếp dữ liệu từ Blockchain Cardano.
1. Hiểu đúng về mô hình EUTxO trên Cardano
Trước khi đi vào phần code, có một khái niệm nền tảng bạn bắt buộc phải nắm vững. Đây là điểm khác biệt lớn nhất giữa Cardano và Ethereum:
-
Trên Ethereum (Mô hình Account): Khi truy vấn số dư, hệ thống sẽ hỏi: “Ví A đang có tổng cộng bao nhiêu tiền?” (Giống như tài khoản ngân hàng truyền thống).
-
Trên Cardano (Mô hình EUTxO): Câu hỏi đúng phải là: “Ví A đang sở hữu những mảnh UTxO (Unspent Transaction Output) nào?”. Để biết tổng số dư, bạn phải cộng gộp giá trị của tất cả các mảnh UTxO đó lại.
Hãy tưởng tượng UTxO giống như những tờ tiền mặt trong ví của bạn. Bạn có thể có một tờ 50k, hai tờ 20k và một tờ 10k. Tổng tài sản là 100k, nhưng nó được chia thành 4 “mảnh” (UTxO) riêng biệt.
2. Chuẩn bị “Tiền” (Thực hành Faucet)
Để có dữ liệu thực tế truy vấn, chúng ta cần xin một ít tADA (Test ADA) trên mạng thử nghiệm.
-
Truy cập trang Faucet chính thức của Cardano: Cardano Testnet Faucet
-
Copy địa chỉ ví
addr_test...mà bạn đã tạo ở bài học trước. -
Dán vào ô địa chỉ, chọn mạng lưới (ví dụ: Preprod) và yêu cầu nhận Funds.
Lưu ý: Sau khi yêu cầu, hãy chờ khoảng 1-2 phút để giao dịch được mạng lưới xác nhận và đưa vào một Block.
3. Truy vấn UTxO của ví cá nhân bằng PyCardano
Bây giờ, hãy tạo một file Python mới (ví dụ: query_wallet.py) và bắt đầu viết lệnh truy vấn. Chúng ta sẽ sử dụng lại BlockFrostChainContext đã học ở các bài đầu.
from pycardano import BlockFrostChainContext
# 1. Cấu hình Context kết nối với mạng Preprod
project_id = "preprod_your_api_key_here" # Thay bằng API Key của bạn
context = BlockFrostChainContext(
project_id=project_id,
base_url="https://cardano-preprod.blockfrost.io/api"
)
# 2. Định nghĩa địa chỉ ví cần kiểm tra (Ví bạn vừa nhận Faucet)
my_address_str = "addr_test1qyour_address_here..."
# 3. Lệnh truy vấn quan trọng nhất: context.utxos()
print(f"Đang truy vấn dữ liệu từ địa chỉ: {my_address_str[:15]}...")
try:
# Lấy danh sách toàn bộ UTxO mà địa chỉ này đang sở hữu
utxos = context.utxos(my_address_str)
print(f"Tìm thấy {len(utxos)} mảnh UTxO trong ví.")
except Exception as e:
print(f"Lỗi truy vấn: {e}")
Kết quả trả về của hàm context.utxos() là một danh sách (List) các đối tượng UTxO. Mỗi đối tượng sẽ chứa thông tin về Input (Transaction Hash + Index) và Output (Số lượng Lovelace, Token, và Datum nếu có).
4. Xử lý dữ liệu và Tính tổng số dư
Dữ liệu thô trả về là các đối tượng Python phức tạp. Để hiển thị một con số dễ hiểu như “10,000 ADA” cho người dùng, chúng ta cần bóc tách dữ liệu và cộng tổng lại.
Lưu ý: Đơn vị nhỏ nhất trên Cardano là Lovelace. 1 ADA = 1,000,000 Lovelace.
def calculate_total_balance(utxo_list):
total_lovelace = 0
for utxo in utxo_list:
# Bóc tách giá trị coin (Lovelace) bên trong mỗi UTxO
amount = utxo.output.amount.coin
total_lovelace += amount
return total_lovelace
# Tính toán và hiển thị
total_lovelace = calculate_total_balance(utxos)
total_ada = total_lovelace / 1_000_000
print(f"Tổng số dư trong ví: {total_ada} ADA")
(Mẹo: Nếu ví của bạn có chứa NFT hoặc các Native Token khác, chúng sẽ được lưu trữ gọn gàng bên trong thuộc tính utxo.output.amount.multi_asset).
5. Truy vấn UTxO từ địa chỉ Smart Contract
Vậy đối với Smart Contract (Hợp đồng thông minh) thì sao?
Trong kiến trúc Cardano, Smart Contract cũng chỉ là một địa chỉ ví (gọi là Script Address). Tuy nhiên, nó không có Private Key (khóa riêng tư) để ký giao dịch như ví người dùng, mà nó được mở khóa bằng các quy tắc Logic mã hóa bên trong.
Khi truy vấn Smart Contract, chúng ta thường không quan tâm đến “Tổng số dư” của nó, mà quan tâm đến việc tìm đúng mảnh UTxO có chứa Datum (dữ liệu trạng thái của hợp đồng) mà chúng ta muốn tương tác.
# Ví dụ về một Script Address (thường bắt đầu bằng addr_test1wp...)
script_address = "addr_test1wp_your_script_address_here..."
# Cách truy vấn hoàn toàn tương tự ví thường
script_utxos = context.utxos(script_address)
print("-" * 30)
print(f"Script này đang nắm giữ {len(script_utxos)} UTxO")
# Duyệt qua danh sách để kiểm tra Datum
for i, utxo in enumerate(script_utxos):
coin_amount = utxo.output.amount.coin
print(f"UTxO #{i}: {coin_amount} Lovelace")
# Kiểm tra xem UTxO này có đính kèm Datum hay không
if utxo.output.datum:
print(f" -> Có chứa Datum (Dữ liệu trạng thái hợp đồng)!")
elif utxo.output.datum_hash:
print(f" -> Có chứa Datum Hash!")
else:
print(f" -> Không có Datum.")
6. Tổng kết và Bài tập thực hành
Tóm tắt kiến thức:
-
Hàm
context.utxos(address)là “chìa khóa” để truy vấn dữ liệu cho cả ví cá nhân và ví hợp đồng. -
Số dư của một ví bằng tổng số Lovelace nằm trong tất cả các UTxO cộng lại.
-
UTxO nằm tại địa chỉ Smart Contract thường đi kèm với Datum để lưu trữ trạng thái.
Bài tập thực hành dành cho bạn: Hãy lên trang Faucet và xin tiền (test ADA) thêm 1 lần nữa vào cùng một địa chỉ ví. Sau đó, chạy lại đoạn code Python ở phần 3 và 4.
Bạn sẽ thấy một điều thú vị: Danh sách số lượng UTxO của bạn sẽ tăng lên (thành 2 hoặc nhiều hơn), nhưng hàm tính tổng số dư của chúng ta vẫn sẽ cộng dồn và hiển thị chính xác tổng số ADA bạn đang có!
Bước tiếp theo: Tiền đã nằm gọn trong ví (dưới dạng các UTxO). Ở bài học kế tiếp, chúng ta sẽ bắt đầu học cách “tiêu” số tiền này bằng việc: Xây dựng và Gửi giao dịch (Building & Submitting Transaction) đầu tiên lên mạng lưới Cardano!
