Ai cũng biết rằng nhiều blockchain có vấn đề về khả năng mở rộng và tắc nghẽn. Những vấn đề này có tác động trên phạm vi rộng từ thời gian giao dịch chậm đến tăng phí giao dịch và làm giảm trải nghiệm người dùng.
Một giải pháp dành cho web3 là đa chuỗi bằng cách sử dụng chuỗi L2 (lớp hai). Ethereum L2, chẳng hạn như Optimism , Arbitrum và Polygon , được xây dựng trên mạng Ethereum nhưng nhanh hơn và rẻ hơn Ethereum.
Tuy nhiên, như một sự đánh đổi, chúng thường kém an toàn hơn Ethereum. Đó là lý do tại sao các L2 xử lý các hoạt động hàng ngày của người dùng trong khi vẫn dựa vào Ethereum L1 như một nền tảng đằng sau hậu trường cho một lớp dữ liệu sẵn có và thanh toán phi tập trung và an toàn.
Đây là một giải pháp tuyệt vời — tuy nhiên, có rất nhiều L2 chỉ riêng trên Ethereum; mỗi người là một mạng độc lập với những sắc thái và trải nghiệm riêng.
Việc xây dựng và sử dụng các dapp tương tác và di chuyển giữa các mạng này và Ethereum L1 có thể rất tẻ nhạt, khó khăn và mang lại trải nghiệm kém cho người dùng cũng như nhà phát triển.
Những gì chúng tôi cần là web3 trở thành trải nghiệm đa chuỗi , nơi người tiêu dùng không cần biết họ đang sử dụng chuỗi nào (và nói thẳng ra là không quan tâm) và nơi các nhà phát triển có thể dựa vào bất kỳ mạng nào hỗ trợ tốt nhất cho nhu cầu của họ .
Bằng cách chuyển sang internet chuỗi khối đa chuỗi này, web3 trở thành trải nghiệm tốt hơn cho mọi người tham gia.
Thật không may, việc cho phép các dapp di chuyển giữa các chuỗi là một thách thức kỹ thuật khó khăn. Trong bài viết này, chúng ta sẽ xem xét một giải pháp — sử dụng các điểm cuối Infura RPC và Truffle Box để xây dựng và kết nối các mạng này một cách liền mạch.
Cụ thể, chúng tôi sẽ sử dụng Hộp truffle cầu lạc quan để tạo một dự án trên mạng thử nghiệm Ethereum Goerli và kết nối với Goerli lạc quan.
Là cốt lõi của giải pháp ví dụ của chúng tôi, chúng tôi sẽ dựa vào Hộp Truffle — bản mẫu soạn sẵn “lối tắt” (chẳng hạn như hợp đồng, thư viện, mô-đun và thậm chí cả dapp đầy đủ chức năng) từ ConsenSys mà bạn có thể sử dụng để xây dựng dapp của mình.
Đối với các giải pháp đa chuỗi, chúng được xây dựng dựa trên các Nút RPC của Infura cho nhiều mạng L2.
Như đã đề cập ở trên, chúng tôi sẽ đặc biệt dựa vào Hộp Truffle Cầu lạc quan . Hộp này có tất cả các hợp đồng cần thiết để tương tác với cầu nối Lạc quan từ cả L1 và L2 và một tập hợp các di chuyển để triển khai, gọi hàm và truyền thông báo/giá trị giữa các lớp.
Nó thậm chí còn có một tập lệnh trợ giúp thực hiện mọi thứ chúng ta cần để thấy tất cả hoạt động này. Chúng tôi chỉ cần mở hộp nó để có được mọi thứ chúng tôi cần! Theo Trufflesuite.com, hộp bao gồm:
Lưu ý: cầu nối là một công cụ cho phép các chuỗi khối độc lập giao tiếp với nhau, gửi mã thông báo, NFT, v.v.
Trước khi bắt đầu, chúng ta cần các điều kiện tiên quyết sau:
node -v && npm -v
Khi bạn đã hoàn thành các điều kiện tiên quyết, hãy truy cập trang web Infura để đăng nhập (hoặc đăng ký tài khoản mới).
Sau khi đăng ký thành công, trang sẽ chuyển hướng đến bảng điều khiển Infura nơi chúng tôi có thể tạo khóa API mới, như được hiển thị bên dưới.
Nhấp vào nút “Tạo khóa mới” và điền thông tin cần thiết.
Sau khi tạo khóa API, ID dự án của bạn sẽ hiển thị trên bảng điều khiển của bạn trong phần API KEY, như được hiển thị bên dưới. Sao chép và giữ nó ở đâu đó; bạn sẽ cần nó sau này trong hướng dẫn này.
Tiếp theo, chúng ta sẽ thiết lập Hộp cầu lạc quan Truffle . Chúng tôi có thể chạy lệnh unbox trong bất kỳ thư mục nào bạn chọn bằng lệnh sau.
npx truffle unbox optimism-bridge <DIRECTORY_NAME>
Thay thế <DIRECTORY_NAME> bằng tên thư mục bạn chọn. Ngoài ra, bạn có thể cài đặt Truffle trên toàn cầu và chạy lệnh unbox.
npm install -g truffle truffle unbox optimism-bridge <DIRECTORY_NAME>
Lệnh sẽ tải xuống và chạy cài đặt npm như một phần của quy trình mở hộp.
Bây giờ, hãy chạy lệnh sau để thay đổi thư mục sang thư mục mới mà chúng ta vừa tạo.
cd truffle-bridge-demo
Lưu ý: truffle-bridge-demo là tên của thư mục đã được tạo.
Chúng ta nên có một cái gì đó tương tự như những gì xuất hiện dưới đây.
Các . gói dotenv
đã được cài đặt, nhưng chúng tôi sẽ cần thêm một số thông tin vào tệp .env được tạo sau khi mở hộp.
Tệp truffle-config.ovm.js
yêu cầu giá trị GOERLI_MNEMONIC tồn tại trong tệp .env để chạy các lệnh trên mạng thử nghiệm Ethereum Goerli và Optimism Goerli và INFURA_KEY để kết nối với mạng.
GOERLI_MNEMONIC="<your-wallet-mnemonic>" INFURA_KEY="<your-infura-key>"
Thay thế <your-infura-key> bằng thông tin chúng tôi đã nhận được trước đó từ bảng điều khiển Infura của chúng tôi. ( Lưu ý : Không bao giờ chia sẻ khóa riêng tư (ghi nhớ) của bạn với bất kỳ ai và hãy giữ chúng an toàn). Và thay thế <your-wallet-mnemonic> bằng cách ghi nhớ của bạn như bên dưới:
Để truy xuất bản ghi nhớ từ Metamask, hãy nhấp vào biểu tượng hiển thị bên dưới trên Metamask của bạn.
Tiếp theo, nhấp vào nút Xuất khóa cá nhân để sao chép bản ghi nhớ.
Git bỏ qua tệp .env trong dự án này để giúp bảo vệ dữ liệu riêng tư của bạn. Thực hành bảo mật tốt là tránh tiết lộ khóa riêng của bạn cho GitHub.
Khi chúng tôi mở hộp dự án, tất cả các hợp đồng và tập lệnh cần thiết của dự án đã được tạo cho chúng tôi. Trong bước tiếp theo này, hãy xem qua các hợp đồng riêng lẻ và quá trình di chuyển để hiểu cách kết nối và tương tác diễn ra giữa các mạng.
Hợp đồng contract/ethereum/GreeterL1.sol
chỉ cho bạn cách gửi tin nhắn qua cầu Lạc quan từ L1 đến L2.
//SPDX-License-Identifier: Unlicense // This contract runs on L1, and controls a Greeter on L2. pragma solidity ^0.8.0; import { ICrossDomainMessenger } from "@eth-optimism/contracts/libraries/bridge/ICrossDomainMessenger.sol"; contract GreeterL1 { address crossDomainMessengerAddr = 0x5086d1eEF304eb5284A0f6720f79403b4e9bE294; address greeterL2Addr = 0xC0836cCc8FBa87637e782Dde6e6572aD624fb984; function setGreeting(string calldata _greeting) public { bytes memory message; message = abi.encodeWithSignature("setGreeting(string)", _greeting); ICrossDomainMessenger(crossDomainMessengerAddr).sendMessage( greeterL2Addr, message, 1000000 // within the free gas limit amount ); } // function setGreeting } // contract GreeterL1
migrations/3_set_L2_greeting.js
sử dụng hợp đồng trên để gửi một thông báo từ Ethereum tới Optimism.
var Greeter = artifacts.require("GreeterL1"); /** * Set L2 Greeting * Run this migration on L1 to update the L1 greeting. */ module.exports = async function (deployer) { console.log("Updating the L2 Greetings contract from L1! 👋👋"); const instance = await Greeter.deployed(); const tx = await instance.setGreeting("👋 Greetings from Truffle!"); console.log(`🙌 Greeter txn confirmed on L1! ${tx.receipt.transactionHash}`); console.log(`🛣️ Bridging message to L2 Greeter contract...`); console.log( `🕐 In about 1 minute, check the Greeter contract "read" function: https://goerli-optimism.etherscan.io/address/0xC0836cCc8FBa87637e782Dde6e6572aD624fb984#readContract` ); };
Tiếp theo, contracts/optimism/GreeterL2.sol
gửi một thông báo theo hướng khác (L2->L1) qua cầu Optimism.
//SPDX-License-Identifier: Unlicense // This contract runs on L2, and controls a Greeter on L1. pragma solidity ^0.8.0; import { ICrossDomainMessenger } from "@eth-optimism/contracts/libraries/bridge/ICrossDomainMessenger.sol"; contract GreeterL2 { address crossDomainMessengerAddr = 0x4200000000000000000000000000000000000007; address greeterL1Addr = 0x7fA4D972bB15B71358da2D937E4A830A9084cf2e; function setGreeting(string calldata _greeting) public { bytes memory message; message = abi.encodeWithSignature("setGreeting(string)", _greeting); ICrossDomainMessenger(crossDomainMessengerAddr).sendMessage( greeterL1Addr, message, 1000000 // irrelevant here ); } // function setGreeting } // contract GreeterL2
migrations/4_set_L1_greeting.js
sử dụng hợp đồng trên để gửi thông báo từ Optimism đến Ethereum.
require("dotenv").config(); const sdk = require("@eth-optimism/sdk"); const ethers = require("ethers"); const Greeter = artifacts.require("GreeterL2"); const goerliMnemonic = process.env["GOERLI_MNEMONIC"]; const infuraKey = process.env["INFURA_KEY"]; const sleep = (milliseconds) => { return new Promise((resolve) => setTimeout(resolve, milliseconds)); }; /** * Set L1 Greeting * Run this migration on L1 to update the L1 greeting. */ module.exports = async function (deployer) { const newGreeting = "👋 Greetings from Truffle!"; //<---- CHANGE THIS VALUE TO YOUR NAME!!! const instance = await Greeter.deployed(); console.log("Updating the L1 Greetings contract from L2! 👋"); const tx = await instance.setGreeting(newGreeting); const txHash = tx.receipt.transactionHash; console.log(`🙌🙌 Greeter txn confirmed on L2! ${txHash}`); console.log( `🛣️ Bridging message to L1 Greeter contract.\n 🕐 This will take at least 1-5 min...` ); // Set providers for Optimism sdk const l1Provider = new ethers.providers.JsonRpcProvider( "https://goerli.infura.io/v3/" + infuraKey ); const l2Provider = new ethers.providers.JsonRpcProvider( "https://optimism-goerli.infura.io/v3/" + infuraKey ); // Connect an L1 signer const wallet = ethers.Wallet.fromMnemonic(goerliMnemonic); const l1Signer = wallet.connect(l1Provider); // Initialize sdk messenger const crossChainMessenger = new sdk.CrossChainMessenger({ l1ChainId: 5, l2ChainId: 420, l1SignerOrProvider: l1Signer, l2SignerOrProvider: l2Provider, }); let statusReady = false; // Sleep for 1 min during L2 -> L1 bridging await sleep(60000); // 60 seconds // Poll the L1 msg status while (!statusReady) { let status = null; status = await crossChainMessenger.getMessageStatus(txHash); statusReady = status == sdk.MessageStatus.READY_FOR_RELAY; if (!statusReady) { console.log( "Message not yet received on L1.\n 🕐 Retrying in 10 seconds..." ); await sleep(10000); // 10 seconds } } console.log("📬 Message received! Finalizing..."); // Open the message on L1 finalize = await crossChainMessenger.finalizeMessage(txHash); console.log( `🎉 Message finalized. Check the L1 Greeter contract "read" function: https://goerli.etherscan.io/address/0x7fA4D972bB15B71358da2D937E4A830A9084cf2e#readContract` ); };
Trong thư mục tập lệnh, chúng tôi cũng có goerli_bridge_message.mjs
và goerli_bridge_value.js
để tự động hóa quy trình biên dịch hợp đồng, chạy di chuyển và gửi tin nhắn.
Tiếp theo, chúng tôi sẽ thực sự triển khai hợp đồng của mình cho Goerli. Tập lệnh trợ giúp tạo điều kiện thuận lợi cho việc biên dịch, di chuyển và kết nối các thông báo giữa Ethereum Goerli và Optimism Goerli.
Trên các mạng đó, chúng tôi sẽ cần ETH testnet để sử dụng. Để nhận một số, hãy sử dụng vòi . Chúng tôi cũng sẽ cần thêm tiện ích bổ sung Lạc quan vào tài khoản Infura của bạn.
Tiếp theo, chúng ta sẽ chạy lệnh sau để bắt đầu dự án.
npm run deploy
Dưới đây là một URL để xác nhận (thông qua Etherscan) thông báo bắc cầu sau khi di chuyển hoàn tất.
Một liên kết để xác nhận thông báo bắc cầu qua Etherscan sẽ được cung cấp sau khi hoàn thành lần di chuyển thứ 4.
Chúng tôi đã thiết lập, cài đặt, xây dựng, triển khai và duyệt thành công dự án mà chúng tôi đã mở hộp trước đó. Tiếp theo, chúng tôi sẽ xác minh dự án trên mạng thử nghiệm Goerli Ethereum.
Truy cập trình khám phá khối Goerli Etherscan và dán địa chỉ txn 0xbcc1746a9ebbfcfb71665225c1a353a8c8dc9a1aa528a3babcb5b046d615a353 hiển thị trên CLI của chúng tôi khi triển khai.
Một thế giới web3 đa chuỗi là rất quan trọng nếu chúng tôi muốn trải nghiệm của người dùng và nhà phát triển tiếp tục được cải thiện. Và để đạt được điều đó, chúng tôi cần các cách để các dapp giao tiếp giữa các chuỗi một cách nhanh chóng và liền mạch.
Hy vọng rằng, ví dụ mà chúng tôi đã thực hiện bằng cách sử dụng Hộp Truffle Cầu lạc quan đã cho bạn thấy một cách tương đối dễ dàng và nhanh chóng để bắt đầu. Để tìm hiểu thêm, hãy xem tài liệu chính thức .
Có một ngày thực sự tuyệt vời!