Tác giả: Gimer Cervera, nhà phát triển hợp đồng thông minh Ethereum Bản dịch: Shan Ouba, Golden Finance< /p>
Giới thiệu
Bài viết này giới thiệu loạt bài cung cấp cái nhìn sâu sắc về Máy ảo Ethereum (EVM) và Solidity Assembly để tối ưu hóa và bảo mật hợp đồng thông minh.
Máy ảo Ethereum (EVM) là thành phần cốt lõi của mạng Ethereum. EVM là phần mềm cho phép triển khai và thực hiện các hợp đồng thông minh được viết bằng các ngôn ngữ cấp cao như Solidity. Sau khi hợp đồng được viết, nó sẽ được biên dịch thành mã byte và triển khai vào EVM. EVM chạy trên mọi nút trên mạng Ethereum.
Solidity Assembly là ngôn ngữ lập trình cấp thấp cho phép các nhà phát triển viết mã ở cấp độ gần với EVM hơn. Nó cung cấp khả năng kiểm soát chi tiết hơn đối với việc thực hiện hợp đồng thông minh, cho phép tối ưu hóa và tùy chỉnh không thể thực hiện được chỉ thông qua mã Solidity cấp cao hơn.
Ngôn ngữ được sử dụng để lắp ráp nội tuyến trong Solidity được gọi là Yul. Ngôn ngữ lập trình đóng vai trò trung gian để biên dịch thành mã byte EVM. Nó được thiết kế như một ngôn ngữ cấp thấp cho phép các nhà phát triển có quyền kiểm soát chi tiết hơn đối với việc thực hiện hợp đồng thông minh. Nó có thể được sử dụng ở chế độ độc lập hoặc lắp ráp nội tuyến trong Solidity. Yul được thiết kế như một ngôn ngữ dựa trên ngăn xếp cấp độ thấp cho phép các nhà phát triển viết mã tối ưu và hiệu quả hơn. Trước khi giải thích cách lắp ráp Solidity, chúng ta cần hiểu cách các thành phần của EVM hoạt động.
EVM là một máy trạng thái quasi-Turing hoàn chỉnh. Trong trường hợp này, thuật ngữ "gần như" có nghĩa là việc thực hiện quy trình bị giới hạn ở một số bước tính toán giới hạn, tùy thuộc vào lượng khí có sẵn cho bất kỳ việc thực hiện hợp đồng thông minh nhất định nào. Đây là cách Ethereum xử lý các vấn đề và tình huống bị đình trệ trong đó việc thực thi có thể (cố ý hoặc vô tình) chạy mãi mãi. Điều này tránh được sự tê liệt hoàn toàn của nền tảng Ethereum.
Gas là một khái niệm đo lường lượng tính toán cần thiết để hoàn thành một giao dịch trong Ethereum. Chi phí giao dịch được thanh toán bằng Ether và gắn liền với giá Gas và Gas. Mục tiêu của chúng tôi trong quá trình này là tìm hiểu cách giảm thiểu tổng lượng gas tiêu thụ mà không ảnh hưởng đến an ninh.
Vấn đề tối ưu hóa mã
Lắp ráp nội tuyến là một cách để truy cập EVM ở cấp độ thấp hơn phương pháp. Nó bỏ qua một số tính năng bảo mật quan trọng và kiểm tra Solidity. Việc sử dụng hợp lý lắp ráp nội tuyến có thể giảm đáng kể chi phí thực hiện. Tuy nhiên, bạn chỉ nên sử dụng nó cho những công việc cần đến nó và chỉ khi bạn biết mình đang làm gì. Việc sử dụng tập hợp nội tuyến để tối ưu hóa mã của bạn có thể đưa ra các vấn đề bảo mật mới vào mã của bạn. Để thành thạo việc lắp ráp nội tuyến, chúng ta cần hiểu cách EVM và các thành phần của nó hoạt động.
Trong EVM, bạn phải trả tiền mỗi lần truy cập vào bất kỳ biến được lưu trữ nào lần đầu tiên. Điều này được gọi là "cold" truy cập và tốn 2100 gas. Lần truy cập thứ hai hoặc liên tiếp được gọi là quyền truy cập "nóng" và tốn 100 Gas.
Đoạn mã sau đây là ví dụ về cách chúng ta có thể sử dụng Yul để tối ưu hóa mã của mình. Hàm SetData1 đặt giá trị mới cho giá trị biến toàn cục theo cách truyền thống bằng cách sử dụng Solidity. Lần đầu tiên chúng tôi phân bổ giá trị mới này tốn 22514 gas. Cái thứ hai có giá thấp hơn nhiều, 5414 Gas.
Giới thiệu
Bài viết này giới thiệu loạt bài tìm hiểu sâu về Máy ảo Ethereum ( EVM) ) và Solidity Assembly để tối ưu hóa và bảo mật hợp đồng thông minh.
Máy ảo Ethereum (EVM) là thành phần cốt lõi của mạng Ethereum. EVM là phần mềm cho phép triển khai và thực hiện các hợp đồng thông minh được viết bằng các ngôn ngữ cấp cao như Solidity. Sau khi hợp đồng được viết, nó sẽ được biên dịch thành mã byte và triển khai vào EVM. EVM chạy trên mọi nút trên mạng Ethereum.
Solidity Assembly là ngôn ngữ lập trình cấp thấp cho phép các nhà phát triển viết mã ở cấp độ gần với EVM hơn. Nó cung cấp khả năng kiểm soát chi tiết hơn đối với việc thực hiện hợp đồng thông minh, cho phép tối ưu hóa và tùy chỉnh không thể thực hiện được chỉ thông qua mã Solidity cấp cao hơn.
Ngôn ngữ được sử dụng để lắp ráp nội tuyến trong Solidity được gọi là Yul. Ngôn ngữ lập trình đóng vai trò trung gian để biên dịch thành mã byte EVM. Nó được thiết kế như một ngôn ngữ cấp thấp cho phép các nhà phát triển có quyền kiểm soát chi tiết hơn đối với việc thực hiện hợp đồng thông minh. Nó có thể được sử dụng ở chế độ độc lập hoặc lắp ráp nội tuyến trong Solidity. Yul được thiết kế như một ngôn ngữ dựa trên ngăn xếp cấp độ thấp cho phép các nhà phát triển viết mã tối ưu và hiệu quả hơn. Trước khi giải thích cách lắp ráp Solidity, chúng ta cần hiểu cách các thành phần của EVM hoạt động.
EVM là một máy trạng thái quasi-Turing hoàn chỉnh. Trong trường hợp này, thuật ngữ "gần như" có nghĩa là việc thực hiện quy trình bị giới hạn ở một số bước tính toán giới hạn, tùy thuộc vào lượng khí có sẵn cho bất kỳ việc thực hiện hợp đồng thông minh nhất định nào. Đây là cách Ethereum xử lý các vấn đề và tình huống bị đình trệ trong đó việc thực thi có thể (cố ý hoặc vô tình) chạy mãi mãi. Điều này tránh được sự tê liệt hoàn toàn của nền tảng Ethereum.
Gas là một khái niệm đo lường lượng tính toán cần thiết để hoàn thành một giao dịch trong Ethereum. Chi phí giao dịch được thanh toán bằng Ether và gắn liền với giá Gas và Gas. Mục tiêu của chúng tôi trong quá trình này là tìm hiểu cách giảm thiểu tổng lượng khí đốt tự nhiên tiêu thụ mà không ảnh hưởng đến sự an toàn.
Vấn đề tối ưu hóa mã
Lắp ráp nội tuyến là một cách để truy cập EVM ở cấp độ thấp hơn phương pháp. Nó bỏ qua một số tính năng bảo mật quan trọng và kiểm tra Solidity. Việc sử dụng hợp lý lắp ráp nội tuyến có thể giảm đáng kể chi phí thực hiện. Tuy nhiên, bạn chỉ nên sử dụng nó cho những công việc cần đến nó và chỉ khi bạn biết mình đang làm gì. Việc sử dụng tập hợp nội tuyến để tối ưu hóa mã của bạn có thể đưa ra các vấn đề bảo mật mới vào mã của bạn. Để thành thạo việc lắp ráp nội tuyến, chúng ta cần hiểu cách EVM và các thành phần của nó hoạt động.
Trong EVM, bạn phải trả tiền mỗi lần truy cập vào bất kỳ biến được lưu trữ nào lần đầu tiên. Điều này được gọi là "cold" truy cập và tốn 2100 gas. Lần truy cập thứ hai hoặc liên tiếp được gọi là lượt truy cập "nóng" và tốn 100 gas.
Đoạn mã sau đây là ví dụ về cách chúng ta có thể sử dụng Yul để tối ưu hóa mã của mình. Hàm SetData1 đặt giá trị mới cho giá trị biến toàn cục theo cách truyền thống bằng cách sử dụng Solidity. Lần đầu tiên chúng tôi phân bổ giá trị mới này tốn 22514 gas. Cái thứ hai có giá thấp hơn nhiều, tức là 5414 gas.
p> p>
Hàm setData2 triển khai tập hợp nội tuyến. Các khối tập hợp nội tuyến được đánh dấu bằng tập hợp { … }, trong đó mã trong dấu ngoặc nhọn là mã ngôn ngữ Yul. Không cần biết mã nguồn vào thời điểm này, chỉ cần nhớ rằng phần mềm đang truy cập vào không gian lưu trữ ở mức thấp hơn. Vì vậy, chi phí thực hiện sẽ thấp hơn.
Trong ví dụ của chúng tôi, việc sửa đổi giá trị lần đầu tiên sẽ tốn 22484 Gas. Nhiều lần liên tiếp, chi phí là 5384 Gas. Sự khác biệt có vẻ không đáng kể, nhưng chúng ta nên lưu ý rằng đoạn mã này có thể được thực thi hàng nghìn lần.
p> p>
Tại sao dung lượng lưu trữ lại đắt như vậy? Hãy nhớ rằng chúng ta đang ở trong một thế giới phi tập trung nơi dữ liệu không được lưu trữ ở một nơi mà trên hàng chục nghìn nút. Nó cũng phải dễ dàng có sẵn cho mọi nút trong mạng nếu các giao dịch trong tương lai cần truy cập hoặc thay đổi nó. Tổng chi phí của dữ liệu này bằng tổng dung lượng lưu trữ mà nó tiêu thụ và lượng tính toán cần thiết để tạo ra dữ liệu đó trên mạng.
Ngăn xếp, bộ lưu trữ và bộ nhớ EVM
EVM là một EVM dựa trên ngăn xếp Một máy hoạt động trên cấu trúc dữ liệu gọi là ngăn xếp, chứa các giá trị và thực hiện các thao tác. EVM có bộ hướng dẫn riêng (được gọi là opcode) được sử dụng để thực hiện các tác vụ như đọc và ghi lưu trữ, gọi các hợp đồng khác và thực hiện các phép toán. Ngăn xếp hoạt động theo kiểu nhập sau xuất trước (LIFO), xem Hình 1, có nghĩa là mục được chèn gần đây nhất được lưu trữ ở đầu ngăn xếp và là mục đầu tiên được xóa.
p> p>
Khi thực thi hợp đồng thông minh, EVM tạo ra bối cảnh thực thi chứa nhiều cấu trúc dữ liệu và biến trạng thái khác nhau. Sau khi thực hiện xong, ngữ cảnh thực thi sẽ bị loại bỏ để chuẩn bị cho hợp đồng tiếp theo. Trong quá trình thực thi, EVM duy trì bộ nhớ tạm thời không tồn tại giữa các giao dịch. EVM thực thi một máy xếp chồng có độ sâu 1024 mục. Mỗi mục là một từ 256 bit, kích thước này được chọn để tạo thuận lợi cho việc sử dụng mã hóa băm 256 bit và đường cong elip.
EVM có các thành phần sau, xem Hình 2:
Ngăn xếp: Ngăn xếp của EVM là cấu trúc dữ liệu hoạt động theo nguyên tắc nhập trước xuất trước (LIFO) và được sử dụng để lưu trữ các giá trị tạm thời trong quá trình thực thi hợp đồng thông minh.
Bộ nhớ: Bộ nhớ vĩnh viễn, một phần của trạng thái Ethereum, chỉ được khởi tạo về 0 trong lần đầu tiên.
Bộ nhớ: mảng byte có kích thước động, dễ thay đổi được sử dụng để lưu trữ dữ liệu trung gian trong quá trình thực hiện hợp đồng. Mỗi khi bối cảnh thực thi mới được tạo, bộ nhớ sẽ được khởi tạo về 0.
Calldata: Đây cũng là vùng lưu trữ dữ liệu dễ bay hơi, tương tự như bộ nhớ. Tuy nhiên nó lưu trữ dữ liệu bất biến. Nó được thiết kế để lưu giữ dữ liệu được gửi như một phần của giao dịch hợp đồng thông minh.
Bộ đếm chương trình: Bộ đếm chương trình (PC) trỏ tới lệnh tiếp theo sẽ được EVM thực thi. PC thường tăng thêm một byte sau khi lệnh được thực thi.
ROM ảo: Hợp đồng thông minh được lưu trữ dưới dạng mã byte trong khu vực này. ROM ảo chỉ đọc.
![7163262 byS0PEfxE9E3EAlqlseO5P36kgSUAJ4RXlEpWJxG.png](https://img.jinse.cn/7163262_watermarknone.png)
Ngăn xếp EVM
Trong kiến trúc này, các hướng dẫn của chương trình và dữ liệu được giữ trong bộ nhớ, việc thực thi chương trình được điều khiển bởi con trỏ ngăn xếp trỏ đến đỉnh ngăn xếp. Con trỏ ngăn xếp theo dõi vị trí trên ngăn xếp mà giá trị hoặc lệnh tiếp theo sẽ được lưu hoặc truy xuất. Khi chương trình chạy, nó sẽ thêm các giá trị vào ngăn xếp và thực hiện các thao tác trên các giá trị đã có sẵn. Khi mã muốn cộng hai số, nó sẽ đẩy các số đó vào ngăn xếp và sau đó thực hiện thao tác cộng trên hai giá trị trên cùng. Kết quả sau đó được trả về ngăn xếp.
p> p>
Một trong những tính năng quan trọng nhất của kiến trúc dựa trên ngăn xếp là nó cho phép thực hiện các hoạt động rất đơn giản và hiệu quả. Vì ngăn xếp là cấu trúc dữ liệu LIFO nên dữ liệu và hướng dẫn có thể được xử lý dễ dàng và nhanh chóng.
EVM có bộ hướng dẫn riêng gọi là opcode. Opcode được sử dụng để thực hiện các tác vụ như đọc và ghi lưu trữ, gọi các hợp đồng khác và thực hiện các phép toán. Tập lệnh EVM cung cấp hầu hết các thao tác mà bạn có thể mong đợi, bao gồm:
Thao tác ngăn xếp: POP , PUSH, DUP, SWAP
Số học/so sánh/bitwise: ADD, SUB, GT, LT, AND, OR p>
Môi trường: NGƯỜI GỌI, CALLVALUE, SỐ
Hoạt động bộ nhớ: MLOAD, MSTORE, MSTORE8, MSIZE
Hoạt động lưu trữ: SLOAD, SSTORE
Các mã hoạt động liên quan đến bộ đếm chương trình: JUMP, JUMPI, PC, JUMPDEST
Dừng các mã hoạt động: STOP, RETURN, REVERT, INVALID, SELFDESTRUCT
Bộ lưu trữ EVM
Bộ lưu trữ EVM là không gian cố định lưu trữ các cặp khóa-giá trị 256-bit –> 256-bit. Tổng số slot lưu trữ trong hợp đồng là 22⁵⁶, đây là một số lượng slot rất lớn. Mỗi hợp đồng thông minh trên blockchain đều có không gian lưu trữ riêng.
Trong khi gọi hàm, lưu trữ dữ liệu cần ghi nhớ giữa các lệnh gọi hàm. Nó được sử dụng để lưu trữ các biến và cấu trúc dữ liệu cần có sẵn ngay cả sau khi quá trình thực hiện hợp đồng thông minh kết thúc.
p> p>
Mã hoạt động để truy cập bộ nhớ là: SLOAD và SSTORE
Bộ nhớ của tài khoản này là nơi lưu trữ dữ liệu vĩnh viễn, chỉ được sử dụng bởi các hợp đồng thông minh. Tài khoản thuộc sở hữu bên ngoài (EOA) sẽ luôn không có mã và bộ nhớ trống.
Bộ nhớ EVM
Bộ nhớ là bộ nhớ dễ thay đổi trong kiến trúc và dữ liệu của nó nằm trong khu vực Không có sự kiên trì trong blockchain. Bộ nhớ là cấu trúc dữ liệu truy cập ngẫu nhiên để lưu trữ dữ liệu tạm thời trong quá trình thực hiện hợp đồng thông minh.
p> p>
Bộ nhớ được chia thành 4 phần: 2 khe cho không gian đầu, 1 khe cho con trỏ bộ nhớ trống, 0 khe và 1 khe trỏ đến bộ nhớ trống khả dụng. 64 byte không gian đầu tiên sẽ được sử dụng bằng các phương pháp băm, yêu cầu không gian tạm thời để lưu trữ đầu ra trung gian trước khi trả về đầu ra cuối cùng.
Con trỏ bộ nhớ trống chỉ là con trỏ tới điểm bắt đầu của bộ nhớ trống. Nó đảm bảo rằng hợp đồng thông minh theo dõi vị trí bộ nhớ nào đã được ghi vào và vị trí nào vẫn còn trống. Điều này ngăn hợp đồng ghi đè lên một số bộ nhớ đã được phân bổ cho một biến khác. Hình 6 cho thấy cách phân chia bộ nhớ:
![7163293 g3imQHTd89wyatS2hNwKZHK4Ys4SANntyutufP7c.png](https://img.jinse.cn/7163293_watermarknone.png)
Bộ nhớ được sử dụng để lưu trữ các biến và cấu trúc dữ liệu không cần lưu trữ trong bộ nhớ. Kích thước bộ nhớ có thể được điều chỉnh trong quá trình thực hiện hợp đồng thông minh, nhưng quyền truy cập chậm hơn và đắt hơn so với ngăn xếp.
Hãy coi bộ nhớ được khởi tạo bằng 0 và các mã hoạt động được sử dụng để truy cập bộ nhớ là: MLOAD, MSTORE, MSTORE8
Tóm tắt
Trong bài viết này, chúng tôi xem xét một số khái niệm cơ bản liên quan đến Máy ảo Ethereum (EVM). Việc triển khai mã lắp ráp nội tuyến đòi hỏi sự hiểu biết sâu sắc về EVM. Điều này là do chúng tôi đang tương tác với một số thành phần của EVM. Trong các bài học sau, chúng ta sẽ phân tích các thành phần EVM khác chi tiết hơn, chẳng hạn như: Bộ nhớ, Bộ nhớ và Dữ liệu cuộc gọi. Ngoài ra, chúng tôi xem xét các khái niệm quan trọng như mã byte, Gas và Giao diện nhị phân ứng dụng (ABI). Cuối cùng, chúng ta sẽ thảo luận về cách hoạt động của opcode và nhiều ví dụ lắp ráp nội tuyến hơn để tối ưu hóa việc thực thi hợp đồng thông minh một cách an toàn.