Hợp đồng ủy quyền là một công cụ quan trọng cho các nhà phát triển hợp đồng thông minh. Ngày nay, có nhiều chế độ ủy quyền và quy tắc sử dụng tương ứng trong hệ thống hợp đồng. Trước đây, chúng tôi đã phác thảo các phương pháp hay nhất về bảo mật hợp đồng proxy có thể nâng cấp.
Trong bài viết này, chúng tôi sẽ giới thiệu một mô hình proxy khác phổ biến trong cộng đồng lập trình viên, mô hình proxy kim cương.
Hợp đồng proxy kim cương, còn được gọi là "kim cương", là một mẫu thiết kế cho hợp đồng thông minh Ethereum được giới thiệu bởi Đề xuất cải tiến Ethereum (EIP) 2535.
Chế độ kim cương cho phép một hợp đồng có chức năng không giới hạn bằng cách chia chức năng của nó thành các hợp đồng nhỏ hơn (còn được gọi một cách khéo léo là "các khía cạnh"). Diamond hoạt động như một proxy, chức năng định tuyến gọi đến khía cạnh thích hợp.
Thiết kế của mô hình kim cương có thể giải quyết vấn đề giới hạn kích thước hợp đồng tối đa của mạng Ethereum. Bằng cách chia hợp đồng lớn thành các khía cạnh nhỏ hơn, mô hình kim cương cho phép các nhà phát triển xây dựng các hợp đồng thông minh phức tạp hơn và giàu tính năng hơn mà không bị ảnh hưởng bởi các hạn chế về kích thước.
Diamond Brokerage cung cấp sự linh hoạt to lớn so với các hợp đồng có thể nâng cấp truyền thống. Chúng cho phép nâng cấp các bộ phận hợp đồng, thêm, thay thế hoặc loại bỏ các bộ phận chức năng đã chọn mà không cần chạm vào các bộ phận khác.
Bài viết này cung cấp tổng quan về EIP-2535, bao gồm so sánh với chế độ proxy trong suốt và chế độ proxy UUPS được sử dụng rộng rãi, cũng như các cân nhắc về bảo mật của nó đối với cộng đồng nhà phát triển.
Trong ngữ cảnh của EIP-2535, "viên kim cương" là một hợp đồng ủy quyền có chức năng triển khai được cung cấp bởi các hợp đồng logic khác nhau, được gọi là "các khía cạnh".
Hãy tưởng tượng rằng một viên kim cương thật có các mặt khác nhau, được gọi là các mặt và các hợp đồng kim cương Ethereum tương ứng cũng có các mặt khác nhau. Mỗi hợp đồng của chức năng mượn kim cương là một khía cạnh hoặc khía cạnh khác nhau.
Tiêu chuẩn kim cương sử dụng phép loại suy để mở rộng khả năng của "vết cắt kim cương" để thêm, thay thế hoặc xóa các mặt và tính năng.
Ngoài ra, Diamond Standard cung cấp một tính năng gọi là "Diamond Loupe" trả về thông tin về các mặt và sự hiện diện của viên kim cương.
So với mô hình ủy quyền truyền thống, "viên kim cương" tương đương với hợp đồng ủy quyền và các "khía cạnh" khác nhau tương ứng với việc thực hiện hợp đồng. Các khía cạnh khác nhau của tác nhân kim cương có thể chia sẻ các hàm nội bộ, thư viện và biến trạng thái. Các thành phần chính của một viên kim cương như sau:
Hợp đồng trung tâm hoạt động như một proxy, chức năng định tuyến gọi đến khía cạnh thích hợp. Nó chứa ánh xạ các bộ chọn chức năng tới các địa chỉ "khía cạnh".
Một hợp đồng duy nhất thực hiện một chức năng cụ thể. Mỗi khía cạnh chứa một tập hợp các hàm có thể được gọi bởi viên kim cương.
là một tập hợp các chức năng tiêu chuẩn được xác định trong EIP-2535 cung cấp thông tin về bộ chọn khía cạnh và chức năng được sử dụng trong kim cương. Diamond Loupe cho phép các nhà phát triển và người dùng kiểm tra và hiểu cấu trúc của kim cương.
Các chức năng thêm, thay thế hoặc loại bỏ các mặt trong viên kim cương và bộ chọn đặc điểm tương ứng của chúng. Chỉ những địa chỉ được ủy quyền (ví dụ: chủ sở hữu viên kim cương hoặc hợp đồng có nhiều chữ ký) mới có thể thực hiện việc cắt kim cương.
Tương tự như các tác nhân truyền thống, khi một lệnh gọi hàm được thực hiện trên tác nhân kim cương, chức năng dự phòng của tác nhân (chức năng dự phòng) được kích hoạt. Sự khác biệt chính so với proxy kim cương là trong chức năng dự phòng, có một ánh xạ selectorToFacet, lưu trữ và xác định địa chỉ hợp đồng logic nào có triển khai chức năng được gọi. Sau đó, nó sử dụng một cuộc gọi ủy nhiệm để thực thi chức năng, giống như một proxy truyền thống.
Tất cả các proxy đều sử dụng hàm dự phòng () để ủy quyền các lệnh gọi hàm đến các địa chỉ bên ngoài. Dưới đây là cách triển khai proxy kim cương và cách triển khai proxy truyền thống.
Điều đáng chú ý là các khối mã hợp ngữ của chúng rất giống nhau, vì vậy điểm khác biệt duy nhất là địa chỉ khía cạnh trong lời gọi đại biểu proxy kim cương và địa chỉ hàm ý trong lời gọi đại biểu proxy truyền thống.
Sự khác biệt chính là trong proxy kim cương, địa chỉ của khía cạnh được xác định bởi hashmap từ msg.sig của người gọi (bộ chọn chức năng) đến địa chỉ của khía cạnh, trong khi ở proxy truyền thống, địa chỉ impl không phụ thuộc vào người gọi nhập.
Chức năng dự phòng đại lý kim cương
Chức năng dự phòng proxy truyền thống
Ánh xạ SelectorToFacet xác định hợp đồng nào chứa việc triển khai từng bộ chọn chức năng. Nhân viên dự án thường cần thêm, thay thế hoặc xóa ánh xạ hợp đồng giữa bộ chọn chức năng và triển khai. EIP-2535 quy định: Để đạt được mục đích này thì phải có hàm diamondCut(). Dưới đây là một giao diện ví dụ.
Mỗi cấu trúc FacetCut chứa một địa chỉ thuộc tính và một mảng bộ chọn tính năng bốn byte sẽ được cập nhật trong hợp đồng proxy kim cương. FaceCutAction cho phép một người thêm, thay thế và xóa bộ chọn tính năng. Việc triển khai chức năng diamondCut() phải bao gồm kiểm soát truy cập phù hợp, ngăn xung đột vị trí, khôi phục khi lỗi, v.v.
Để truy vấn tác nhân kim cương có những chức năng và mặt nào, chúng tôi sử dụng “kính lúp kim cương”. "Diamond Loupe" là một khía cạnh đặc biệt triển khai giao diện sau được xác định trong EIP-2535:
Hàm facets() sẽ trả về địa chỉ của tất cả các khía cạnh và bộ chọn hàm bốn byte của chúng. Hàm facetFunctionSelectors() sẽ trả về tất cả các bộ chọn hàm được hỗ trợ bởi một khía cạnh cụ thể. Hàm facetAddresses() sẽ trả về tất cả các địa chỉ khía cạnh được sử dụng bởi một viên kim cương.
Hàm facetAddress() sẽ trả về một khía cạnh hỗ trợ bộ chọn đã cho hoặc địa chỉ (0) nếu không tìm thấy. Lưu ý rằng không nên có nhiều hơn một địa chỉ khía cạnh có cùng bộ chọn tính năng.
Do các proxy kim cương ủy quyền các lệnh gọi chức năng khác nhau cho các hợp đồng triển khai khác nhau, điều quan trọng là phải quản lý các vị trí lưu trữ đúng cách để tránh xung đột. EIP-2535 đề cập đến một số phương pháp quản lý khe lưu trữ.
Khía cạnh này có thể khai báo các biến trạng thái trong cấu trúc. Khía cạnh này có thể sử dụng bất kỳ số lượng cấu trúc nào, mỗi cấu trúc có một vị trí lưu trữ khác nhau. Mỗi cấu trúc có một vị trí cụ thể trong lưu trữ hợp đồng. Các khía cạnh có thể khai báo các biến trạng thái của riêng chúng, nhưng chúng không thể xung đột với các vị trí lưu trữ của các biến trạng thái được khai báo bởi các khía cạnh khác. Một thư viện mẫu và hợp đồng lưu trữ kim cương được cung cấp trong EIP-2535, như thể hiện trong hình dưới đây:
Lưu trữ ứng dụng là một phiên bản lưu trữ kim cương chuyên biệt hơn. Mẫu này được sử dụng để chia sẻ các biến trạng thái của các khía cạnh một cách thuận tiện và dễ dàng hơn. Cấu trúc cửa hàng ứng dụng được xác định để chứa bất kỳ số lượng và loại biến trạng thái nào mà ứng dụng yêu cầu. Một khía cạnh luôn khai báo cấu trúc AppStorage là biến trạng thái đầu tiên và duy nhất, ở vị trí 0 của khe lưu trữ. Các khía cạnh khác nhau sau đó có thể truy cập các biến từ cấu trúc này.
Ngoài ra còn có các chiến lược quản lý khe lưu trữ khác, bao gồm cả sự kết hợp giữa Diamond Storage và AppStorage. Ví dụ: một số cấu trúc được chia sẻ giữa các khía cạnh khác nhau và một số cấu trúc dành riêng cho một khía cạnh cụ thể. Trong mọi trường hợp, điều rất quan trọng là phải ngăn ngừa các va chạm ngẫu nhiên của rãnh.
So sánh với Proxy trong suốt và Proxy UUPS
Hai chế độ proxy chính hiện được cộng đồng nhà phát triển Web3 sử dụng là chế độ proxy minh bạch và chế độ proxy UUPS. Trong phần này, chúng tôi so sánh ngắn gọn chế độ proxy kim cương với chế độ proxy trong suốt và chế độ proxy UUPS.
1.EPI-2535:
2.EPI-1967:
3.Triển khai tham chiếu proxy kim cương:
4.Triển khai OpenZeppelin:
Các giải pháp proxy và có thể mở rộng là các hệ thống phức tạp hơn và OpenZeppelin cung cấp cơ sở mã và tài liệu toàn diện cho các proxy có thể mở rộng UUPS, Minh bạch và Beacon. Tuy nhiên đối với chế độ proxy kim cương, mặc dù OpenZeppelin khẳng định lợi ích của nó nhưng họ vẫn quyết định không đưa triển khai kim cương EIP-2535 vào thư viện của mình.
Do đó, các nhà phát triển sử dụng thư viện bên thứ ba hiện có hoặc tự triển khai giải pháp này phải hết sức thận trọng khi triển khai. Ở đây chúng tôi đã biên soạn một danh sách kiểm tra các phương pháp hay nhất về bảo mật để cộng đồng nhà phát triển xem xét.
Bằng cách chia logic hợp đồng thành các mô-đun nhỏ hơn, dễ quản lý hơn, các nhà phát triển có thể dễ dàng kiểm tra và kiểm tra mã của họ hơn.
Ngoài ra, cách tiếp cận này cho phép các nhà phát triển tập trung vào các khía cạnh cụ thể của việc xây dựng và duy trì hợp đồng, thay vì quản lý một cơ sở mã nguyên khối, phức tạp. Kết quả cuối cùng là một cơ sở mã mô-đun và linh hoạt hơn, có thể dễ dàng cập nhật và sửa đổi mà không ảnh hưởng đến các phần khác của hợp đồng.
Nguồn: Aavegotchi Github
Khi hợp đồng proxy kim cương được triển khai, nó phải thêm địa chỉ của hợp đồng DiamondCutFacet vào hợp đồng proxy kim cương và triển khai hàm diamondCut(). Hàm diamondCut() được sử dụng để thêm, xóa hoặc thay thế các mặt và hàm, nếu không có DiamondCutFacet và diamondCut(), tác nhân kim cương không thể hoạt động bình thường.
Nguồn: Diamond-3-Hardhat của Mugen
Khi thêm một biến trạng thái mới vào cấu trúc lưu trữ trong hợp đồng thông minh, nó phải được thêm vào cuối cấu trúc. Việc thêm một biến trạng thái mới vào đầu hoặc ở giữa cấu trúc sẽ khiến biến trạng thái mới ghi đè lên dữ liệu biến trạng thái hiện có và bất kỳ biến trạng thái nào sau biến trạng thái mới có thể tham chiếu đến vị trí bộ nhớ sai.
Mẫu AppStorage yêu cầu một và chỉ một cấu trúc được khai báo cho proxy kim cương và cấu trúc này được chia sẻ bởi tất cả các khía cạnh. Nếu cần nhiều cấu trúc, nên sử dụng mẫu DiamondStorage.
Không đặt một cấu trúc trực tiếp bên trong một cấu trúc khác trừ khi bạn chắc chắn rằng mình không có ý định thêm nhiều biến trạng thái hơn vào cấu trúc bên trong. Không thể thêm các biến trạng thái mới vào các cấu trúc bên trong trong bản nâng cấp mà không ghi đè lên các khe lưu trữ biến được khai báo sau cấu trúc.
Giải pháp thay thế là thêm các biến trạng thái mới vào cấu trúc ánh xạ bộ nhớ thay vì đặt "struct" trực tiếp vào "struct". Các vị trí lưu trữ thay đổi trong bản đồ được tính toán khác nhau và không liền kề trong bộ lưu trữ.
Kích thước của mảng sẽ bị ảnh hưởng bởi kích thước của cấu trúc. Khi một biến trạng thái mới được thêm vào một cấu trúc, nó sẽ thay đổi kích thước và bố cục của cấu trúc đó.
Điều này có thể gây ra vấn đề nếu cấu trúc được sử dụng như một phần tử trong mảng. Nếu kích thước và bố cục của cấu trúc thay đổi thì kích thước và bố cục của mảng cũng sẽ thay đổi, điều này có thể gây ra sự cố với việc lập chỉ mục hoặc các hoạt động khác dựa trên kích thước và bố cục nhất quán của cấu trúc.
Tương tự như các mẫu proxy khác, mỗi biến phải có một vị trí lưu trữ duy nhất. Nếu không, hai cấu trúc khác nhau tại cùng một vị trí sẽ ghi đè lên nhau.
Hàm khởi tạo () thường được sử dụng để đặt các biến quan trọng, chẳng hạn như địa chỉ của các vai trò đặc quyền. Nếu nó không được khởi tạo khi hợp đồng được triển khai, một tác nhân độc hại có thể gọi và kiểm soát hợp đồng.
Bạn nên thêm kiểm soát truy cập thích hợp vào chức năng khởi tạo/thiết lập hoặc đảm bảo rằng chức năng được gọi khi hợp đồng được triển khai và không thể gọi lại.
Nếu bất kỳ khía cạnh nào của hợp đồng có thể gọi hàm tự hủy (), thì nó có khả năng hủy toàn bộ hợp đồng, dẫn đến mất tiền hoặc dữ liệu. Điều này cực kỳ nguy hiểm trong chế độ proxy kim cương, vì nhiều khía cạnh có thể truy cập vào kho lưu trữ và dữ liệu của hợp đồng proxy.
Hiện tại, chúng tôi thấy ngày càng có nhiều dự án áp dụng mô hình proxy kim cương trong các hợp đồng thông minh của họ. Nó cung cấp tính linh hoạt và các lợi thế khác so với proxy truyền thống.
Tuy nhiên, tính linh hoạt bổ sung cũng có nghĩa là bề mặt tấn công rộng hơn cho những kẻ tấn công. Chúng tôi hy vọng bài viết này sẽ giúp cộng đồng nhà phát triển hiểu cơ chế của mô hình proxy kim cương và những cân nhắc về bảo mật của nó.
Đồng thời, nhóm dự án nên tiến hành kiểm tra nghiêm ngặt và kiểm toán của bên thứ ba để giảm nguy cơ lỗ hổng liên quan đến việc thực hiện các hợp đồng đại lý kim cương.
Xem bản gốc
Nội dung chỉ mang tính chất tham khảo, không phải là lời chào mời hay đề nghị. Không cung cấp tư vấn về đầu tư, thuế hoặc pháp lý. Xem Tuyên bố miễn trừ trách nhiệm để biết thêm thông tin về rủi ro.
Thực hành bảo mật tốt nhất cho hợp đồng đại lý kim cương
Hợp đồng ủy quyền là một công cụ quan trọng cho các nhà phát triển hợp đồng thông minh. Ngày nay, có nhiều chế độ ủy quyền và quy tắc sử dụng tương ứng trong hệ thống hợp đồng. Trước đây, chúng tôi đã phác thảo các phương pháp hay nhất về bảo mật hợp đồng proxy có thể nâng cấp.
Trong bài viết này, chúng tôi sẽ giới thiệu một mô hình proxy khác phổ biến trong cộng đồng lập trình viên, mô hình proxy kim cương.
Hợp đồng proxy kim cương, còn được gọi là "kim cương", là một mẫu thiết kế cho hợp đồng thông minh Ethereum được giới thiệu bởi Đề xuất cải tiến Ethereum (EIP) 2535.
Chế độ kim cương cho phép một hợp đồng có chức năng không giới hạn bằng cách chia chức năng của nó thành các hợp đồng nhỏ hơn (còn được gọi một cách khéo léo là "các khía cạnh"). Diamond hoạt động như một proxy, chức năng định tuyến gọi đến khía cạnh thích hợp.
Thiết kế của mô hình kim cương có thể giải quyết vấn đề giới hạn kích thước hợp đồng tối đa của mạng Ethereum. Bằng cách chia hợp đồng lớn thành các khía cạnh nhỏ hơn, mô hình kim cương cho phép các nhà phát triển xây dựng các hợp đồng thông minh phức tạp hơn và giàu tính năng hơn mà không bị ảnh hưởng bởi các hạn chế về kích thước.
Diamond Brokerage cung cấp sự linh hoạt to lớn so với các hợp đồng có thể nâng cấp truyền thống. Chúng cho phép nâng cấp các bộ phận hợp đồng, thêm, thay thế hoặc loại bỏ các bộ phận chức năng đã chọn mà không cần chạm vào các bộ phận khác.
Bài viết này cung cấp tổng quan về EIP-2535, bao gồm so sánh với chế độ proxy trong suốt và chế độ proxy UUPS được sử dụng rộng rãi, cũng như các cân nhắc về bảo mật của nó đối với cộng đồng nhà phát triển.
Trong ngữ cảnh của EIP-2535, "viên kim cương" là một hợp đồng ủy quyền có chức năng triển khai được cung cấp bởi các hợp đồng logic khác nhau, được gọi là "các khía cạnh".
Hãy tưởng tượng rằng một viên kim cương thật có các mặt khác nhau, được gọi là các mặt và các hợp đồng kim cương Ethereum tương ứng cũng có các mặt khác nhau. Mỗi hợp đồng của chức năng mượn kim cương là một khía cạnh hoặc khía cạnh khác nhau.
Tiêu chuẩn kim cương sử dụng phép loại suy để mở rộng khả năng của "vết cắt kim cương" để thêm, thay thế hoặc xóa các mặt và tính năng.
Ngoài ra, Diamond Standard cung cấp một tính năng gọi là "Diamond Loupe" trả về thông tin về các mặt và sự hiện diện của viên kim cương.
So với mô hình ủy quyền truyền thống, "viên kim cương" tương đương với hợp đồng ủy quyền và các "khía cạnh" khác nhau tương ứng với việc thực hiện hợp đồng. Các khía cạnh khác nhau của tác nhân kim cương có thể chia sẻ các hàm nội bộ, thư viện và biến trạng thái. Các thành phần chính của một viên kim cương như sau:
Hợp đồng trung tâm hoạt động như một proxy, chức năng định tuyến gọi đến khía cạnh thích hợp. Nó chứa ánh xạ các bộ chọn chức năng tới các địa chỉ "khía cạnh".
Một hợp đồng duy nhất thực hiện một chức năng cụ thể. Mỗi khía cạnh chứa một tập hợp các hàm có thể được gọi bởi viên kim cương.
là một tập hợp các chức năng tiêu chuẩn được xác định trong EIP-2535 cung cấp thông tin về bộ chọn khía cạnh và chức năng được sử dụng trong kim cương. Diamond Loupe cho phép các nhà phát triển và người dùng kiểm tra và hiểu cấu trúc của kim cương.
Các chức năng thêm, thay thế hoặc loại bỏ các mặt trong viên kim cương và bộ chọn đặc điểm tương ứng của chúng. Chỉ những địa chỉ được ủy quyền (ví dụ: chủ sở hữu viên kim cương hoặc hợp đồng có nhiều chữ ký) mới có thể thực hiện việc cắt kim cương.
Tương tự như các tác nhân truyền thống, khi một lệnh gọi hàm được thực hiện trên tác nhân kim cương, chức năng dự phòng của tác nhân (chức năng dự phòng) được kích hoạt. Sự khác biệt chính so với proxy kim cương là trong chức năng dự phòng, có một ánh xạ selectorToFacet, lưu trữ và xác định địa chỉ hợp đồng logic nào có triển khai chức năng được gọi. Sau đó, nó sử dụng một cuộc gọi ủy nhiệm để thực thi chức năng, giống như một proxy truyền thống.
Tất cả các proxy đều sử dụng hàm dự phòng () để ủy quyền các lệnh gọi hàm đến các địa chỉ bên ngoài. Dưới đây là cách triển khai proxy kim cương và cách triển khai proxy truyền thống.
Điều đáng chú ý là các khối mã hợp ngữ của chúng rất giống nhau, vì vậy điểm khác biệt duy nhất là địa chỉ khía cạnh trong lời gọi đại biểu proxy kim cương và địa chỉ hàm ý trong lời gọi đại biểu proxy truyền thống.
Sự khác biệt chính là trong proxy kim cương, địa chỉ của khía cạnh được xác định bởi hashmap từ msg.sig của người gọi (bộ chọn chức năng) đến địa chỉ của khía cạnh, trong khi ở proxy truyền thống, địa chỉ impl không phụ thuộc vào người gọi nhập.
Chức năng dự phòng đại lý kim cương
Chức năng dự phòng proxy truyền thống
Ánh xạ SelectorToFacet xác định hợp đồng nào chứa việc triển khai từng bộ chọn chức năng. Nhân viên dự án thường cần thêm, thay thế hoặc xóa ánh xạ hợp đồng giữa bộ chọn chức năng và triển khai. EIP-2535 quy định: Để đạt được mục đích này thì phải có hàm diamondCut(). Dưới đây là một giao diện ví dụ.
Mỗi cấu trúc FacetCut chứa một địa chỉ thuộc tính và một mảng bộ chọn tính năng bốn byte sẽ được cập nhật trong hợp đồng proxy kim cương. FaceCutAction cho phép một người thêm, thay thế và xóa bộ chọn tính năng. Việc triển khai chức năng diamondCut() phải bao gồm kiểm soát truy cập phù hợp, ngăn xung đột vị trí, khôi phục khi lỗi, v.v.
Để truy vấn tác nhân kim cương có những chức năng và mặt nào, chúng tôi sử dụng “kính lúp kim cương”. "Diamond Loupe" là một khía cạnh đặc biệt triển khai giao diện sau được xác định trong EIP-2535:
Hàm facets() sẽ trả về địa chỉ của tất cả các khía cạnh và bộ chọn hàm bốn byte của chúng. Hàm facetFunctionSelectors() sẽ trả về tất cả các bộ chọn hàm được hỗ trợ bởi một khía cạnh cụ thể. Hàm facetAddresses() sẽ trả về tất cả các địa chỉ khía cạnh được sử dụng bởi một viên kim cương.
Hàm facetAddress() sẽ trả về một khía cạnh hỗ trợ bộ chọn đã cho hoặc địa chỉ (0) nếu không tìm thấy. Lưu ý rằng không nên có nhiều hơn một địa chỉ khía cạnh có cùng bộ chọn tính năng.
Do các proxy kim cương ủy quyền các lệnh gọi chức năng khác nhau cho các hợp đồng triển khai khác nhau, điều quan trọng là phải quản lý các vị trí lưu trữ đúng cách để tránh xung đột. EIP-2535 đề cập đến một số phương pháp quản lý khe lưu trữ.
Khía cạnh này có thể khai báo các biến trạng thái trong cấu trúc. Khía cạnh này có thể sử dụng bất kỳ số lượng cấu trúc nào, mỗi cấu trúc có một vị trí lưu trữ khác nhau. Mỗi cấu trúc có một vị trí cụ thể trong lưu trữ hợp đồng. Các khía cạnh có thể khai báo các biến trạng thái của riêng chúng, nhưng chúng không thể xung đột với các vị trí lưu trữ của các biến trạng thái được khai báo bởi các khía cạnh khác. Một thư viện mẫu và hợp đồng lưu trữ kim cương được cung cấp trong EIP-2535, như thể hiện trong hình dưới đây:
Lưu trữ ứng dụng là một phiên bản lưu trữ kim cương chuyên biệt hơn. Mẫu này được sử dụng để chia sẻ các biến trạng thái của các khía cạnh một cách thuận tiện và dễ dàng hơn. Cấu trúc cửa hàng ứng dụng được xác định để chứa bất kỳ số lượng và loại biến trạng thái nào mà ứng dụng yêu cầu. Một khía cạnh luôn khai báo cấu trúc AppStorage là biến trạng thái đầu tiên và duy nhất, ở vị trí 0 của khe lưu trữ. Các khía cạnh khác nhau sau đó có thể truy cập các biến từ cấu trúc này.
Ngoài ra còn có các chiến lược quản lý khe lưu trữ khác, bao gồm cả sự kết hợp giữa Diamond Storage và AppStorage. Ví dụ: một số cấu trúc được chia sẻ giữa các khía cạnh khác nhau và một số cấu trúc dành riêng cho một khía cạnh cụ thể. Trong mọi trường hợp, điều rất quan trọng là phải ngăn ngừa các va chạm ngẫu nhiên của rãnh.
So sánh với Proxy trong suốt và Proxy UUPS
Hai chế độ proxy chính hiện được cộng đồng nhà phát triển Web3 sử dụng là chế độ proxy minh bạch và chế độ proxy UUPS. Trong phần này, chúng tôi so sánh ngắn gọn chế độ proxy kim cương với chế độ proxy trong suốt và chế độ proxy UUPS.
1.EPI-2535:
2.EPI-1967:
3.Triển khai tham chiếu proxy kim cương:
4.Triển khai OpenZeppelin:
Các giải pháp proxy và có thể mở rộng là các hệ thống phức tạp hơn và OpenZeppelin cung cấp cơ sở mã và tài liệu toàn diện cho các proxy có thể mở rộng UUPS, Minh bạch và Beacon. Tuy nhiên đối với chế độ proxy kim cương, mặc dù OpenZeppelin khẳng định lợi ích của nó nhưng họ vẫn quyết định không đưa triển khai kim cương EIP-2535 vào thư viện của mình.
Do đó, các nhà phát triển sử dụng thư viện bên thứ ba hiện có hoặc tự triển khai giải pháp này phải hết sức thận trọng khi triển khai. Ở đây chúng tôi đã biên soạn một danh sách kiểm tra các phương pháp hay nhất về bảo mật để cộng đồng nhà phát triển xem xét.
Bằng cách chia logic hợp đồng thành các mô-đun nhỏ hơn, dễ quản lý hơn, các nhà phát triển có thể dễ dàng kiểm tra và kiểm tra mã của họ hơn.
Ngoài ra, cách tiếp cận này cho phép các nhà phát triển tập trung vào các khía cạnh cụ thể của việc xây dựng và duy trì hợp đồng, thay vì quản lý một cơ sở mã nguyên khối, phức tạp. Kết quả cuối cùng là một cơ sở mã mô-đun và linh hoạt hơn, có thể dễ dàng cập nhật và sửa đổi mà không ảnh hưởng đến các phần khác của hợp đồng.
Nguồn: Aavegotchi Github
Khi hợp đồng proxy kim cương được triển khai, nó phải thêm địa chỉ của hợp đồng DiamondCutFacet vào hợp đồng proxy kim cương và triển khai hàm diamondCut(). Hàm diamondCut() được sử dụng để thêm, xóa hoặc thay thế các mặt và hàm, nếu không có DiamondCutFacet và diamondCut(), tác nhân kim cương không thể hoạt động bình thường.
Nguồn: Diamond-3-Hardhat của Mugen
Khi thêm một biến trạng thái mới vào cấu trúc lưu trữ trong hợp đồng thông minh, nó phải được thêm vào cuối cấu trúc. Việc thêm một biến trạng thái mới vào đầu hoặc ở giữa cấu trúc sẽ khiến biến trạng thái mới ghi đè lên dữ liệu biến trạng thái hiện có và bất kỳ biến trạng thái nào sau biến trạng thái mới có thể tham chiếu đến vị trí bộ nhớ sai.
Mẫu AppStorage yêu cầu một và chỉ một cấu trúc được khai báo cho proxy kim cương và cấu trúc này được chia sẻ bởi tất cả các khía cạnh. Nếu cần nhiều cấu trúc, nên sử dụng mẫu DiamondStorage.
Không đặt một cấu trúc trực tiếp bên trong một cấu trúc khác trừ khi bạn chắc chắn rằng mình không có ý định thêm nhiều biến trạng thái hơn vào cấu trúc bên trong. Không thể thêm các biến trạng thái mới vào các cấu trúc bên trong trong bản nâng cấp mà không ghi đè lên các khe lưu trữ biến được khai báo sau cấu trúc.
Giải pháp thay thế là thêm các biến trạng thái mới vào cấu trúc ánh xạ bộ nhớ thay vì đặt "struct" trực tiếp vào "struct". Các vị trí lưu trữ thay đổi trong bản đồ được tính toán khác nhau và không liền kề trong bộ lưu trữ.
Kích thước của mảng sẽ bị ảnh hưởng bởi kích thước của cấu trúc. Khi một biến trạng thái mới được thêm vào một cấu trúc, nó sẽ thay đổi kích thước và bố cục của cấu trúc đó.
Điều này có thể gây ra vấn đề nếu cấu trúc được sử dụng như một phần tử trong mảng. Nếu kích thước và bố cục của cấu trúc thay đổi thì kích thước và bố cục của mảng cũng sẽ thay đổi, điều này có thể gây ra sự cố với việc lập chỉ mục hoặc các hoạt động khác dựa trên kích thước và bố cục nhất quán của cấu trúc.
Tương tự như các mẫu proxy khác, mỗi biến phải có một vị trí lưu trữ duy nhất. Nếu không, hai cấu trúc khác nhau tại cùng một vị trí sẽ ghi đè lên nhau.
Hàm khởi tạo () thường được sử dụng để đặt các biến quan trọng, chẳng hạn như địa chỉ của các vai trò đặc quyền. Nếu nó không được khởi tạo khi hợp đồng được triển khai, một tác nhân độc hại có thể gọi và kiểm soát hợp đồng.
Bạn nên thêm kiểm soát truy cập thích hợp vào chức năng khởi tạo/thiết lập hoặc đảm bảo rằng chức năng được gọi khi hợp đồng được triển khai và không thể gọi lại.
Nếu bất kỳ khía cạnh nào của hợp đồng có thể gọi hàm tự hủy (), thì nó có khả năng hủy toàn bộ hợp đồng, dẫn đến mất tiền hoặc dữ liệu. Điều này cực kỳ nguy hiểm trong chế độ proxy kim cương, vì nhiều khía cạnh có thể truy cập vào kho lưu trữ và dữ liệu của hợp đồng proxy.
Hiện tại, chúng tôi thấy ngày càng có nhiều dự án áp dụng mô hình proxy kim cương trong các hợp đồng thông minh của họ. Nó cung cấp tính linh hoạt và các lợi thế khác so với proxy truyền thống.
Tuy nhiên, tính linh hoạt bổ sung cũng có nghĩa là bề mặt tấn công rộng hơn cho những kẻ tấn công. Chúng tôi hy vọng bài viết này sẽ giúp cộng đồng nhà phát triển hiểu cơ chế của mô hình proxy kim cương và những cân nhắc về bảo mật của nó.
Đồng thời, nhóm dự án nên tiến hành kiểm tra nghiêm ngặt và kiểm toán của bên thứ ba để giảm nguy cơ lỗ hổng liên quan đến việc thực hiện các hợp đồng đại lý kim cương.