

Tham gia cộng đồng PolkaWorld và cùng nhau xây dựng Web 3.0!
Với bản phát hành Polkadot 1.0 cuối cùng và các parachain đang đến gần, Định dạng thông báo đồng thuận chéo, hay gọi tắt là XCM, sắp phát hành phiên bản sẵn sàng sản xuất đầu tiên. Đây là phần giới thiệu về định dạng, mục tiêu, cách thức hoạt động và có thể được sử dụng để triển khai các tác vụ xuyên chuỗi điển hình.
Với bản phát hành Polkadot 1.0 cuối cùng và các parachain đang đến gần, Định dạng thông báo đồng thuận chéo, hay gọi tắt là XCM, sắp phát hành phiên bản sẵn sàng sản xuất đầu tiên. Đây là phần giới thiệu về định dạng, mục tiêu, cách thức hoạt động và có thể được sử dụng để triển khai các tác vụ xuyên chuỗi điển hình.
Hãy bắt đầu với một sự thật thú vị. XCM là định dạng thông báo "đồng thuận chéo", không chỉ "chuỗi chéo". Sự khác biệt này là dấu hiệu cho thấy cuối cùng định dạng đạt được gì, một định dạng không chỉ giao tiếp giữa các chuỗi mà còn giữa các hợp đồng thông minh và mô-đun, cũng như thông qua các cầu nối và phân đoạn (chẳng hạn như Polkadot's Spree) để gửi các ý tưởng khác nhau.
trình soạn thảo mdnice
🤟 Một định dạng, không phải là một giao thức
Không bao gồm các mô-đun cầu nối và hợp đồng, Polkadot đi kèm với ba hệ thống riêng biệt để thực sự truyền thông điệp XCM giữa các chuỗi cấu thành của nó: UMP, DMP và XCMP. UMP (Up Message Passing) cho phép các parachain gửi tin nhắn đến chuỗi chuyển tiếp của chúng. DMP (Nhắn tin hướng xuống) cho phép chuỗi chuyển tiếp chuyển tin nhắn xuống các chuỗi dù của nó. XCMP có lẽ là nổi tiếng nhất trong số này, cho phép gửi tin nhắn giữa các parachains. XCM có thể được sử dụng để thể hiện ý nghĩa của thông điệp qua bất kỳ kênh nào trong ba kênh liên lạc này.
Ngoài việc gửi tin nhắn giữa các chuỗi, XCM cũng hữu ích trong các ngữ cảnh khác, chẳng hạn, nó có thể được sử dụng để thực hiện các giao dịch trên các chuỗi có định dạng giao dịch mà trước đây bạn không biết rõ. Đối với các chuỗi mà logic nghiệp vụ thay đổi rất ít (chẳng hạn như Bitcoin), định dạng giao dịch — hoặc định dạng ví sử dụng để gửi hướng dẫn đến chuỗi — có xu hướng giữ nguyên hoàn toàn hoặc ít nhất là tương thích vô thời hạn. Sử dụng các chuỗi dựa trên siêu giao thức có khả năng phát triển cao, chẳng hạn như Polkadot và các chuỗi cấu thành của nó, logic kinh doanh có thể được nâng cấp trên toàn mạng chỉ bằng một giao dịch. Điều này có thể thay đổi mọi thứ, kể cả các định dạng giao dịch, gây ra các sự cố tiềm ẩn cho người bảo trì ví, đặc biệt là đối với các ví cần được giữ ngoại tuyến (chẳng hạn như Người ký chẵn lẻ). Vì XCM là phiên bản tốt, trừu tượng và chung chung nên nó có thể được sử dụng như một phương tiện cung cấp ví với định dạng giao dịch liên tục để tạo nhiều giao dịch phổ biến.
trình soạn thảo mdnice
🥅 mục tiêu
Giống như tất cả các ngôn ngữ, một số người sẽ có xu hướng sử dụng một số yếu tố nhất định hơn những người khác. XCM không được thiết kế theo cách mà mọi hệ thống hỗ trợ XCM đều có thể diễn giải mọi thông báo XCM có thể. Một số thông báo sẽ không có cách giải thích hợp lý theo một số hệ thống. Một số khác có thể hợp lý, nhưng vẫn không được trình thông dịch cố tình hỗ trợ do hạn chế về nguồn lực hoặc do cùng một nội dung có thể được diễn đạt một cách rõ ràng, chuẩn mực hơn. Hệ thống chắc chắn sẽ chỉ hỗ trợ một tập hợp con các thông báo có thể. Một hệ thống bị hạn chế nghiêm trọng về tài nguyên (chẳng hạn như hợp đồng thông minh) chỉ có thể hỗ trợ một "phương ngữ" rất hạn chế.
Mức độ phổ biến này thậm chí còn mở rộng sang các khái niệm như trả tiền cho việc thực hiện các thông báo XCM. Vì chúng tôi biết rằng XCM có thể được sử dụng trong nhiều hệ thống khác nhau, từ các nền tảng hợp đồng thông minh được đo bằng gas và các dù chuỗi cộng đồng, cho đến các tương tác đáng tin cậy giữa các dù chuỗi hệ thống và chuỗi chuyển tiếp của chúng, nên chúng tôi không muốn đưa ra các yếu tố như thanh toán phí quá sâu và trở nên không thể đảo ngược trong thỏa thuận.
trình soạn thảo mdnice
😬 Tại sao không chỉ sử dụng định dạng tin nhắn gốc
Thứ hai, các trường hợp sử dụng phổ biến trên chuỗi không dễ dàng phù hợp với một giao dịch đơn lẻ; các thủ thuật đặc biệt có thể được yêu cầu để rút tiền, trao đổi tiền và sau đó gửi tất cả kết quả trong một giao dịch. Các thông báo chuyển tiếp theo cần thiết cho khung tài sản dự trữ nhất quán không tồn tại trong các chuỗi mà những người khác không biết.
Thứ ba, các hoạt động như thanh toán phí không dễ dàng phù hợp với mô hình giả định rằng các khoản thanh toán phí đã được thương lượng như thông điệp hợp đồng thông minh. Ngược lại, phong bì giao dịch cung cấp một số hệ thống xử lý thanh toán, nhưng cũng thường được thiết kế để chứa chữ ký, điều này vô nghĩa khi giao tiếp giữa các hệ thống đồng thuận.
trình soạn thảo mdnice
🎬 Một số trường hợp sử dụng ban đầu
Mặc dù XCM hướng đến mục tiêu chung, linh hoạt và phù hợp với tương lai, nhưng tất nhiên nó phải đáp ứng các nhu cầu thực tế, đặc biệt là đối với việc chuyển mã thông báo giữa các chuỗi. Thanh toán phí tùy chọn (có thể sử dụng các mã thông báo này) là một cách khác, giống như một giao diện chung cho các dịch vụ trao đổi, phổ biến trên toàn thế giới DeFi. Cuối cùng, có thể thực hiện một số thao tác dành riêng cho nền tảng bằng ngôn ngữ XCM. Ví dụ, trong một chuỗi Substrate, có thể cần gửi lệnh gọi từ xa đến một trong các mô-đun của nó để truy cập chức năng chuyên dụng.
Ngoài ra, có nhiều mô hình chuyển mã thông báo mà chúng tôi muốn hỗ trợ: chúng tôi có thể chỉ muốn kiểm soát các tài khoản trên chuỗi từ xa, cho phép chuỗi cục bộ có địa chỉ trên chuỗi từ xa để nhận tiền và cuối cùng chuyển tiền. kiểm soát các tài khoản khác trên chuỗi từ xa.
Chúng tôi có thể có hai hệ thống đồng thuận, cả hai đều là "nhà riêng" cho một mã thông báo cụ thể. Hãy tưởng tượng một mã thông báo như USDT hoặc USDC có các phiên bản trên một số chuỗi khác nhau và hoàn toàn có thể hoán đổi cho nhau. Có thể ghi các mã thông báo như vậy trên một chuỗi và đúc các mã thông báo tương ứng trên một chuỗi được hỗ trợ khác. Theo cách nói của XCM, chúng tôi gọi đó là dịch chuyển tức thời vì việc chuyển một tài sản thực sự được thực hiện bằng cách phá hủy nó ở một bên và tạo một bản sao ở bên kia.
Cuối cùng, có thể có hai chuỗi muốn chỉ định chuỗi thứ ba và một tài sản trên một trong những chuỗi đó có thể được coi là tài sản gốc được sử dụng làm dự trữ cho tài sản đó. Các hình thức phái sinh của từng tài sản trên chuỗi sẽ được hỗ trợ đầy đủ, cho phép tài sản phái sinh được trao đổi với tài sản cơ bản trên chuỗi dự trữ hỗ trợ nó. Đây có thể là trường hợp hai chuỗi không nhất thiết phải tin tưởng lẫn nhau, nhưng (ít nhất là đối với tài sản được đề cập) sẵn sàng tin tưởng vào chuỗi địa phương của tài sản đó. Một ví dụ ở đây là chúng tôi có một số dù cộng đồng muốn gửi DOT cho nhau. Mỗi người trong số họ có một dạng DOT riêng được hỗ trợ hoàn toàn bởi một DOT do parachain kiểm soát trên chuỗi Statemint (trung tâm cục bộ của DOT). Mặc dù các dạng DOT gốc được gửi giữa các chuỗi, nhưng DOT "thực" di chuyển giữa các tài khoản parachain trên Statemint.
Ngay cả mức chức năng có vẻ khiêm tốn này cũng có số lượng cấu hình tương đối lớn, việc sử dụng chúng có thể được mong muốn và cần có một số thiết kế thú vị để tránh trang bị quá mức.
Giải phẫu của XCM
Trọng tâm của định dạng XCM là XCVM. Trái ngược với những gì một số người có thể tin, đây không phải là một chữ số La Mã (hợp lệ) (mặc dù nếu có, nó có thể có nghĩa là 905). Trên thực tế, đây là viết tắt của Máy ảo đồng thuận chéo. Đó là một máy tính không hoàn thiện Turing ở cấp độ rất cao với các hướng dẫn được thiết kế ở mức tương đương với các giao dịch.
Một "thông điệp" trong XCM thực sự chỉ là một chương trình chạy trên XCVM. Đó là một hoặc nhiều chỉ thị XCM. Chương trình thực thi cho đến khi chạy đến cuối hoặc gặp lỗi, lúc đó nó kết thúc (tôi cố tình không giải thích điều này ngay bây giờ) và dừng lại.
enum Instruction {
TransferAsset {
assets: MultiAssets,
beneficiary: MultiLocation,
}
/* snip */
}
XCVM bao gồm một số Thanh ghi, cũng như quyền truy cập vào trạng thái tổng thể của hệ thống đồng thuận lưu trữ nó. Các hướng dẫn có thể thay đổi Sổ đăng ký, chúng có thể thay đổi trạng thái của hệ thống đồng thuận hoặc cả hai.
Tài sản, như bạn có thể đoán, là các tham số cho biết tài sản nào sẽ được chuyển giao, trong khi người thụ hưởng nêu rõ những tài sản đó sẽ được chuyển cho ai/nơi nào. Tất nhiên, chúng tôi đang thiếu một thông tin khác, đó là ai/ở đâu để lấy nội dung. Điều này được tự động suy ra từ Đăng ký ban đầu. Khi bắt đầu chương trình, Sổ đăng ký này thường được đặt theo hệ thống truyền (Mạng, XCMP hoặc các hệ thống khác) để phản ánh thông báo thực sự đến từ đâu và người thụ hưởng là cùng một loại thông tin. Thanh ghi Gốc hoạt động như một Thanh ghi được bảo vệ -- các chương trình không thể đặt tùy ý, mặc dù có hai hướng dẫn có thể được sử dụng để thay đổi nó theo một cách nào đó.
Các loại được sử dụng là những ý tưởng rất cơ bản trong XCM: tài sản, được đại diện bởi MultiAsset, các vị trí trong phạm vi đồng thuận, được đại diện bởi MultiLocation. Đăng ký gốc là một Đa vị trí tùy chọn (tùy chọn vì nó có thể bị xóa hoàn toàn nếu cần).
trình soạn thảo mdnice
📍 Tại địa điểm XCM
Loại MultiLocation xác định bất kỳ vị trí nào tồn tại trong thế giới đồng thuận. Đây là một ý tưởng khá trừu tượng có thể đại diện cho mọi thứ từ các chuỗi khối đa phân đoạn có thể mở rộng (như Polkadot) cho đến các tài khoản tài sản ERC-20 cấp thấp trên các parachain tồn tại đồng thuận. Theo thuật ngữ khoa học máy tính, nó thực sự chỉ là một cấu trúc dữ liệu đơn lẻ toàn cầu, bất kể kích thước hay độ phức tạp.
MultiLocation luôn đại diện cho một vị trí có liên quan đến vị trí hiện tại. Bạn có thể coi nó giống như một đường dẫn hệ thống tệp, nhưng không có cách nào để biểu thị trực tiếp "gốc" của cây hệ thống tệp. Có một lý do đơn giản cho điều này: trong thế giới của Polkadot, các chuỗi khối có thể được hợp nhất vào các chuỗi khối khác hoặc phân tách từ các chuỗi khối khác. Chuỗi khối có thể bắt đầu cuộc sống rất độc lập và cuối cùng được quảng bá dưới dạng parachains trong một sự đồng thuận lớn hơn. Nếu bạn làm như vậy, ý nghĩa của "root" sẽ thay đổi chỉ sau một đêm, có thể gây nhầm lẫn cho các thông báo XCM và bất kỳ điều gì khác sử dụng MultiLocation. Để đơn giản, chúng tôi loại trừ hoàn toàn khả năng này.
Các vị trí trong XCM được phân cấp, với một số vị trí trong sự đồng thuận được gói gọn hoàn toàn ở những nơi khác trong sự đồng thuận. Các parachains của Polkadot tồn tại hoàn toàn trong sự đồng thuận tổng thể của Polkadot, mà chúng tôi gọi là các vị trí nội bộ. Nghiêm túc hơn, chúng ta có thể nói rằng bất cứ khi nào bất kỳ thay đổi nào trong một hệ thống đồng thuận này kéo theo sự thay đổi trong một hệ thống đồng thuận khác, thì hệ thống cũ là nội bộ của hệ thống sau. Ví dụ: hợp đồng thông minh Canvas tồn tại bên trong mô-đun hợp đồng lưu trữ nó. UTXO trong Bitcoin là nội bộ của chuỗi khối Bitcoin.
Điều này có nghĩa là XCM không phân biệt giữa câu hỏi "ai" và "ở đâu". Từ quan điểm của một thứ khá trừu tượng như XCM, sự khác biệt không thành vấn đề -- cả hai đều mờ nhạt và về cơ bản trở thành giống nhau.
MultiLocations được sử dụng để xác định nơi gửi tin nhắn XCM, nơi có thể nhận nội dung và sau đó thậm chí giúp mô tả chính loại nội dung đó, như chúng ta sẽ thấy. Công cụ rất hữu ích.
Khi được viết ra dưới dạng văn bản như thế này, chúng được biểu diễn dưới dạng một số thành phần .. (hoặc "cha mẹ", đóng gói hệ thống đồng thuận), theo sau là một số điểm nối, tất cả được phân tách bằng / . (Điều này thường không xảy ra khi chúng tôi diễn đạt chúng bằng một ngôn ngữ như Rust, nhưng nó có ý nghĩa trên giấy vì nó giống với đường dẫn thư mục quen thuộc được sử dụng rộng rãi.) Các kết nối trong sự đồng thuận đóng gói của chúng Xác định một hệ thống định vị nội bộ. Nếu không có nút cha/điểm giao nào cả, thì ta chỉ nói vị trí ở đây.
Ví dụ:
../Parachain(1000): Đánh giá trong một parachain, điều này sẽ xác định parachain anh chị em của chúng ta với chỉ số 1000. (Trong Rust, chúng tôi sẽ viết ParentThen(Parachain(1000)).into())
Parachain(42)/AccountKey20(0x1234...abcd): Được đánh giá trên chuỗi chuyển tiếp, điều này sẽ xác định tài khoản 20 byte 0x1234...abcd trên chuỗi parachain số 42 (có lẽ tương tự như Moonbeam lưu trữ các tài khoản tương thích với Ethereum).
Có nhiều loại điểm tham gia khác nhau được sử dụng để xác định nơi bạn có thể tìm thấy chúng trên chuỗi theo nhiều cách khác nhau, chẳng hạn như khóa, chỉ mục, đốm màu nhị phân và mô tả số nhiều.
trình soạn thảo mdnice
💰 Tài sản trong XCM
Khi làm việc trong XCM, thường cần phải tham khảo một số loại tài sản. Điều này là do hầu hết tất cả các chuỗi khối công khai hiện có đều dựa vào một số tài sản kỹ thuật số gốc để cung cấp xương sống cho các cơ chế bảo mật và kinh tế nội bộ của chúng. Đối với các chuỗi khối bằng chứng công việc như Bitcoin, tài sản gốc (BTC) được sử dụng để thưởng cho những người khai thác phát triển chuỗi khối và ngăn chặn chi tiêu gấp đôi. Đối với các chuỗi khối bằng chứng cổ phần như Polkadot, tài sản gốc (DOT) được sử dụng như một dạng tài sản thế chấp mà các quản trị viên mạng (được gọi là người đặt cược) phải chịu để tạo ra các khối hợp lệ và nhận phần thưởng vật chất.
struct MultiAsset {
id: AssetId,
fun: Fungibility,
}
Một số chuỗi khối quản lý nhiều tài sản, ví dụ như khung ERC-20 của Ethereum cho phép nhiều tài sản khác nhau được quản lý trên chuỗi. Một số tài sản quản lý các tài sản không thể thay thế, chẳng hạn như ETH của Ethereum, là những trường hợp không thể thay thế — duy nhất; Crypto-kitties là một ví dụ ban đầu về các mã thông báo không thể thay thế hoặc NFT như vậy.
plain
enum AssetId {
Concrete(MultiLocation),
Abstract(BinaryBlob),
}
XCM được thiết kế để xử lý tất cả các nội dung đó một cách dễ dàng. Với mục đích này, có loại dữ liệu MultiAsset và các loại liên kết của nó MultiAssets, WildMultiAsset và MultiAssetFilter. Hãy xem MultiAsset trong Rust:
enum Fungibility {
Fungible(NonZeroAmount),
NonFungible(AssetInstance),
}
Vì vậy, có hai trường xác định nội dung của chúng tôi: id và fun, đây là dấu hiệu tốt về cách XCM xử lý nội dung. Đầu tiên, danh tính tài sản tổng thể phải được cung cấp. Đối với nội dung có thể thay thế, điều này chỉ đơn giản là xác định nội dung. Đối với NFT, điều này xác định toàn bộ "lớp" nội dung - các phiên bản nội dung khác nhau có thể nằm trong lớp này.
Danh tính tài sản được thể hiện theo một trong hai cách; cụ thể hoặc trừu tượng. Tóm tắt không thực sự được sử dụng, nhưng nó cho phép ID nội dung được chỉ định theo tên. Điều này thuận tiện, nhưng phụ thuộc vào người nhận để giải thích tên theo cách mà người gửi mong đợi, điều này có thể không phải lúc nào cũng dễ dàng. Cụ thể sử dụng và sử dụng các vị trí nói chung để xác định rõ ràng tài sản. Đối với nội dung gốc (chẳng hạn như DOT), nội dung thường được xác định là chuỗi đã tạo ra nội dung đó (trong trường hợp này là chuỗi chuyển tiếp Polkadot, sẽ là nơi chứa các parachain của nó ..). Các tài sản được quản lý chủ yếu trong mô-đun chuỗi có thể được xác định bằng cách bao gồm vị trí được lập chỉ mục của chúng trong mô-đun đó. Ví dụ: một parachain Karura có thể đề cập đến một tài sản trên một parachain Statemine tại ../Parachain(1000)/PalletInstance(50)/GeneralIndex(42) .
Thứ hai, chúng phải có thể thay thế được hoặc không thể thay thế được. Nếu chúng có thể thay thế được, thì phải có một số lượng khác không liên quan. Nếu chúng không thể thay thế được, thì sẽ có một số dấu hiệu cho biết chúng là trường hợp nào hơn là số lượng. (Điều này thường được biểu thị bằng một chỉ mục, nhưng XCM cũng cho phép nhiều loại dữ liệu khác, chẳng hạn như mảng và các đốm màu nhị phân.) Điều này bao gồm MultiAsset, nhưng đôi khi chúng tôi sử dụng ba loại có liên quan khác. MultiAssets là một trong số đó và thực sự chỉ có nghĩa là một tập hợp các mục MultiAsset. Sau đó, chúng tôi có WildMultiAsset; đây là ký tự đại diện có thể được sử dụng để khớp với một hoặc nhiều mục MultiAsset. Nó thực sự chỉ hỗ trợ hai ký tự đại diện: Tất cả (khớp với tất cả nội dung) và AllOf khớp với tất cả nội dung có danh tính cụ thể (AssetId) và khả năng thay thế. Đáng chú ý, đối với trường hợp thứ hai, không cần chỉ định số lượng (đối với trường hợp thay thế) hoặc trường hợp (đối với trường hợp không thể thay thế) và tất cả đều khớp.
👉 Holding Register
Cuối cùng là MultiAssetFilter. Đây là cách được sử dụng phổ biến nhất và thực sự chỉ là sự kết hợp giữa MultiAssets và WildMultiAsset, cho phép ký tự đại diện hoặc danh sách nội dung rõ ràng (nghĩa là không phải ký tự đại diện) được chỉ định.
WithdrawAsset(MultiAssets),
Trong Rust XCM API, chúng tôi cung cấp một số chuyển đổi để làm việc với các loại dữ liệu này dễ dàng nhất có thể. Ví dụ: khi chúng tôi tham gia chuỗi chuyển tiếp Polkadot, để chỉ định MultiAsset có thể thay thế (Planck, dành cho những người biết) bằng 100 đơn vị tài sản DOT không thể chia được, thì chúng tôi sẽ sử dụng (Ở đây, 100).into ().
Hãy xem một hướng dẫn khác của XCM: WithdrawAsset. Nhìn bề ngoài, điều này hơi giống với nửa đầu của TransferAsset: nó rút một số tài sản từ tài khoản ban đầu. Nhưng nó có liên quan gì đến họ? Nếu họ không gửi nó ở bất cứ đâu, thì đó phải là một hoạt động khá vô dụng. Nếu chúng ta nhìn vào tuyên bố Rust của nó, chúng ta sẽ tìm thấy nhiều manh mối hơn về cách sử dụng nó:
enum Instruction {
DepositAsset {
assets: MultiAssetFilter,
max_assets: u32,
beneficiary: MultiLocation,
},
/* snip */
}
Vì vậy, lần này chỉ có một tham số (loại MultiAssets, chỉ định tài sản nào phải được rút khỏi quyền sở hữu của Sổ đăng ký gốc). Nhưng nó không chỉ định nơi đặt tài sản.
Những tài sản chưa được sử dụng tạm thời này được gọi là Holding Registers. ("Giữ" vì chúng ở một vị trí tạm thời không tồn tại vô thời hạn và "Đăng ký" vì nó hơi giống Thanh ghi CPU, nơi lưu trữ dữ liệu đang hoạt động.) Có nhiều hướng dẫn hoạt động trên thanh ghi giữ. Một chỉ thị rất đơn giản là chỉ thị DepositAsset. Chúng ta hãy nhìn vào nó:
à! Những độc giả tinh ý sẽ nhận thấy rằng điều này trông giống như một nửa còn thiếu của chỉ thị TransferAsset. Chúng tôi có tham số nội dung, chỉ định nội dung nào sẽ bị xóa khỏi sổ đăng ký nắm giữ để gửi trên chuỗi. max_assets cho phép tác giả XCM thông báo cho người nhận số lượng tài sản duy nhất mà họ định gửi. (Điều này hữu ích khi tính phí trước khi biết nội dung của Sổ đăng ký nắm giữ, vì việc ký gửi tài sản có thể là một hoạt động tốn kém.) Cuối cùng là người thụ hưởng, đây là tham số giống như chúng ta đã gặp trước đó trong hoạt động Chuyển giao tài sản. Có nhiều lệnh đại diện cho các hành động được thực hiện trên Sổ đăng ký lưu giữ và DepositAsset là một trong những lệnh đơn giản nhất. Những người khác phức tạp hơn.
🤑 Thanh toán phí bằng XCM
Thanh toán phí trong XCM là một trường hợp sử dụng khá quan trọng. Hầu hết các parachains trong cộng đồng Polkadot sẽ yêu cầu người đối thoại của họ thanh toán cho bất kỳ hoạt động nào họ muốn, để không tạo cơ hội cho "spam giao dịch" và các cuộc tấn công từ chối dịch vụ. Các trường hợp ngoại lệ cũng tồn tại khi các chuỗi có lý do chính đáng để tin rằng những người đối thoại của họ sẽ cư xử tốt — đây là trường hợp khi chuỗi chuyển tiếp Polkadot giao tiếp với chuỗi lợi ích công cộng Polkadot Statemint. Tuy nhiên, đối với trường hợp chung, phí là một cách tốt để đảm bảo rằng các thông báo XCM và các giao thức vận chuyển của chúng không bị lạm dụng. Chúng ta hãy xem cách thanh toán phí khi tin nhắn XCM đến được Polkadot.
Như đã đề cập trước đó, XCM không bao gồm phí và các khoản thanh toán phí với tư cách là công dân hạng nhất: không giống như mô hình giao dịch Ethereum, để thanh toán phí là thứ không bắt buộc trong giao thức, nó phải được phá vỡ. Giống như khái niệm trừu tượng không có chi phí của Rust, thanh toán phí không có chi phí thiết kế đáng kể trong XCM.
Đối với các hệ thống yêu cầu thanh toán, XCM cung cấp khả năng sử dụng tài sản để mua tài nguyên thực thi. Nói chung, điều này bao gồm ba phần:
Đầu tiên, một số tài sản cần phải được cung cấp.
Thứ hai, tài sản phải được đổi lấy thời gian tính toán (trọng lượng theo cách nói của Chất nền).
Cuối cùng, thao tác XCM sẽ thực hiện theo chỉ dẫn.
WithdrawAsset((Here, 10_000_000_000).into()),
Phần đầu tiên được quản lý bởi một trong số các chỉ thị XCM cung cấp nội dung. Chúng tôi đã biết một trong những lệnh này ( WithdrawAsset ), nhưng có một số lệnh khác mà chúng tôi sẽ xem xét sau. Tất nhiên, tài sản kết quả trong Sổ đăng ký nắm giữ sẽ được sử dụng để thanh toán các chi phí liên quan đến việc thực hiện XCM. Bất kỳ tài sản nào không được sử dụng để thanh toán phí sẽ được gửi vào tài khoản đích. Trong ví dụ của chúng tôi, chúng tôi giả định rằng XCM diễn ra trên chuỗi chuyển tiếp Polkadot và 1 DOT được giao dịch (tức là 10.000.000.000 đơn vị không thể chia nhỏ).
enum Instruction {
/* snip */
BuyExecution {
fees: MultiAsset,
weight: u64,
},
}
Hiện tại chỉ thị XCM của chúng tôi trông như thế này:
Điều này đưa chúng ta đến phần thứ hai, trao đổi (một phần) các tài sản này để đổi lấy thời gian tính toán để thanh toán cho chúng ta bằng XCM. Đối với điều này, chúng tôi có hướng dẫn XCM BuyExecution . Hãy xem nó trông như thế nào:
Phí mục đầu tiên là số tiền sẽ được rút từ Sổ đăng ký nắm giữ và được sử dụng để thanh toán phí. Về mặt kỹ thuật, đây chỉ là mức tối đa, vì mọi số dư chưa sử dụng sẽ được hoàn trả ngay lập tức.
WithdrawAsset((Here, 10_000_000_000).into()),
BuyExecution {
fees: (Here, 10_000_000_000).into(),
weight: 3_000_000,
},
Số tiền chi tiêu cuối cùng tùy thuộc vào hệ thống diễn giải - phí chỉ giới hạn ở mức đó và nếu hệ thống diễn giải cần trả nhiều tiền hơn cho việc thực hiện mong muốn, thì lệnh BuyExecution sẽ gây ra lỗi. Mục thứ hai chỉ định lượng thời gian thực hiện để mua. Điều này thường không được nhỏ hơn tổng trọng lượng của chương trình XCM.
Trong ví dụ của chúng tôi, chúng tôi giả định trọng số là 1 triệu cho tất cả các hướng dẫn XCM, cho đến nay chúng tôi có hai dự án (WithdrawAsset và BuyExecution) là 2 triệu và một dự án nữa sắp ra mắt. Chúng tôi sẽ chỉ sử dụng tất cả số DOT mà chúng tôi phải trả cho các khoản phí đó (điều này chỉ có ý nghĩa nếu chúng tôi tin tưởng chuỗi điểm đến không có các khoản phí điên rồ - giả sử đúng như vậy). Tại thời điểm này, hãy xem XCM của chúng tôi:
WithdrawAsset((Here, 10_000_000_000).into()),
BuyExecution {
fees: (Here, 10_000_000_000).into(),
weight: 3_000_000,
},
DepositAsset {
assets: All.into(),
max_assets: 1,
beneficiary: Parachain(1000).into(),
},Phần thứ ba của XCM của chúng tôi là gửi số tiền còn lại vào Sổ đăng ký nắm giữ. Đối với điều này, chúng tôi sẽ chỉ sử dụng chỉ thị DepositAsset. Chúng tôi thực sự không biết số tiền còn lại trong Sổ đăng ký nắm giữ, nhưng điều đó không thành vấn đề vì chúng tôi có thể chỉ định một ký tự đại diện cho các tài sản sẽ được ký gửi. Chúng tôi đặt chúng vào một tài khoản có chủ quyền trong Statemint (được xác định là Parachain(1000)).
Vì vậy, chỉ thị XCM cuối cùng của chúng tôi trông như thế này:
Gửi tài sản đến một chuỗi khác có lẽ là trường hợp sử dụng phổ biến nhất cho nhắn tin liên chuỗi. Việc cho phép một chuỗi quản lý tài sản có nguồn gốc từ một chuỗi khác sẽ cho phép nhiều trường hợp sử dụng phái sinh (không có ý định chơi chữ), đơn giản nhất là trao đổi phi tập trung, nhưng thường được gộp chung dưới tài chính phi tập trung hoặc De-Fi.
Nói chung, có hai cách để tài sản di chuyển giữa các chuỗi, tùy thuộc vào việc các chuỗi có tin tưởng vào tính bảo mật và logic của nhau hay không.
trình soạn thảo mdnice
✨ Dịch chuyển tức thời
WithdrawAsset((Here, 10_000_000_000).into()),
InitiateTeleport {
assets: All.into(),
dest: Parachain(1000).into(),
xcm: Xcm(vec![
BuyExecution {
fees: (Parent, 10_000_000_000).into(),
weight: 3_000_000,
},
DepositAsset {
assets: All.into(),
max_assets: 1,
beneficiary: Parent.into(),
},
]),
}
Đối với các chuỗi tin tưởng lẫn nhau (ví dụ: các phân đoạn đồng nhất dưới cùng một ô bảo mật và đồng thuận tổng thể), chúng ta có thể sử dụng khung của Polkadot có tên là dịch chuyển tức thời, về cơ bản có nghĩa là phá hủy tài sản ở bên gửi và đúc nó ở bên nhận. Phương pháp phòng thủ này vừa đơn giản vừa hiệu quả - nó chỉ yêu cầu sự phối hợp của hai chuỗi và chỉ liên quan đến một hành động ở mỗi bên. Thật không may, nếu chuỗi nhận không thể tin tưởng 100% rằng chuỗi gửi thực sự phá hủy tài sản mà nó đang đào (và thực tế không đúc tài sản ngoài các quy tắc đã thỏa thuận của tài sản), thì chuỗi gửi thực sự không có lý do gì để đúc tài sản dựa trên tin nhắn.
Chúng ta hãy xem XCM chuyển (hầu hết) 1 DOT từ chuỗi chuyển tiếp Polkadot sang tài khoản chủ quyền của nó trên Statemint trông như thế nào. Chúng tôi cho rằng Polkadot đã thanh toán phí.
Như bạn có thể thấy, mô hình này trông rất giống với mô hình gửi-rút-mua-gửi trực tiếp mà chúng ta đã thấy lần trước. Sự khác biệt là chỉ thị InitiateTeleport, được chèn xung quanh hai chỉ thị cuối cùng (BuyExecution và DepositAsset). Đằng sau hậu trường, chuỗi gửi (chuỗi chuyển tiếp Polkadot) đang tạo một thông báo hoàn toàn mới khi nó thực thi lệnh InitiateTeleport; nó lấy trường xcm và đặt nó vào một XCMReceiveTeleportedAsset mới, sau đó gửi XCM này đến chuỗi nhận (Statemint). Statemint tin rằng chuỗi chuyển tiếp Polkadot đã phá hủy 1 DOT bên phía nó trước khi gửi tin nhắn. (Và đúng như vậy!)
ReceiveTeleportedAsset((Parent, 10_000_000_000).into()),
BuyExecution {
fees: (Parent, 10_000_000_000).into(),
weight: 3_000_000,
},
DepositAsset {
assets: All.into(),
max_assets: 1,
beneficiary: Parent.into(),
},
Người thụ hưởng được khai báo là Parent.into() , độc giả thông minh có thể thắc mắc điều này đề cập đến điều gì trong ngữ cảnh của chuỗi chuyển tiếp Polkadot. Câu trả lời là "không có gì", nhưng không có gì sai ở đây cả. Mọi thứ trong tham số xcm được viết từ quan điểm của người nhận, vì vậy mặc dù đây là một phần của XCM tổng thể được đưa vào chuỗi chuyển tiếp Polkadot, nhưng nó thực sự chỉ được thực thi trên Statemint, vì vậy bối cảnh của nó được theo sau bởi Statemint đã biến mất.
Như bạn có thể nhận thấy, điều này trông rất giống với WithdrawAsset XCM trước đó. Sự khác biệt lớn duy nhất là thay vì trả phí cấp vốn và tiền gửi bằng cách rút tiền từ tài khoản cục bộ, nó tôn vinh thông báo ReceiveTeleportedAsset bằng cách tin tưởng rằng DOT thực sự được đốt trên người gửi (chuỗi chuyển tiếp Polkadot). Điều đáng chú ý là mã định danh nội dung của 1 DOT mà chúng tôi đã gửi trên chuỗi chuyển tiếp Polkadot (Ở đây, đề cập đến chính chuỗi chuyển tiếp là môi trường gốc của DOT) đã được tự động biến thành biểu diễn của nó trên Statemint: Parent. into(), vị trí của chuỗi chuyển tiếp trong bối cảnh Statemint.
Người thụ hưởng cũng được chỉ định là chuỗi chuyển tiếp Polkadot, vì vậy tài khoản có chủ quyền của họ (trên Statemint) được ghi có 1 DOT mới được đúc trừ phí. XCM có thể dễ dàng chỉ định một tài khoản cho người thụ hưởng hoặc tài khoản nào khác. Trên thực tế, 1 DOT này có thể được di chuyển bằng cách sử dụng TransferAsset tiếp theo được gửi từ chuỗi chuyển tiếp.
trình soạn thảo mdnice
🏦 Dự trữ
Một cách khác để chuyển tài sản qua các chuỗi phức tạp hơn một chút. Một bên thứ ba được gọi là dự trữ được sử dụng. Cái tên này xuất phát từ hệ thống dự trữ của ngân hàng, nơi tài sản được "dành riêng" để tạo uy tín cho những lời hứa giá trị được công bố nhất định. Ví dụ: nếu chúng tôi có lý do để tin rằng mỗi DOT "có nguồn gốc" được phát hành trên một parachain độc lập có thể được đổi lấy chính xác 1 DOT "thực" (chẳng hạn như Statemint hoặc DOT trên chuỗi chuyển tiếp), thì chúng tôi có thể tạo các DOT parachain là được coi là tương đương về mặt kinh tế với DOT thực. (Hầu hết các ngân hàng thực hiện ngân hàng dự trữ theo tỷ lệ, có nghĩa là họ giữ ít hơn mệnh giá trong khoản dự trữ. Điều này thường ổn, nhưng có thể nhanh chóng gặp trục trặc khi có quá nhiều người muốn mua lại.) Vì vậy, khoản dự trữ là nơi cất giữ "thực" tài sản, cho mục đích truyền tải, có logic và bảo mật được cả người gửi và người nhận tin cậy. Bất kỳ tài sản tương ứng nào trên người gửi và người nhận sẽ là công cụ phái sinh, nhưng chúng sẽ được hỗ trợ 100% bằng tài sản dự trữ "thực". Giả sử parachain hoạt động tốt (nghĩa là nó không có lỗi và việc quản trị của nó không quyết định đánh cắp dự trữ và chạy trốn), điều này sẽ làm cho các DOT phái sinh có giá trị gần bằng với các DOT dự trữ cơ bản. Tài sản dự trữ được giữ trong tài khoản có chủ quyền của người gửi/người nhận (tức là tài khoản do chuỗi người gửi hoặc người nhận kiểm soát) trên chuỗi dự trữ, vì vậy trừ khi có vấn đề với parachain, còn không thì có lý do chính đáng để tin rằng những tài sản này sẽ được bảo vệ tốt của.
WithdrawAsset((Parent, 10_000_000_000).into()),
InitiateReserveWithdraw {
assets: All.into(),
dest: ParentThen(Parachain(1000)).into(),
xcm: Xcm(vec![
BuyExecution {
fees: (Parent, 10_000_000_000).into(),
weight: 3_000_000,
},
DepositReserveAsset {
assets: All.into(),
max_assets: 1,
dest: ParentThen(Parachain(2001)).into(),
xcm: Xcm(vec![
BuyExecution {
fees: (Parent, 10_000_000_000).into(),
weight: 3_000_000,
},
DepositAsset {
assets: All.into(),
max_assets: 1,
beneficiary: ParentThen(Parachain(2000)).into(),
},
]),
},
]),
},
Quay trở lại cơ chế chuyển nhượng, người gửi sẽ hướng dẫn người dự trữ chuyển một tài sản thuộc sở hữu của người gửi (và sử dụng nó làm tài sản dự trữ cho phiên bản của chính tài sản đó) vào tài khoản chính phủ của người nhận và tài khoản dự trữ (thay vì bên gửi!) để thông báo cho bên nhận về nội dung mới của họ. Điều này có nghĩa là người gửi và người nhận không cần tin tưởng logic hoặc bảo mật của nhau mà chỉ cần tin tưởng logic hoặc bảo mật của chuỗi được sử dụng làm dự trữ. Tuy nhiên, điều đó có nghĩa là ba bên cần phải phối hợp, điều này làm tăng thêm chi phí, thời gian và độ phức tạp chung.
WithdrawAsset((Parent, 10_000_000_000).into()),
InitiateReserveWithdraw {
assets: All.into(),
dest: ParentThen(Parachain(1000)).into(),
xcm: /* snip */
}
Hãy xem xét XCM cần thiết. Lần này, chúng tôi sẽ gửi 1 DOT từ parachain 2000 đến parachain 2001, sử dụng DOT được hỗ trợ dự trữ trên parachain 1000. Một lần nữa, chúng tôi cho rằng phí đã được thanh toán tại người gửi.
/*snip*/
xcm: Xcm(vec![
BuyExecution {
fees: (Parent, 10_000_000_000).into(),
weight: 3_000_000,
},
DepositReserveAsset {
assets: All.into(),
max_assets: 1,
dest: ParentThen(Parachain(2001)).into(),
xcm: /* snip */
},
]),
/*snip*/
Như tôi đã nói trước đây, nó sẽ hơi phức tạp một chút. Hãy đi qua quá trình này. Phần bên ngoài chịu trách nhiệm rút 1 DOT trên người gửi (parachain 2000) và rút 1 DOT tương ứng trên Statemint (parachain 1000) - để làm điều này, nó sử dụng InitiateReserveWithdraw để thực hiện những gì nó nói .
/*snip*/
xcm: Xcm(vec![
BuyExecution {
fees: (Parent, 10_000_000_000).into(),
weight: 3_000_000,
},
DepositAsset {
assets: All.into(),
max_assets: 1,
beneficiary: ParentThen(Parachain(2000)).into(),
},
]),
/*snip*/
Bây giờ chúng tôi nắm giữ 1 DOT trong Sổ đăng ký nắm giữ của Statemint. Trước khi chúng tôi có thể làm bất cứ điều gì khác, chúng tôi cần mua một số thời gian thực hiện trên Statemint. Quá trình này cũng có vẻ quen thuộc:
ReserveAssetDeposited((Parent, 10_000_000_000).into()),
BuyExecution {
fees: (Parent, 10_000_000_000).into(),
weight: 3_000_000,
},
DepositAsset {
assets: All.into(),
max_assets: 1,
beneficiary: ParentThen(Parachain(2000)).into(),
},
Chúng tôi sử dụng 1 DOT của riêng mình để thanh toán phí và chúng tôi giả sử 1 triệu cho mỗi hoạt động XCM. Sau khi thanh toán cho một thao tác này, chúng tôi gửi 1 DOT (đã trừ phí và chúng tôi lười nên chỉ sử dụng All.into()) vào tài khoản chính chủ của Parachain 2001, nhưng điều này được thực hiện như một tài sản dự trữ, Điều này có nghĩa là rằng chúng tôi cũng yêu cầu Statemint gửi thông báo XCM tới chuỗi nhận này, thông báo về việc chuyển giao và một số hướng dẫn sẽ được thực hiện trên tài sản phái sinh thu được. Chỉ thị DepositReserveAsset không phải lúc nào cũng hoạt động; để nó hoạt động, đích phải là một vị trí mà tiền có thể được giữ một cách hợp lý trên chuỗi dự trữ và là nơi chuỗi dự trữ có thể gửi XCM đến. Brother parachains phù hợp chính xác với hóa đơn.
Phần cuối cùng xác định phần thông báo đến parachain 2001 . Giống như khi bắt đầu thao tác chuyển tiền, DepositReserveAsset soạn và gửi một tin nhắn mới, trong trường hợp này là ReserveAssetDeposited. Chính thông báo này, mặc dù chứa chương trình XCM mà chúng tôi đã xác định, nhưng lại đến được parachain nhận. Nó trông như thế này:
(Điều này giả định rằng Statemint không thực sự thu bất kỳ khoản phí nào và toàn bộ 1 DOT đã được thông qua. Điều này không đặc biệt thực tế, vì vậy các con số cho dòng tài sản có thể thấp hơn.) Phần lớn thông báo này sẽ trông quen thuộc ; điểm khác biệt đáng chú ý duy nhất so với thông báo ReceiveTeleportedAsset mà chúng ta đã thấy trong phần trước là chỉ thị cấp cao nhất ReserveAssetDeposited , nhằm đạt được mục đích tương tự, ngoại trừ việc nó cho biết "chuỗi gửi sẽ phá hủy nội dung để bạn có thể đúc một nội dung tương đương", có nghĩa là Nó là "chuỗi gửi đã nhận tài sản và giữ chúng cho bạn, vì vậy bạn có thể đúc các công cụ phái sinh được hỗ trợ bởi toàn bộ tài sản". Dù bằng cách nào, chuỗi đích sẽ đúc chúng vào Dự trữ lưu trữ và chúng tôi gửi chúng vào tài khoản có chủ quyền của người gửi trên chuỗi nhận. 🎉
“
🏁 Kết luận
