Nếu bạn nào đã làm quen với blockchain và lập trình smart contract thì chắc hẳn sẽ cảm thấy smart contract còn rất nhiều hạn chế, dẫn đến việc lập trình ứng dụng chưa được linh hoạt. Ví dụ như gọi api bên ngoài, hoặc set crontab, v.v...
Việc gọi api bên ngoài hoặc set crontab trong smart contract hiện nay cũng đã được các nhà phát triển quan tâm, họ đã và đang phát triển một cơ chế mới gọi là Blockchain Oracle. Blockchain Oracle hiện nay vẫn đang được phát triển mạnh mẽ, mặc dù chưa giải quyết hết được toàn bộ khó khăn hạn chế hiện nay nhưng cũng một phần nhỏ hỗ trợ kha khá trong việc lập trình smart contract.
1. Đặt vấn đề bài toán
Giả sử mình muốn viết một ứng dụng trên blockchain về đặt cược trận bóng đá chung kết world cup 2022. Mình sẽ viết bằng smart contract. Người chơi sẽ gửi số tiền đặt cược và kết quả dự đoán tỷ số đến smart contract. Dự tính trận đấu sẽ kết thúc vào lúc 1h 19/12/2022. Và tại thời điểm 1h 19/12/2022 smart contract sẽ bắt đầu trả thưởng cho người chơi đã dự đoán đúng.
Nếu bạn đã quen với lập trình smart contract rồi thì việc code phần lưu lại thông tin players kèm tỷ số và việc gửi thưởng đến player thắng cuộc sẽ không có gì khó.
Nhưng câu hỏi bây giờ cần đặt ra là:
- Làm sao để smart contract biết được tỷ số trận đấu?
- Làm sao để vào lúc 1h 19/12/2022 smart contract tự động start hàm tìm người thắng cuộc và trả thưởng?
Mình đoán lúc này trong đầu bạn sẽ mường tượng ra việc dựng thêm một con server và viết batch. Batch sẽ call api đến một bên thứ 3 nào đó để lấy kết quả tỷ số và gọi hàm gửi thông tin đến cho smart contract. Sau đó chỉ cần set crontab cho batch đó chạy lúc 1h 19/12/2022 là ok.
Vâng, chính xác thì hiện tại khá nhiều các dịch vụ ứng dụng blockchain hầu như phải dựng thêm server bên ngoài để thực hiện những tác vụ mà smart contract đang bị hạn chế. Nhưng có một điều lưu ý ở đây là khi ta dựng một server như vậy thì nó lại là Centralized (tập trung) mất rồi. Không ai đảm bảo rằng thông tin tỷ số của bạn khi đẩy vào smart contract là chính xác và tường minh. Dẫn đến ứng dụng của bạn trở thành bán phi tập trung.
Nên để giải quyết vấn trên, các nhà phát triển đã tạo ra cơ chế là Blockchain Oracle. Thay vì bạn lấy tỷ số từ 1 bên thứ ba thì bạn có thể lấy tỷ số từ blockchain oracle, blockchain oracle đảm bảo tỷ số đó là đúng và đã được xác minh. Bên cạch đó cơ chế cũng hỗ trợ bạn set crontab. Như vậy ứng dụng của bạn bây giờ mới có thể gọi là 100% phi tập trung.
2. Giới thiệu Blockchain Oracle
2.1 Nguồn gốc từ "Oracle"
Ngày xưa, ở Hy Lạp, một ông vua trước khi ra trận, thường cầu hỏi ý các tiên tri liệu rằng nếu đánh trận đó thì có thắng không. Trong các đền thời, họ thường xây thêm một phòng gọi là "Oracle's Chamber". Phòng này sẽ nuôi các tiên tri. Khi ông vua đến cầu hỏi, tiên tri sẽ đưa ra các thông điệp, các thông điệp này sẽ được các tu sĩ tổng hợp lại để ra được kết quả cuối cùng là CÓ hay KHÔNG nên đánh trận đó. Nếu thực tế có khác với dự đoán thì người ta sẽ cho rằng do hiểu sai ý tiên tri (ở bước tu sĩ tập hợp chưa hiểu hết ý nghĩa lời tiên tri). Thời kì Oracle khá thịnh hành và kéo dài rất nhiều thế kỷ.
Ở thế giới hiện đại hiện nay, thì cơ chế Oracle vẫn đang được sử dụng. Thay vì là lời tiên tri của một ai đó thì sẽ là "Data input" - dữ liệu đầu vào. Sau đó thay cho tu sĩ thì những dữ liệu này sẽ được xử lý bằng các thuật toán, tổng hợp lại để ra được kết quả cuối cùng.
2.2 Vấn đề oracle là gì?
Blockchain không thể kết nối với dữ liệu từ thế giới bên ngoài theo mặc đinh.
Điều này đảm bảo mức độ an toàn cao cho hệ thống.
Ngược lại, điều này cũng làm hợp đồng thông minh không thể phát huy được 90% trường hợp sử dụng.
2.3 Oracle là gì?
Oracle là một phần mềm trung gian an toàn tạo điều kiện giao tiếp giữa blockchain và bất kì hệ thống ngoài chuỗi nào.
2.4 Centralized Oracle
- Oracle tập trung là điểm thất bại duy nhất
- Oracle tập trung không đảm bảo được chất lượng dữ liệu đầu vào và đầu ra
- Cần sự tin tưởng
2.5 Decentralized Oracle
- Oracle phi tập trung khó bị tấn công hơn
- Oracle phi tập trung tập hợp và đảm bảo chất lượng dữ liệu đầu vào và đầu ra
- Không cần sự tin tưởng
- Là dữ liệu căn cứ
- Là dữ liệu căn cứ được cung cấp bởi một mạng phi tập trung có xác thực và đồng thuận.
- Thường được dùng làm cầu nối giữa thế giới thực và blockchain, kết nối các dữ liệu thực tế vào blockchain.
2.6 Decetralized Oracle đã được triển khai theo hình thái nào?
- Người ta sẽ dựng servers bên ngoài blockchain (còn gọi là Off-chain)
- Các servers sẽ tổng hợp thông tin từ nhiều nhà cung cấp khác
- Sau khi tổng hợp và thống nhất dữ liệu → sẽ tạo 1 transaction → update thông tin mới vào smartcontract của dịch vụ cung cấp oracle đó.
- Các smartcontract khác khi muốn tham khảo giá sẽ gọi đến smartcontract của dịch vụ blockchain oracle đó.
- Decetralized Oracle khi triển khai phải được triển khai trên cả On-chain lẫn Off-chain
2.7 Các nhà cung cấp dịch vụ Blockchain Oracle
Hiện nay có khá nhiều nhà phát triển đã quan tâm đến khía cạnh này của blockchain. Đầu tiên và nổi trội nhất hiện này là Chainlink. Chainlink cũng hỗ trợ trên khá nhiều chain lớn như Ethereum, Polkadot, Binance chain, v.v...
3. Giới thiệu Chainlink và các dịch vụ
Chainlink là một trong những dịch vụ blockchain oracle nổi trội nhất hiện nay. Họ sẽ tập hợp các thông tin từ nhiều nguồn như thông tin về giá vàng, chứng khoán, giá xăng, thông tin định danh con người, ai mất ai vừa được sinh ra, v.v... đưa thông tin vào trong blockchain.
3.1 Dịch vụ Chainlink Data Feeds
Dịch vụ này giống như là nơi cung cấp các thông tin. Ví dụ ở trang https://data.chain.link/ bạn sẽ thấy được các thông tin về giá token mới nhất.
Để có được thông tin giá mới nhất của ETH, Chainlink đã tập hợp giá từ các node server (là các node bên phải ảnh). Nếu có một node nào đó báo giá khác xa với các node còn lại thì hệ thống sẽ cho rằng node đấy báo giá không trung thực và sẽ bị phạt. Còn các node báo giá đúng sẽ được thưởng. Khi báo giá các node sẽ bị block số tiền cọc lại để đảm bảo thưởng/phạt phân minh.
Để lấy thông tin giá ETH từ smart contract của bạn, việc lập trình cũng khá đơn giản. Trên document của họ cũng đã hướng dẫn khá chi tiết https://docs.chain.link/data-feeds/price-feeds
// import thư viện của chainlink vào để sử dụng
import "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";
// Khởi tạo
// Bạn truyền vào địa chỉ smart contract của cặp tiền mà bạn muốn lấy giá
priceFeed = AggregatorV3Interface(
0xD4a33860578De61DBAbDc8BFdb98FD742fA7028e
);
// gọi hàm latestRoundData để lấy thông tin giá về
(
/* uint80 roundID */,
int price,
/*uint startedAt*/,
/*uint timeStamp*/,
/*uint80 answeredInRound*/
) = priceFeed.latestRoundData();
3.2 Dịch vụ Chainlink VRF
Đây là dịch vụ cung cấp một số ngẫu nhiên. Về tính ứng dụng thì mình chưa biết để làm gì ngoài ứng dụng tạo xổ số. Bạn có thể tham khảo thêm ở đây https://docs.chain.link/vrf/v2/introduction
Để sử dụng dịch vụ này thì bạn sẽ phải tốn token LINK của Chainlink. Mỗi lần gọi hàm tạo số ngẫu nhiên thì Chainlink tính một ít phí.
Việc lập trình smart contract sử dụng VRF như sau:
Những bước import thư viện ở dòng 5, 6, 7 là không thể thiếu rồi nhé.
bytes32 keyHash =
0x79d3d8832d904592c0bf9818b621522c988bb8b0c05cdc3b15aea1b6e8db0c15;
COORDINATOR = VRFCoordinatorV2Interface(
0x2Ca8E0C643bDe4C2E08ab1fA0da3401AdAD7734D
);
Tiếp theo là những thông tin như keyHash hay địa chỉ address khi bạn khai báo VRFCoordinatorV2Interface
thì tùy vào mạng mà bạn sử dụng. Trong ví dụ là sử dụng Goerli testnet. Mỗi mạng sẽ có thông tin khác nhau, bạn chỉ việc lên document và copy về sử dụng. Bạn có thể tham khảo các mạng khác ở đây:
https://docs.chain.link/vrf/v2/subscription/supported-networks
// gọi lấy giá
requestId = COORDINATOR.requestRandomWords(keyHash, s_subscriptionId, requestConfirmations, callbackGasLimit, numWords);
Bạn để ý hàm fulfillRandomWords()
đây là hàm callback, chainlink sẽ gọi đúng tên hàm này và trả về số ngẫu nhiên vào biến _randomWords
function fulfillRandomWords(uint256 _requestId, uint256[] memory _randomWords) internal override {
...
}
Sau đó bạn deploy smart contract của bạn lên network.
Tiếp theo, để đăng ký sử dụng VRF này:
- Vào https://vrf.chain.link/ đăng ký thông tin.
- Sau đó nhấn nút "Add Funds" để chuyển một ít token LINK vào. Mỗi lần gọi hàm, hệ thống sẽ trừ token trong đây. Nếu không đủ token thì hàm sẽ không trả về thông tin.
- Đăng ký consumer. Tức là bạn sử dụng Address của smart contract mà bạn đã deploy và đăng ký một consumer.
Kết quả test sẽ như sau.
3.3 Dịch vụ Chainlink Keeper
Đây là dịch vụ hỗ trợ kích hoạt call hàm tự động trong smart contract tại một thời điểm. Khá giống với crontab.
Tài liệu tham khảo ở đây: https://docs.chain.link/chainlink-automation/introduction/
Nhìn vào hình trên, Chainlink sẽ gọi đến hàm checkUpKeep
trong smart contract của bạn, nếu hàm trả về false
thì sẽ không có gì xảy ra tiếp theo. Nếu hàm trả về true
thì Chainlink sẽ gọi hàm callback trong smart contract của bạn và bạn có thể xử lý tiếp logic của mình.
Chainlink cũng hỗ trợ set time giống như crontab.
Để sử dụng chức năng này trong smart contract, bạn lập trình như sau:
Bạn để ý có 2 hàm quan trọng là checkUpkeep()
và performUpkeep()
.
checkUpkeep()
sẽ trả về true/false. Trong hàm này bạn tự định nghĩa điều kiện thỏa mãn để thực hiện tiếp logic khác.performUpkeep()
sẽ được gọi nếu hàmcheckUpkeep()
trả về true.
Đây là 2 hàm có tên cố định mà Chainlink quy định. Khi lập trình cần giữ đúng tên như thế.
Sau đó bạn deploy smart contract lên network.
Tiếp theo bạn vào https://automation.chain.link/ để đăng ký một Upkeep cho mình nhé.
Thông tin Target contract address
là address của smart contract mà bạn đã deploy.
Cũng giống như VRF, phí sử dụng chức năng automation này cũng là token LINK.
Token chỉ bị trừ khi hàm performUpkeep()
được gọi. Nghĩa là việc checkUpkeep
sẽ không mất phí, khi nào thỏa điều kiện trả về true thì hàm performUpkeep
sẽ được gọi và LINK sẽ bị trừ. Nếu tài khoản không đủ token LINK thì sẽ dừng việc gọi.
Để nạp token LINK vào bạn bấm "Actions" và chọn add funds.
Smart contract trong ví dụ là viết hàm counter. Nếu thỏa mãn thì sẽ update counter lên một số. Kết quả khi chạy và lấy giá trị của biến counter:
3.4 Chức năng call any api bên ngoài
Đôi lúc muốn call một api bất kì bên ngoài blockchain, thì chainlink cũng hỗ trợ. Việc call api này vẫn còn nhiều hạn chế, thông tin response về chỉ có 1 thông tin trong chuỗi json, tức là bạn không thể lấy được toàn bộ chuỗi json như các hệ thống backend thông thường. Nhưng đây cũng là một khởi đầu mới rất hữu ích.
Mình có thông tin api như trên https://reqres.in/api/products/3
Nó sẽ trả về một chuỗi json. Nếu bạn sử dụng các ngôn ngữ khác như js, php, v.v... thì dễ dàng lấy được full thông tin.
Nhưng trong smart contract còn hạn chế, chỉ lấy được một thông tin. Trong ví dụ này mình sẽ lấy thông tin id
ra.
Thông tin id
là kiểu số. Tùy vào mỗi kiểu output thì chainlink sẽ support các Job ID
khác nhau. Khi lập trình bạn cần xem xét dữ liệu cần lấy thuộc kiểu dữ liệu gì và sử dụng Job ID
mà chainlink cung cấp sẵn.
Bạn có thể tham khảo thêm thông tin về Job ID
ở đây:
https://docs.chain.link/any-api/testnet-oracles
Việc lập trình cũng đơn giản như sau:
Những biến oracle
hay jobId
là thông tin có trên document của Chainlink.
oracle
là thông tin network mà bạn sử dụngjobId
như đã trình bày ở trên, là kiểu dữ liệu trả về
Kết quả khi chạy lấy thông tin id
:
4. Tổng kết
Về cơ bản thì những cơ chế Oracle còn sơ khai nhưng cũng phần nào giải quyết được những hạn chế của blockchain. Quay lại với bài toán ban đầu, nếu sử dụng tính năng Data Feeds và Keeper cũng đã có thể biến ứng dụng thành 100% là phi tập trung.
5. Tài liệu tham khảo
5.1 Các loại service phổ biến của chainlink
5.2 Demo chainlink vs smartcontract
- https://www.youtube.com/watch?v=pgf8Prwibio
- https://dapp-world.com/smartbook/call-any-api-in-smart-contract-parti-f77z
- https://dapp-world.com/smartbook/call-any-api-in-smart-contract-partii-J8hn