Ý tưởng thiết kế của V God đã được công bố, nêu chi tiết những ưu điểm và nhược điểm tiềm ẩn của Ethereum
đâyđây, bản tái bản này đã được hiệu đính. Tôi xin bày tỏ lòng biết ơn đến dịch giả gốc Kim.
Thời gian viết văn bản gốc là không chắc chắn, nhưng nó có thể được coi là điểm khởi đầu để phản ánh khái niệm thiết kế của Ethereum và sự phát triển của Ethereum trong vài năm qua. Nó không chỉ để phản ánh về sự đổi mới của nó, mà còn để phản ánh về sự thiếu cân nhắc của nó.
về nguyên tắc
về nguyên tắc
Thiết kế của giao thức Ethereum tuân theo các nguyên tắc sau:
Sandwich Complex Model (còn được dịch là "mô hình phân lớp phức tạp"): Chúng tôi tin rằng giao thức cơ bản của Ethereum phải đơn giản nhất có thể và thiết kế giao diện phải dễ hiểu (cho dù đó là lập trình cấp cao hướng đến nhà phát triển giao diện ngôn ngữ hoặc giao diện sử dụng hướng đến người dùng). Những phần phức tạp không thể tránh khỏi đó nên được đặt ở lớp giữa. Lớp giữa không phải là một phần của sự đồng thuận cốt lõi và vô hình đối với người dùng cuối. Nó bao gồm: trình biên dịch ngôn ngữ cấp cao, tập lệnh tuần tự hóa và giải tuần tự hóa tham số, mô hình cấu trúc dữ liệu lưu trữ, giao diện lưu trữ leveldb và giao thức mạng. Tất nhiên, ranh giới phân biệt không hoàn toàn rõ ràng và đôi khi cần được điều chỉnh cho phù hợp.
Tự do: Người dùng không nên bị hạn chế sử dụng giao thức Ethereum, họ cũng không nên cố gắng ủng hộ hoặc không hỗ trợ một số hợp đồng hoặc giao dịch Ethereum nhất định. Điều này tương tự như các nguyên tắc hướng dẫn đằng sau khái niệm "tính trung lập ròng". Giao thức giao dịch Bitcoin không tuân theo nguyên tắc này: giao thức giao dịch Bitcoin không khuyến khích "mục đích ngoài phòng thí nghiệm" (ví dụ: lưu trữ dữ liệu, giao thức meta) của chuỗi khối (ghi chú hiệu đính: ngoài phòng thí nghiệm. Mục đích ban đầu là sử dụng thuốc cho các triệu chứng khác với chỉ định đã được phê duyệt, chẳng hạn như việc sử dụng thuốc ho để điều trị đau đầu. Ở đây, nó được diễn giải là "việc sử dụng không theo quy ước" ); và, đôi khi, một số người sử dụng các thay đổi lớp gần như giao thức (ví dụ: giới hạn độ dài của trường OP_RETURN thành 40 byte) để tấn công các ứng dụng sử dụng chuỗi khối theo cách "trái phép" Propensity). Do đó, trong Ethereum, chúng tôi kiên quyết ủng hộ phương pháp chỉ sử dụng phí giao dịch để đạt được khả năng tương thích gần như khuyến khích - người dùng càng tiêu thụ nhiều tài nguyên trong toàn bộ mạng, mức giá họ phải trả càng cao, ngay cả khi họ tự chịu chi phí (tức là Pigou Thuế).
Tổng quát hóa: Các thuộc tính và mã lệnh của giao thức Ethereum nên tối đa hóa các khái niệm cấp thấp (như các hạt cơ bản), để chúng có thể được kết hợp theo ý muốn, bao gồm cả việc kết hợp những thứ dường như vô dụng ngày nay, nhưng có thể hữu ích trong tương lai. Ngoài ra, các khái niệm cấp thấp có thể được thực hiện hiệu quả hơn bằng cách loại bỏ chức năng không cần thiết. Một ví dụ về việc tuân theo nguyên tắc này là việc chúng tôi lựa chọn LOG opcode làm cách cung cấp thông tin cho dapp, thay vì ghi nhật ký tất cả các giao dịch và tin nhắn như trước đây. Trong những ngày đầu, khái niệm "thông điệp (tin nhắn)" hoàn toàn là một tập hợp nhiều khái niệm khác nhau, bao gồm "lệnh gọi hàm (gọi hàm)" và "thông tin sự kiện (sự kiện) mà các nhà quan sát bên ngoài quan tâm", và cả hai là hoàn toàn có thể tách rời.
Không có tính năng nào là tính năng lớn nhất: Để tuân theo nguyên tắc khái quát hóa, chúng tôi từ chối đưa các trường hợp sử dụng nâng cao đó vào giao thức, ngay cả đối với các trường hợp sử dụng thường xuyên sử dụng, chúng tôi sẽ không bao giờ làm như vậy. Nếu một người thực sự muốn triển khai các trường hợp sử dụng này, các giao thức phụ có thể được tạo trong hợp đồng (ví dụ: tiền tệ phụ dựa trên Ethereum, chuỗi bên Bitcoin/Litecoin/Dogecoin, v.v.). Ví dụ, Ethereum thiếu chức năng "khóa thời gian" tương tự như Bitcoin. Tuy nhiên, chức năng này có thể được mô phỏng thông qua giao thức sau: người dùng gửi gói dữ liệu đã ký đến một hợp đồng cụ thể để xử lý và nếu gói dữ liệu hợp lệ trong hợp đồng cụ thể, thì chức năng tương ứng sẽ được thực thi.
Không sợ rủi ro: Chúng tôi sẵn sàng chấp nhận rủi ro cao hơn nếu rủi ro gia tăng mang lại lợi ích có thể đo lường được (ví dụ: chuyển đổi trạng thái chung, giảm 50 lần thời gian tạo khối, hiệu quả đồng thuận, v.v.).
tiêu đề cấp đầu tiên
Giao thức lớp chuỗi khối
tiêu đề phụ
tài khoản, không phải UTXO 1
Bitcoin và nhiều biến thể của nó lưu trữ thông tin số dư của người dùng trong cấu trúc UTXO và toàn bộ trạng thái của hệ thống bao gồm một loạt "đầu ra chưa sử dụng" (bạn có thể coi những "đầu ra chưa sử dụng" này là tiền xu) (đọc lại Lưu ý: Tốt hơn ẩn dụ có thể là "cheque".). Mỗi UTXO có chủ sở hữu và thuộc tính giá trị riêng. Một giao dịch sẽ tạo ra một số UTXO mới trong khi sử dụng một số UTXO; và giao dịch phải tuân theo các yêu cầu về tính hợp lệ sau:
1. Mỗi đầu vào được tham chiếu phải hợp lệ và chưa được sử dụng 2. Chữ ký của giao dịch phải khớp với chữ ký của chủ sở hữu của mỗi đầu vào 3. Tổng giá trị của đầu vào phải bằng hoặc lớn hơn tổng giá trị của đầu ra .
Mô tả hình ảnh
- Sổ sách kế toán ba lần được sử dụng bởi Bitcoin -
Tuy nhiên, Ethereum đã từ bỏ sơ đồ UTXO và chuyển sang một phương pháp đơn giản hơn: sử dụng khái niệm trạng thái (state) để lưu trữ một loạt tài khoản, mỗi tài khoản có số dư riêng và dữ liệu dành riêng cho Ethereum (mã và bộ nhớ trong). Nếu số dư tài khoản của người khởi tạo giao dịch đủ để trả phí giao dịch, thì giao dịch hợp lệ và số tiền tương ứng sẽ được khấu trừ từ tài khoản của người khởi tạo và ghi có vào tài khoản nhận. Trong một số trường hợp, nếu có mã cần được thực thi trong tài khoản nhận, giao dịch sẽ kích hoạt việc thực thi mã, sau đó bộ nhớ trong của tài khoản có thể thay đổi và thậm chí có thể tạo thêm tin nhắn để gửi cho các tài khoản khác , dẫn đến các giao dịch mới xảy ra.
Mặc dù Ethereum không áp dụng khái niệm UTXO, nhưng UTXO có một số ưu điểm:
Mức độ bảo vệ quyền riêng tư cao hơn:Nếu người dùng sử dụng một địa chỉ mới cho mọi giao dịch, việc liên kết các tài khoản sẽ khó khăn. Điều này phù hợp với các hệ thống tiền tệ có yêu cầu bảo mật cao, nhưng không phù hợp với bất kỳ dapp nào. Bởi vì các dapp thường cần theo dõi trạng thái ràng buộc phức tạp của người dùng và trạng thái của các dapp không thể được phân chia đơn giản như trạng thái trong hệ thống tiền tệ.
Khả năng mở rộng tiềm năng:Về lý thuyết, UTXO phù hợp hơn với một số loại sơ đồ khả năng mở rộng (mô hình khả năng mở rộng), bởi vì chỉ những người nắm giữ cần có bằng chứng Merkel mới có thể chứng minh quyền sở hữu tiền tệ của họ, ngay cả khi mọi người (bao gồm cả chính TA) quên dữ liệu này và điều này một người thực sự bị thiệt hại, và những người khác không bị ảnh hưởng. Trong hệ thống tài khoản Ethereum, nếu mọi người mất phần cây Merkle tương ứng với một tài khoản, thì tài khoản đó sẽ không thể xử lý bất kỳ tin nhắn nào có thể ảnh hưởng đến nó, kể cả tin nhắn được gửi đến nó và nó sẽ không thể xử lý Nó. Tuy nhiên, UTXO không phải là thứ duy nhất có thể được mở rộng và có nhiều cách để mở rộng mà không cần dựa vào UTXO (không có phần mở rộng ở đây, Ghi chú của Người dịch).
Lợi ích của tài khoản như sau:
Tiết kiệm nhiều dung lượng: Nếu một tài khoản có 5 UTXO, thì dung lượng cần thiết sẽ giảm từ 300 byte xuống 30 byte khi chuyển từ chế độ UTXO sang chế độ tài khoản. Cách tính cụ thể như sau: 300 = (20+32+8) * 5 (20 là số byte địa chỉ, 32 là số byte id TX và 8 là số byte chiếm giữ bởi mệnh giá); 30 = 20 + 8 + 2 ( 20 là byte địa chỉ, 8 là byte giá trị số dư tài khoản, 2 là 2 byte nonce); nhưng mức tiết kiệm thực tế không lớn đến thế, vì các tài khoản cần được lưu trữ trong cây Patricia. Ngoài ra, các giao dịch trong Ethereum nhỏ hơn so với giao dịch trong Bitcoin (100 byte trong Ethereum, 200-250 byte trong Bitcoin), bởi vì mỗi giao dịch chỉ cần tạo một tham chiếu, một chữ ký và một đầu ra.
Khả năng thay thế lẫn nhau mạnh mẽ hơn: Cấu trúc UTXO không có khái niệm về lớp chuỗi khối, vì vậy, cho dù về mặt kỹ thuật hay pháp lý, việc thiết lập danh sách đỏ/danh sách đen và phân biệt chúng dựa trên nguồn của những "đầu ra hợp lệ" này là không thực tế lắm.
Tính đơn giản: Mã hóa Ethereum đơn giản và dễ hiểu hơn, đặc biệt khi có liên quan đến các tập lệnh phức tạp. Mặc dù bất kỳ ứng dụng phi tập trung nào cũng có thể được triển khai (miễn cưỡng) với UTXO, nhưng về cơ bản, phương pháp này trao quyền cho tập lệnh để giới hạn các loại UTXO mà một UTXO nhất định có thể xuất ra và các điều kiện sử dụng của nó (ví dụ: nó cần chứa Bằng chứng cây Merkle để hỗ trợ tập lệnh ứng dụng tương ứng thay đổi gốc trạng thái). Do đó, việc triển khai UTXO phức tạp hơn nhiều so với cách Ethereum sử dụng tài khoản.
Ứng dụng khách nhẹ: Ứng dụng khách nhẹ có thể truy cập tất cả dữ liệu liên quan đến tài khoản bất kỳ lúc nào bằng cách quét cây trạng thái theo một hướng xác định. Trong mô hình UTXO, mỗi giao dịch cần sử dụng các tham chiếu khác nhau, điều này chắc chắn gây khó khăn cho các ứng dụng dapp chạy dài sử dụng cơ chế lan truyền trạng thái gốc UTXO đã đề cập ở trên.
Chúng tôi tin rằng lợi ích của tài khoản vượt trội hơn rất nhiều so với các lựa chọn thay thế, đặc biệt đối với loại dapp mà chúng tôi muốn hỗ trợ có thể chứa trạng thái và mã tùy ý. Ngoài ra, theo nguyên tắc hướng dẫn "không có tính năng nào là tính năng lớn nhất", chúng tôi tin rằng nếu người dùng thực sự quan tâm đến quyền riêng tư, họ có thể xây dựng một "bộ trộn và coinjoin" được mã hóa thông qua giao thức gói dữ liệu đã ký trong hợp đồng Thanh toán làm xáo trộn những con đường.
Một điểm yếu của phương pháp tài khoản là để ngăn chặn các cuộc tấn công lặp lại (replayattacks, nghĩa là cùng một giao dịch được thực hiện lặp đi lặp lại), mỗi giao dịch phải có một "nonce" (số sê-ri). Do đó, mỗi tài khoản phải có một giá trị nonce được cập nhật theo thời gian thực và mỗi giao dịch mới sẽ tăng giá trị nonce của tài khoản lên 1 như nonce của chính nó (và cập nhật giá trị nonce của tài khoản theo giá trị này sau khi xử lý giao dịch) (ghi chú hiệu đính: Trong chế độ tài khoản, nếu giao dịch không có mã định danh tiêu hao này đi kèm, giao dịch có thể được xử lý lặp đi lặp lại, để tài khoản nhận có thể lấy tài khoản nhiều lần mà không phải trả bất kỳ chi phí nào, trong khi tài khoản gửi sẽ bị hút cạn; nonce của tài khoản Ethereum được tăng lên khi giao dịch bắt đầu được xử lý, giải quyết vấn đề này). Điều này có nghĩa là ngay cả những tài khoản không còn được sử dụng cũng không thể bị xóa khỏi trạng thái tài khoản. Một giải pháp đơn giản cho vấn đề này là yêu cầu các giao dịch chứa số khối, khiến chúng không thể khôi phục được sau một khoảng thời gian nhất định và thường xuyên đặt lại nonce.
Nếu bạn muốn xóa một tài khoản ở trạng thái (chẳng hạn như tài khoản đã lâu không được sử dụng), trước tiên bạn phải "ping" chúng ra và chi phí quét toàn bộ giao thức chuỗi khối là rất lớn. Chúng tôi đã không triển khai cơ chế này trên 1.0 và các phiên bản 1.1 trở lên có thể sử dụng cơ chế này.
Đọc lại Lưu ý: Đây là lý do kỹ thuật cho sự cố "bùng nổ trạng thái" mà Ethereum sẽ gặp phải trong tương lai: tất cả dữ liệu trạng thái phải được bảo toàn hoàn toàn và không thể xóa tài khoản một cách hợp lý. Là một giao thức chuỗi khối, các nút của Ethereum không chỉ phải đạt được sự đồng thuận về thứ tự giao dịch (giao dịch) mà còn phải đạt được sự đồng thuận về trạng thái toàn cầu (hình thức biểu hiện là gốc trạng thái cần được đưa vào khối header Vì vậy, để xóa trạng thái cũng cần có sự đồng thuận của toàn mạng lưới, nếu không sẽ rơi vào tình trạng chia rẽ.
bài viết nàybài viết này。
Cây Patricia Merkel (MPT)
Merkle Patricia tree/trie, được hình thành bởi Alan Reiner và được triển khai trong giao thức Ripple, là cấu trúc dữ liệu chính của Ethereum, được sử dụng để lưu trữ tất cả các trạng thái tài khoản và mỗi khối Dữ liệu giao dịch và biên nhận ở định dạng . MPT là sự kết hợp của cây Merkle và cây Patricia, và cấu trúc được tạo bằng cách kết hợp hai cây này có các thuộc tính sau:
Giá trị băm gốc tương ứng với bất kỳ bộ cặp khóa-giá trị nào là duy nhất. Nếu bạn muốn khai man rằng một cặp khóa-giá trị tồn tại trên một cây nào đó, nó chắc chắn sẽ bị nhìn thấu (trừ khi kẻ tấn công có khoảng 2^128 máy tính quyền lực).
Độ phức tạp về thời gian của việc thêm, xóa và thay đổi một cặp khóa-giá trị là logarit.
MPT cung cấp cho chúng tôi một "dấu vân tay" hiệu quả, dễ cập nhật, đại diện cho toàn bộ cây trạng thái. Mô tả chi tiết hơn về MPT: https://github.com/ethereum/wiki/wiki/Patricia-Tree.
Các quyết định thiết kế cụ thể cho MPT như sau:
Có hai loại nút: nút KV và nút rời rạc. Sự hiện diện của các nút KV giúp cải thiện hiệu quả, bởi vì nếu cây thưa thớt ở một vùng nhất định, các nút KV có thể được sử dụng làm "lối tắt" để nén chiều cao của cây (đọc mô tả chi tiết về MPT để biết thêm chi tiết).
Các nút rời rạc ở dạng thập lục phân, không phải nhị phân: điều này làm cho việc tra cứu hiệu quả hơn, một lựa chọn mà giờ đây chúng tôi nhận ra là không lý tưởng, vì hiệu quả tra cứu của cây hex có thể được mô phỏng ở dạng nhị phân bằng cách lưu trữ các nút theo lô. Tuy nhiên, việc triển khai cấu trúc cây MPT rất dễ xảy ra lỗi và ít nhất sẽ gây ra sự không khớp trong gốc trạng thái, vì vậy chúng tôi quyết định tạm dừng thay đổi cho đến 1.1.
Không có sự phân biệt giữa giá trị trống và không phải là thành viên: điều này được thực hiện để đơn giản hóa logic, giá trị (số dư) của tài khoản không được kích hoạt trong Ethereum mặc định là 0 và chuỗi trống cũng được biểu thị bằng 0. Tuy nhiên, cần nhấn mạnh rằng điều này hy sinh một số tính tổng quát và do đó không phải là tối ưu.
Sự khác biệt giữa các nút đầu cuối và không đầu cuối: Về mặt kỹ thuật, không cần thiết phải xác định một nút "cho dù đó là nút đầu cuối" bởi vì tất cả các cây trong Ethereum được sử dụng để lưu trữ dữ liệu có độ dài cố định (nghĩa là độ dài khóa), nhưng theo thứ tự để tăng tính linh hoạt, chúng tôi vẫn sẽ thêm logo này, hy vọng rằng việc triển khai MPT của Ethereum có thể được áp dụng bởi các loại tiền điện tử khác như hiện tại.
Sử dụng SHA3(k) làm khóa trong "cây bảo mật" (cây trạng thái và cây lưu trữ tài khoản): sử dụng SHA3(k), bạn muốn tạo nhiều tài khoản (các tài khoản có thể tạo cây trạng thái lên tới 64 cấp!) và lặp đi lặp lại call Các opcode SLOAD và SSTORE làm cho các cuộc tấn công DoS trở nên khó khăn hơn nhiều. Lưu ý rằng điều này cũng làm cho việc liệt kê cây trở nên khó khăn hơn; nếu bạn muốn khách hàng của mình có thể liệt kê, cách dễ nhất là duy trì ánh xạ cơ sở dữ liệu sha3(k) -> k.
Hiệu đính Lưu ý: Ý nghĩa ở đây là nếu k được sử dụng làm khóa của cây Merkle để lưu trữ dữ liệu, phân phối của nó có thể rất thưa thớt và kẻ tấn công có thể dễ dàng lập kế hoạch cho các tài khoản yêu cầu đường dẫn cây sâu để lưu trữ và nhắm mục tiêu các tài khoản này Liên tục gọi hoạt động truy cập trạng thái gây ra quá tải cho các nút trong mạng. Tuy nhiên, kết quả của hàm băm được phân phối ngẫu nhiên. Sử dụng sha3(k) làm khóa có thể làm cho phân phối khóa đồng đều hơn và chiều cao của cây sẽ ngắn hơn) .
Đặc điểm này cũng có ưu và nhược điểm, một mặt nghĩa là tấn công DoS sẽ trở nên khó khăn hơn, mặt khác nó cũng làm cho đường truy cập cây trạng thái của các giao dịch trong một khối ít trùng nhau nên mỗi lần tìm kiếm đều là trường hợp xấu nhất phức tạp.
Ngoài ra, điều này cũng khiến MPT không phù hợp để đạt được trạng thái "không trạng thái" (bản thân khối mang dữ liệu cần thiết để xác minh và trình xác minh không cần phải có trạng thái toàn cầu), bởi vì các đường dẫn truy cập trạng thái không chồng chéo và hiệu quả không gian của bằng chứng cũng là trường hợp xấu nhất. Tất nhiên, cũng có thể nói rằng bản thân hiệu quả không gian của bằng chứng cây Merkle không đủ cao
RLP
RLP (recursive length prefix): Tiền tố độ dài đệ quy.
Mã hóa RLP là định dạng tuần tự hóa chính trong Ethereum và nó được sử dụng ở mọi nơi: khối, giao dịch, trạng thái tài khoản và thông báo giao thức mạng. Xem mô tả chính thức về RLP để biết chi tiết: https://github.com/ethereum/wiki/wiki/RLP
RLP được dự định là một định dạng tuần tự hóa được đơn giản hóa cao với mục đích duy nhất là lưu trữ các mảng byte lồng nhau3. Không giống như các giải pháp hiện có như protobuf và BSON, RLP không định nghĩa bất kỳ kiểu dữ liệu cụ thể nào như Boolean (Boolean), float (dấu phẩy động), double hay integer (số nguyên). Nó chỉ lưu trữ các cấu trúc dưới dạng các mảng lồng nhau và tùy thuộc vào giao thức để xác định ý nghĩa của mảng. RLP cũng không hỗ trợ rõ ràng các bộ sưu tập bản đồ Đề xuất bán chính thức là sử dụng các mảng lồng nhau [[k1, v1], [k2, v2], ...] để biểu diễn các bộ sưu tập cặp khóa-giá trị, k1, k2 .. .theo Chuẩn sắp xếp cho chuỗi.
Một lược đồ có chức năng tương tự như RLP là protobuf hoặc BSON, đây là những thuật toán đã được sử dụng mọi lúc. Tuy nhiên, trong Ethereum, chúng tôi thích sử dụng RLP hơn vì: (1) nó dễ thực hiện; (2) tính nhất quán của byte được đảm bảo tuyệt đối.
Nhiều ngôn ngữ không có thứ tự rõ ràng của các bộ sưu tập cặp khóa-giá trị và các định dạng dấu phẩy động có nhiều trường hợp đặc biệt có thể dẫn đến các mã hóa khác nhau và các giá trị băm khác nhau cho cùng một dữ liệu. Bằng cách phát triển giao thức nội bộ, chúng tôi có thể đảm bảo rằng nó được thiết kế với những mục tiêu này (đây là nguyên tắc chung cũng áp dụng cho các phần khác của mã, chẳng hạn như máy ảo). Phương pháp mã hóa được sử dụng bởi BitTorrent, bencode, có thể là một giải pháp thay thế cho RLP. Tuy nhiên, nó sử dụng phương pháp mã hóa thập phân, kém hơn một chút so với RLP nhị phân.
thuật toán nén
Cả giao thức mạng và cơ sở dữ liệu đều sử dụng thuật toán nén tùy chỉnh để lưu trữ dữ liệu. Thuật toán có thể được mô tả như sau: sử dụng mã hóa run-length 4 cho 0 trong khi bảo toàn các giá trị khác (trừ một số trường hợp đặc biệt như sha3(' ') ), chẳng hạn:
Trước khi thuật toán nén tồn tại, có một số trường hợp đặc biệt ở nhiều nơi trong giao thức Ethereum, ví dụ: sha3 thường được định nghĩa lại để sha3(' ')=' ', do đó không cần lưu trữ mã trong tài khoản, có thể lưu 64 byte. Tuy nhiên, gần đây, tất cả các trường hợp đặc biệt khiến cấu trúc dữ liệu của Ethereum trở nên cồng kềnh đã bị loại bỏ và thay vào đó, các chức năng bảo quản dữ liệu đã được thêm vào các lớp bên ngoài giao thức chuỗi khối, tức là vào giao thức mạng và triển khai cơ sở dữ liệu người dùng Chèn của nó. Điều này làm tăng khả năng mô đun hóa, đơn giản hóa lớp đồng thuận và làm cho việc triển khai cập nhật liên tục thuật toán nén tương đối đơn giản (ví dụ: nó có thể được phân biệt và triển khai theo số phiên bản của giao thức mạng).
Công dụng của cây (trie)
Nhắc lại: Để hiểu được phần kiến thức này, người đọc cần nắm được nguyên lý hoạt động của bộ lọc Bloom 5. Phần giới thiệu có thể xem tại: http://en.wikipedia.org/wiki/Bloom_filter
Mỗi tiêu đề khối trong chuỗi khối Ethereum chứa các con trỏ tới ba cây: cây trạng thái, cây giao dịch và cây biên nhận.
Cây trạng thái đại diện cho toàn bộ trạng thái sau khi xử lý khối;
Cây giao dịch đại diện cho tất cả các giao dịch trong khối và các giao dịch này được lập chỉ mục theo chỉ mục làm khóa; (ví dụ: k0: giao dịch được thực hiện đầu tiên, k1: giao dịch được thực hiện thứ hai)
Cây biên nhận đại diện cho biên lai tương ứng cho mỗi giao dịch.
Biên lai giao dịch là cấu trúc dữ liệu được mã hóa RLP:
TRONG:
medstate: Sau khi giao dịch được xử lý, gốc của cây trạng thái;
gas_used: lượng gas đã sử dụng sau khi giao dịch được xử lý;
logs: là danh sách gồm nhiều phần tử [address, [topic1, topic2...], data]. Các phần tử này được tạo bởi opcodes LOG0 ... LOG4 được gọi trong quá trình thực hiện giao dịch (chứa lệnh gọi chính và lệnh gọi phụ); địa chỉ là địa chỉ của hợp đồng tạo nhật ký; chủ đề có tối đa bốn giá trị 32 byte; dữ liệu là một từ của mảng phần kích thước bất kỳ;
logbloom: Bộ lọc Bloom bao gồm các địa chỉ và chủ đề của tất cả nhật ký trong giao dịch.
Ghi chú:
Ghi chú:
UTXO: đầu ra giao dịch chưa sử dụng, nghĩa đen: đầu ra giao dịch chưa sử dụng, tức là đầu ra giao dịch không được bất kỳ giao dịch nào tham chiếu làm đầu vào. Nó là một cấu trúc dữ liệu được sử dụng trong giao thức Bitcoin để lưu trữ thông tin giá trị (quyền sở hữu). —— ghi chú hiệu đính
Nonce, viết tắt của Số được sử dụng một lần hoặc Số một lần, trong mật mã học, Nonce là một giá trị ngẫu nhiên tùy ý hoặc không lặp lại chỉ được sử dụng một lần và cả vectơ ban đầu và hàm băm được mã hóa trong công nghệ mã hóa đều đóng một vai trò quan trọng. ứng dụng truyền thông của các giao thức xác thực khác nhau, đảm bảo thông tin xác thực không được sử dụng lại để chống lại các cuộc tấn công lặp lại (Replay Attack). ——Ghi chú của người dịch
Mảng lồng nhau: Tạo một mảng và điền vào đó các mảng khác. Chẳng hạn như mảng pet:
var cats : String[] = ["Cat","Beansprout", "Pumpkin", "Max"];
var dogs : String[] = ["Dog","Oly","Sib"];
var pets : String = [cats, dogs];——Ghi chú của người dịch
run-length-encoding: Mã hóa thống kê. Kỹ thuật chính là phát hiện các chuỗi bit hoặc ký tự lặp lại và thay thế chúng bằng số lần xuất hiện của chúng. (Bách khoa toàn thư Baidu) - Ghi chú của người dịch
tiêu đề cấp đầu tiên
Phần thưởng cho khối chú
Giao thức GHOST là một cải tiến đáng chú ý lần đầu tiên được đề xuất vào tháng 10 năm 2013 bởi Yonatan Sompolinsky và Aviv Zohar. Đây là nỗ lực nghiêm túc đầu tiên để giải quyết vấn đề liên quan đến việc tạo khối nhanh.
Mục đích của GHOST là giải quyết một vấn đề như vậy: thời gian khối ngắn hơn (và do đó tốc độ xác nhận nhanh hơn) sẽ dẫn đến nhiều khối bị "lỗi thời" và do đó kém an toàn hơn - vì cần có thời gian để các khối lan truyền trong mạng, nếu người khai thác A đào một khối và phát nó ra toàn mạng, trên đường phát B cũng đào khối đó ra, khi đó khối của B đã lỗi thời và việc khai thác hiện tại của B không góp phần bảo mật mạng .
Ngoài ra, có một vấn đề về tập trung: nếu A là nhóm khai thác với 30% sức mạnh tính toán, thì B có 10% sức mạnh tính toán. A có 70% thời gian tạo block lỗi thời (vì 30% thời gian còn lại sẽ tạo block mới nhất nên có thể coi TA "lấy ngay" dữ liệu của block mới nhất mà không cần đợi truyền block), trong khi B có 90% thời gian Thời gian để tạo ra các khối lỗi thời. Nếu khoảng thời gian giữa các lần sản xuất khối rất ngắn, tốc độ lỗi thời sẽ trở nên cao hơn và A sẽ giúp việc khai thác hiệu quả hơn với sức mạnh tính toán lớn hơn. Do đó, nếu các khối được tạo ra quá nhanh, nó sẽ dễ dẫn đến sự độc quyền trên thực tế của các nhóm khai thác có sức mạnh tính toán mạng lớn.
Theo Sompolinsky và Zohar, GHOST giải quyết vấn đề suy giảm an ninh mạng do các khối lỗi thời gây ra trong quá trình tính toán chuỗi nào là chuỗi dài nhất. Nghĩa là, không chỉ khối mẹ và các khối trước đó, mà cả các khối thế chấp lỗi thời (trong Ethereum, chúng tôi gọi chúng là "khối chú") cũng được thêm vào để tính xem khối nào có tổng công suất lớn nhất.
Để giải quyết vấn đề thứ hai: vấn đề tập trung hóa, chúng tôi đã áp dụng một chiến lược khác: phần thưởng khối cũng được cung cấp cho các khối lỗi thời: phần thưởng cho việc khai thác các khối lỗi thời là 7/8 phần thưởng cơ bản của khối; khối cháu của khối thời gian sẽ nhận 1/32 phần thưởng cơ bản dưới dạng tiền thưởng. Tuy nhiên, phí giao dịch không được trao cho khối chú và cháu.
Trong Ethereum, các khối lỗi thời chỉ có thể được bao gồm dưới dạng khối chú bởi các khối hậu duệ trực tiếp trong vòng 7 thế hệ của các khối anh em của chúng. Lý do của hạn chế này là, trước hết, nếu giao thức GHOST không giới hạn khoảng cách giữa các thế hệ của các khối lỗi thời, nó sẽ tốn rất nhiều chi phí cho việc tính toán tính hợp lệ của các khối lỗi thời; thứ hai, chính sách khuyến khích không giới hạn cho các khối lỗi thời sẽ khiến những người khai thác mất hứng thú khai thác trên chuỗi chính; cuối cùng, các tính toán cho thấy chính sách phần thưởng khối lỗi thời giới hạn ở lớp 7 mang lại hầu hết hiệu quả mong muốn mà không có tác dụng phụ tiêu cực.
Bạn có thể tìm thấy trình giả lập để đo lường rủi ro tập trung tại đây: https://github.com/ethereum/economic-modeling/blob/master/ghost.py
Một cuộc thảo luận cấp cao hơn có thể được tìm thấy ở đây: https://blog.ethereum.org/2014/07/11/toward-a-12-second-block-time/
Hiệu đính Lưu ý: Hình thức kỹ thuật của "bao gồm" ở đây là: khối cháu tham chiếu giá trị băm khối của khối chú trong tiêu đề khối, sau đó bao gồm tiêu đề khối của khối chú trong phần thân khối.
Các quyết định thiết kế cho thuật toán blocktime bao gồm:
Thời gian khối 12 giây: 12 giây được chọn vì thời gian này đã dài hơn khoảng thời gian tối thiểu của độ trễ mạng. Trong một bài báo năm 2013 về đo lường độ trễ của mạng Bitcoin, người ta đã xác định rằng 12,6 giây là thời gian để một khối mới được tạo lan truyền tới 95% các nút; tuy nhiên, bài báo cũng tuyên bố rằng thời gian lan truyền tỷ lệ thuận với khối kích thước, do đó, ở các loại tiền tệ nhanh hơn, chúng ta có thể mong đợi thời gian lan truyền sẽ giảm đáng kể. Khoảng thời gian lan truyền không đổi vào khoảng 2 giây. Tuy nhiên, để đảm bảo an toàn, trong phân tích của chúng tôi, chúng tôi giả định rằng việc truyền khối mất 12 giây
Hạn chế trong vòng 7 thế hệ tổ tiên: Mục đích của thiết kế này là chỉ giữ lại một số lượng nhỏ các khối và xóa các khối trước đó. Một phạm vi có thể trích dẫn gồm 7 thế hệ đã được chứng minh là cung cấp hầu hết các hiệu ứng mong muốn.
Hạn chế con cháu 1 thế hệ: (ví dụ: c(c(p(p(p(head))))) không hợp lệ nếu c = con và p = cha mẹ): Đây cũng là một mục tiêu thiết kế để đơn giản hóa, và đã nói ở trên mô phỏng cho thấy rằng điều này không gây rủi ro tập trung đáng kể. (Đọc lại Lưu ý: Câu này khó hiểu; một ý nghĩa có thể là: con cháu của khối chú không thể được sử dụng làm khối chú, nghĩa là chỉ thế hệ nhánh phụ của chuỗi chính mới có thể được sử dụng làm khối chú .)
Khối chú phải hợp lệ: Khối chú phải là tiêu đề hợp lệ, không phải khối hợp lệ. Điều này cũng được thực hiện để đơn giản hóa, giữ cho mô hình chuỗi khối dưới dạng cấu trúc dữ liệu tuyến tính (không biến thành DAG). Tuy nhiên, nó cũng hợp lệ để yêu cầu các khối chú là khối hợp lệ.
tiêu đề cấp đầu tiên
Thuật toán cập nhật độ khó
Hiện tại, Ethereum thực hiện cập nhật độ khó thông qua các quy tắc sau:
Mục tiêu thiết kế của quy tắc cập nhật độ khó như sau:
Cập nhật nhanh: Thời gian giữa các khối nên được điều chỉnh nhanh chóng với sự tăng hoặc giảm sức mạnh băm;
Độ biến động thấp: nếu công suất khai thác không đổi, độ khó sẽ không dao động mạnh;
Đơn giản: việc triển khai thuật toán phải tương đối đơn giản;
Bộ nhớ thấp: Thuật toán không nên dựa vào quá nhiều khối lịch sử và sử dụng càng ít "biến bộ nhớ" càng tốt. Giả sử rằng có mười khối mới nhất, hãy thêm các biến bộ nhớ được lưu trữ trong tiêu đề của mười khối này và các khối này có thể được sử dụng để tính toán thuật toán;
Không thể phá vỡ: Thuật toán không nên khuyến khích người khai thác can thiệp vào dấu thời gian hoặc nhóm khai thác để liên tục thêm hoặc xóa sức mạnh tính toán
tiêu đề cấp đầu tiên
Gas và phí
Tất cả các giao dịch bằng Bitcoin gần như giống nhau, vì vậy chi phí mạng của chúng được mô hình hóa trong một đơn vị duy nhất. Các giao dịch trong Ethereum phức tạp hơn nên phí giao dịch cần tính đến nhiều khía cạnh của tài khoản, bao gồm chi phí băng thông mạng, chi phí lưu trữ và chi phí tính toán. Ít nhất, ngôn ngữ lập trình Ethereum là Turing hoàn chỉnh, vì vậy các giao dịch có thể sử dụng bất kỳ lượng băng thông, lưu trữ và chi phí tính toán nào; không thể dự đoán một cách đáng tin cậy bao nhiêu sẽ được sử dụng (do cái gọi là "sự cố tạm dừng Turing" ) ) (Đọc lại Lưu ý: Nghĩa là, không có cách nào đáng tin cậy để khẳng định rằng bất kỳ chương trình nào có thể thực thi được trên máy Turing sẽ kết thúc trong một số bước hữu hạn). Ngăn chặn các cuộc tấn công từ chối dịch vụ bằng cách sử dụng các vòng lặp vô hạn là mục tiêu chính của chúng tôi.
Cơ chế cơ bản của phí giao dịch Ethereum như sau:
Mỗi giao dịch phải chỉ định lượng gas mà nó sẵn sàng tiêu thụ (nghĩa là chỉ định giá trị của gas bắt đầu) và khoản phí mà nó sẵn sàng trả cho mỗi đơn vị gas (tức là giá gas). (Lưu ý hiệu đính: Startgas ở đây là gaslimit chúng ta quen sử dụng hiện nay.)
Tất cả các hoạt động trong quá trình thực hiện giao dịch, bao gồm đọc và ghi cơ sở dữ liệu, gửi tin nhắn và tính toán ở mỗi bước sẽ tiêu tốn một lượng gas nhất định;
Nếu giao dịch được hoàn thành và giá trị gas tiêu thụ nhỏ hơn giá trị giới hạn đã chỉ định, thì giao dịch được thực hiện bình thường và giá trị gas còn lại được gán cho biến gas_rem; sau khi giao dịch hoàn tất, người gửi sẽ nhận được ether được trả lại với giá trị của gas_rem * gasprice, Phần thưởng cho những người khai thác là (startgas - gas_rem) * gasprice trị giá ether;
Nếu hết gas trong khi thực hiện giao dịch, tất cả các lần thực thi sẽ được khôi phục về trạng thái ban đầu, nhưng giao dịch vẫn hợp lệ, nhưng kết quả duy nhất của giao dịch là trả cho những người khai thác giá trị của startgas * gasprice, và cái kia không đổi;
Khi một hợp đồng gửi tin nhắn đến một hợp đồng khác, có thể đặt giới hạn gas cho các lần thực hiện phụ do tin nhắn gây ra. Nếu phụ công hết gas thì phục hồi phụ công nhưng vẫn hao gas. (Lưu ý hiệu đính: Tính đến thời điểm hiệu đính bài viết này (ngày 9 tháng 7 năm 2021), điều này vẫn chưa thay đổi nhưng có thể thay đổi trong tương lai. Xem "Các tính năng EVM đáng xem xét loại bỏ》)
Các điểm được đề cập ở trên phải được đáp ứng, ví dụ:
Nếu giao dịch không cần chỉ định giới hạn gas, thì người dùng ác ý có thể gửi giao dịch với một vòng lặp gồm hàng tỷ bước. Không ai có thể xử lý một giao dịch như vậy, bởi vì có thể mất nhiều thời gian để xử lý một giao dịch như vậy, nhưng không ai có thể thông báo trước cho những người khai thác trên mạng, điều này sẽ dẫn đến lỗ hổng từ chối dịch vụ.
Một giải pháp thay thế cho số lượng gas nghiêm ngặt là giới hạn thời gian, nhưng chúng không hữu ích vì chúng quá chủ quan (một số máy tính nhanh hơn những máy tính khác và ngay cả khi máy tính của mọi người giống nhau thì vẫn có thể xảy ra sai sót).
Toàn bộ giá trị của startgas * gasprice nên được đặt ngay từ đầu, để tài khoản không bị "phá sản" trong quá trình thực hiện giao dịch và không thể tiếp tục thanh toán phí gas. Việc kiểm tra số dư trong khi thực hiện cũng không được, vì tài khoản có thể đưa số dư đi nơi khác.
Nếu việc thực hiện giao dịch sẽ không được hoàn nguyên hoàn toàn (khôi phục) trong trường hợp không đủ gas, hợp đồng phải sử dụng các biện pháp an toàn mạnh mẽ để ngăn hợp đồng thay đổi.
Nếu các hạn chế phụ không tồn tại, các tài khoản độc hại có thể thực hiện các cuộc tấn công từ chối dịch vụ đối với các hợp đồng khác. Trước tiên, kẻ tấn công có thể đạt được sự đồng thuận với hợp đồng nạn nhân, sau đó chèn một vòng lặp vô hạn vào đầu quá trình tính toán, sau đó gửi tin nhắn đến hợp đồng nạn nhân hoặc bất kỳ nỗ lực nào để khắc phục hợp đồng nạn nhân, toàn bộ giao dịch sẽ bị bế tắc. (Lưu ý hiệu đính: Câu này cũng khó hiểu.)
Yêu cầu người gửi giao dịch, thay vì hợp đồng, trả tiền gas làm tăng đáng kể khả năng hoạt động của nhà phát triển. Các phiên bản đầu tiên của Ethereum thanh toán gas theo hợp đồng, dẫn đến một vấn đề khá nghiêm trọng: mỗi hợp đồng phải triển khai mã "người gác cổng" để đảm bảo rằng mỗi tin nhắn đến cung cấp đủ ether để hợp đồng tiêu thụ.
Tính toán tiêu thụ khí có các đặc điểm sau:
Đối với bất kỳ giao dịch nào, phí cơ bản là 21000 gas sẽ được tính. Các khoản phí này có thể được sử dụng để thanh toán chi phí chạy thuật toán đường cong elliptic được thiết kế để khôi phục địa chỉ của người gửi từ chữ ký, cũng như dung lượng ổ cứng và băng thông được sử dụng để lưu trữ giao dịch.
Các giao dịch có thể bao gồm một lượng "dữ liệu" không giới hạn. Một số opcode trong máy ảo cho phép các hợp đồng nhận các giao dịch đó truy cập dữ liệu. Quy tắc "mức tiêu thụ cố định" cho dữ liệu là: 4 gas trên mỗi byte 0, 68 gas trên mỗi byte khác 0. Công thức này phát sinh vì hầu hết các giao dịch do người dùng gửi đến hợp đồng bao gồm một loạt các tham số 32 byte, hầu hết trong số đó có nhiều byte 0 ở đầu. Cấu trúc này có vẻ không hiệu quả, nhưng do thuật toán nén nên nó thực sự khá hiệu quả. Chúng tôi hy vọng rằng cấu trúc này có thể thay thế các cơ chế khác phức tạp hơn bao bọc chặt chẽ các tham số theo số byte dự kiến, dẫn đến sự gia tăng đáng kể độ phức tạp của giai đoạn biên dịch. Đây là một ngoại lệ đối với mô hình tổ hợp bánh sandwich, nhưng nó cũng là một mô hình hợp lý do tỷ lệ chi phí-lợi ích.
Mức tiêu thụ của mã hoạt động SSTORE được sử dụng để đặt mục lưu trữ tài khoản là: 1) Khi thay đổi giá trị 0 thành giá trị khác 0, nó sẽ tiêu thụ 20000 gas; 2) thay đổi giá trị 0 thành giá trị 0 hoặc giá trị khác 0 giá trị 0 thành giá trị khác 0, tiêu thụ 5000 gas; 3) Thay đổi giá trị khác 0 thành giá trị 0 và tiêu thụ 5000 gas; ngoài ra, 15000 gas sẽ được hoàn trả sau khi giao dịch được thực hiện thành công (nghĩa là giao dịch được thực hiện mà không làm cạn kiệt khí). Giới hạn trên của số tiền hoàn trả là 50% tổng lượng gas tiêu thụ của giao dịch. Điều này mang lại cho mọi người một động lực nhỏ để xóa các mặt hàng được lưu trữ. Chúng tôi nhận thấy rằng do thiếu các ưu đãi như vậy, không gian lưu trữ của nhiều hợp đồng không được sử dụng hiệu quả, dẫn đến việc mở rộng nhanh chóng dữ liệu được lưu trữ. Thiết kế này cung cấp hầu hết các lợi ích của mô hình "thuê liên tục các hạng mục lưu trữ" mà không làm mất đi sự đảm bảo rằng hợp đồng, một khi được thiết lập, có thể tồn tại vô thời hạn. Cơ chế hoàn tiền bị trì hoãn là cần thiết vì nó có thể ngăn chặn các cuộc tấn công từ chối dịch vụ: kẻ tấn công có thể gửi một giao dịch với một lượng gas nhỏ và xóa một số lượng lớn các mục lưu trữ trong một chu kỳ cho đến khi gas được sử dụng hết. rất nhiều sức mạnh tính toán xác minh, nhưng thực tế Nó không thực sự xóa bộ nhớ và không tốn nhiều gas. Giới hạn 50% là để đảm bảo rằng những người khai thác đóng gói giao dịch vẫn có thể xác định giới hạn trên của thời gian tính toán để thực hiện giao dịch.
(Lưu ý hiệu đính: Trước hết, mức tiêu thụ gas của các mã truy cập trạng thái như SSTORE đã được thay đổi nhiều lần với hard fork của Ethereum. Kể từ tháng 7 năm 2021, giá trị mới nhất có thể được tìm thấy trong "Tổng quan về nội dung nâng cấp của Berlin"; trong tương lai gần, giá trị của opcode này sẽ tiếp tục thay đổi; thứ hai, cơ chế hoàn trả gas ở đây chưa được kích hoạt để giảm bớt vấn đề mở rộng dữ liệu trạng thái, mà còn làm vấn đề trở nên tồi tệ hơn, bởi vì mọi người có thể thay đổi giá trị của giá gas Khi giá gas thấp, một lượng lớn dữ liệu rác được ghi và khi giá gas cao, những dữ liệu này sẽ bị xóa để lấy gas, đây là nguyên tắc của "GasToken". Đã có xác nhận rằng cơ chế hoàn trả xăng sẽ được thay đổi trong ngã ba "London", xem "Bản xem trước nâng cấp Ethereum "London"》。)
Dữ liệu tin nhắn được cung cấp bởi hợp đồng không có chi phí. Bởi vì không cần thực sự sao chép bất kỳ dữ liệu nào trong suốt cuộc gọi tin nhắn, dữ liệu cuộc gọi (dữ liệu cuộc gọi) có thể được coi đơn giản như một con trỏ tới bộ nhớ của hợp đồng cha, sẽ không thay đổi khi tiến trình con thực thi.
Bộ nhớ là một mảng có thể mở rộng vô hạn, tuy nhiên mỗi lần mở rộng 32 byte bộ nhớ sẽ tiêu tốn 1 gas cost, dưới 32 byte được tính là 32 byte. (Lưu ý hiệu đính: bộ nhớ thường được dịch là bộ nhớ, nhưng trong ngữ cảnh của Ethereum, nó là một trong ba loại EVM vì lưu trữ dữ liệu, vì vậy nó không được dịch để thể hiện tính đặc thù của nó.)
Thời gian tính toán của một số opcode phụ thuộc rất nhiều vào các tham số và việc tính toán chi phí gas được thay đổi linh hoạt. Ví dụ: chi phí của EXP là cấp số nhân (10 gas + 10 gas/byte, tức là x^0 = 1 gas, x^1 ... x^255 = 2 gas, x^256 ... x^65535 = 3 khí, v.v.). Các opcode sao chép (ví dụ: CALLDATACOPY, CODECOPY, EXTCODECOPY) có chi phí hoạt động là 1 gas + 1 gas/32 byte (làm tròn lên; các quy tắc cho opcode LOG là tương tự nhau). Chi phí mở rộng bộ nhớ không được bao gồm ở đây. Nếu nó được thêm vào, nó sẽ trở thành một vectơ tấn công hình vuông (50.000 CALLDATACOPY, tiêu thụ 50.000 gas mỗi lần, số tiền tính toán phải là 50.000^2, nhưng nếu bạn không sử dụng quy tắc tính phí động, bạn chỉ cần trả ~50.000 gas ).
Opcode CALL (và CALLCODE ) tốn thêm 9000 gas nếu giá trị khác không. Điều này là do bất kỳ sự chuyển giao giá trị nào cũng sẽ khiến bộ nhớ lịch sử của nút lưu trữ tăng lên đáng kể. Xin lưu ý rằng mức tiêu thụ thực tế của hoạt động là 6700; nhưng trên cơ sở này, chúng tôi mạnh mẽ tăng giá trị gas được tự động cung cấp cho người nhận và giá trị này ít nhất là 2300. Điều này được thực hiện để ví chấp nhận giao dịch có ít nhất đủ gas để tạo nhật ký. (ghi chú hiệu đính: xem "Các tính năng EVM đáng xem xét loại bỏ》)
Một phần quan trọng khác của cơ chế gas là tính kinh tế thể hiện trong chính giá gas. Trong Bitcoin, cách tiếp cận mặc định là thu phí hoàn toàn tự nguyện, với những người khai thác đóng vai trò là người gác cổng và tự động đặt mức phí tối thiểu. Trong Ethereum, người gửi giao dịch được phép đặt bất kỳ số lượng gas nào. Phương pháp này rất phổ biến trong cộng đồng Bitcoin vì nó là hiện thân của “nền kinh tế thị trường”: cho phép thợ mỏ và thương nhân xác định giá dựa trên cung và cầu. Tuy nhiên, vấn đề với cách tiếp cận này là việc xử lý giao dịch không tuân theo nguyên tắc thị trường. Mặc dù xử lý giao dịch có thể được coi là một dịch vụ do người khai thác cung cấp cho người gửi (nghe có vẻ trực quan), nhưng trên thực tế, mọi giao dịch do người khai thác xử lý đều phải được xử lý bởi mọi nút trong mạng, do đó, phần lớn chi phí xử lý giao dịch đều do người khai thác chịu bởi các cơ quan bên thứ ba, chứ không phải những người khai thác quyết định có vứt bỏ nó hay không. Do đó, vấn đề “bi kịch của cái chung” rất dễ xảy ra.
tiêu đề cấp đầu tiên
máy ảo
Máy ảo Ethereum là công cụ thực thi các mã giao dịch và nó cũng là điểm khác biệt cốt lõi giữa Ethereum và các hệ thống khác. Lưu ý rằng máy ảo nên được xem xét riêng biệt với "mô hình hợp đồng và thông báo". Ví dụ: opcode SIGNEXTEND là một chức năng của máy ảo, nhưng trên thực tế, "một hợp đồng có thể gọi các hợp đồng khác và chỉ định giới hạn gas cho các cuộc gọi phụ" là một phần của "mô hình hợp đồng và thông báo".
Các mục tiêu thiết kế của EVM như sau:
Đơn giản: càng ít opcode cấp thấp càng tốt, càng ít loại dữ liệu càng tốt, càng ít cấu trúc máy ảo càng tốt;
Kết quả là rõ ràng: Trong đặc tả VM, không có chỗ cho sự mơ hồ có thể xảy ra và kết quả phải hoàn toàn mang tính quyết định. Ngoài ra, bước tính toán phải chính xác để có thể đo được lượng khí tiêu thụ;
Tiết kiệm không gian: Các thành phần EVM phải càng nhỏ gọn càng tốt;
Chuyên biệt cho mục đích sử dụng: Các ứng dụng được xây dựng trên VM sẽ có thể xử lý các địa chỉ 20 byte và các giá trị được mã hóa tùy chỉnh 32 bit, có các hoạt động mô đun cho dữ liệu giao dịch, khối đọc và được mã hóa tùy chỉnh cũng như các Khả năng như tương tác trạng thái;
Đơn giản và an toàn: Để ngăn chặn việc khai thác VM, cần dễ dàng thiết lập một bộ mô hình chi phí tiêu thụ khí;
Tối ưu hóa thân thiện: nên dễ dàng tối ưu hóa để có thể xây dựng các phiên bản tăng tốc và biên dịch đúng lúc (JIT) và tăng tốc của VM.
Đồng thời, EVM còn có thiết kế đặc biệt sau:
Sự khác biệt giữa lưu trữ tạm thời/vĩnh viễn: Trước tiên hãy xem lưu trữ tạm thời và lưu trữ vĩnh viễn là gì. Lưu trữ tạm thời: Tồn tại trong mọi phiên bản của máy ảo và biến mất sau khi quá trình thực thi máy ảo kết thúc. Lưu trữ vĩnh viễn: Tồn tại trong lớp trạng thái chuỗi khối. Giả sử cây sau được thực thi (S là lưu trữ vĩnh viễn, M là lưu trữ tạm thời):
A gọi B;
B đặt BS[0]=5, BM[0]=9;
B gọi C;
C gọi B.
Lúc này nếu B cố đọc BS[0] thì sẽ lấy dữ liệu lưu trong B trước đó là 5, nhưng nếu B cố đọc BM[0] thì sẽ nhận được 0 vì BM là nơi lưu trữ tạm thời. và đọc Khi nó được tìm nạp, nó là một phiên bản mới của máy ảo. Trong một cuộc gọi bên trong (cuộc gọi bên trong), nếu bạn đặt BM[0] = 13 và BS[0] = 17, thì cả cuộc gọi bên trong và cuộc gọi của C đều kết thúc và trở về cuộc gọi bên ngoài (cuộc gọi bên ngoài) của B , lúc này hãy đọc Lấy M, bạn sẽ thấy BM[0] = 9 (giá trị này được đặt trong phiên bản cuối cùng của cùng một lần thực thi VM), BS[0] = 17 . Nếu cuộc gọi bên ngoài của B kết thúc và A gọi lại B, ta sẽ thấy BM[0] = 0 và BS[0] = 17. Mục đích của sự khác biệt này là: 1. Mỗi phiên bản thực thi được phân bổ không gian bộ nhớ, không gian này sẽ không bị suy giảm bởi các cuộc gọi vòng lặp, giúp lập trình an toàn dễ dàng hơn. 2. Cung cấp một biểu mẫu trong bộ nhớ có thể được vận hành nhanh chóng: vì cây cần được sửa đổi nên các cập nhật lưu trữ nhất thiết phải chậm.
Chế độ ngăn xếp/bộ nhớ: Trong những ngày đầu, có ba loại trạng thái máy tính (ngoại trừ bộ đếm chương trình trỏ đến lệnh tiếp theo): ngăn xếp (ngăn xếp, ngăn xếp LIFO tiêu chuẩn 32 byte), bộ nhớ (bộ nhớ, mảng byte tạm thời có thể kéo dài vô thời hạn), Hạng mục lưu trữ (lưu trữ, lưu trữ vĩnh viễn). Về mặt lưu trữ tạm thời, giải pháp thay thế cho ngăn xếp và bộ nhớ là mô hình chỉ bộ nhớ hoặc kết hợp giữa thanh ghi và bộ nhớ (không có nhiều khác biệt giữa hai loại này, thanh ghi về cơ bản là một loại bộ nhớ). Trong trường hợp này, mỗi lệnh có ba đối số, ví dụ: ADD R1 R2 R3: M[R1] = M[R2] + M[R3] . Lý do chọn mô hình ngăn xếp là hiển nhiên, nó làm cho mã nhỏ hơn theo hệ số 4.
Kích thước từ 32 byte: Trong hầu hết các cấu trúc, như Bitcoin, kích thước từ là 4 hoặc 8 byte. 4 hoặc 8 byte là quá hạn chế đối với địa chỉ bộ nhớ và tính toán mật mã. Rất khó để thiết lập một mô hình khí an toàn tương ứng mà không giới hạn quy mô. 32 byte là một kích thước lý tưởng vì nó đủ để lưu trữ các giá trị và địa chỉ lớn theo yêu cầu của nhiều thuật toán mật mã mà không quá lớn gây ra sự kém hiệu quả.
Chúng tôi có máy ảo của riêng mình: máy ảo của chúng tôi được phát triển bằng các ngôn ngữ như java, Lisp và Lua. Chúng tôi nghĩ rằng đáng để phát triển một máy ảo chuyên dụng vì: 1) Đặc điểm kỹ thuật VM của chúng tôi đơn giản hơn nhiều so với nhiều máy ảo khác, bởi vì các máy ảo khác trả ít tiền hơn cho độ phức tạp, nghĩa là chúng dễ thay đổi hơn. sự phức tạp trong kế hoạch của chúng tôi tạo ra các rào cản đối với sự phát triển tăng cường và đưa ra các lỗ hổng bảo mật tiềm ẩn, chẳng hạn như lỗi đồng thuận, khiến chi phí phức tạp của chúng tôi cao;2) VM của chúng tôi chuyên biệt hơn, chẳng hạn như hỗ trợ 32 byte; 3) Chúng tôi sẽ không có bên ngoài phức tạp phụ thuộc, điều này sẽ khiến cài đặt của chúng tôi không thành công; 4) Cơ chế xem xét hoàn chỉnh có thể dành riêng cho các yêu cầu bảo mật đặc biệt; Ngay cả khi sử dụng máy ảo bên ngoài cũng không tiết kiệm được nhiều công việc.
Kích thước bộ nhớ có thể mở rộng, có thể thay đổi được sử dụng: kích thước bộ nhớ cố định là một ràng buộc không cần thiết, quá nhỏ hoặc quá lớn. Nếu kích thước bộ nhớ là cố định, thì cần phải kiểm tra xem quyền truy cập có vượt quá ranh giới mỗi khi truy cập bộ nhớ hay không, điều này rõ ràng là không hiệu quả.
1024 Giới hạn độ sâu cuộc gọi: Nhiều ngôn ngữ lập trình gặp sự cố do độ sâu cuộc gọi quá sâu trước khi tràn bộ nhớ. Vì vậy, nó không đủ để sử dụng giới hạn khí khối như một giới hạn.
Untyped: chỉ cho ngắn gọn. Tuy nhiên, DIV, SDIV, MOD, SMOD sử dụng opcodes có dấu hoặc không dấu (hóa ra là có dấu và không dấu tương đương với opcode ADD và MUL); Các trường hợp rất đơn giản, ví dụ: a * b -> (a * b) / 2^32, a / b -> a * 2^32 / b ở độ dài 32 bit, +, - và * ở dạng số nguyên không đổi.
Hiệu đính Lưu ý: Trong bản dịch gốc cũng có đoạn sau, nhưng đoạn tương ứng của nó đã bị xóa trong phiên bản hiện tại của văn bản gốc: Không có giới hạn về kích thước ngăn xếp: không có lý do đặc biệt! Trong nhiều trường hợp, thiết kế này không thực sự cần thiết; vì, chi phí gas và nắp gas khối sẽ luôn đóng vai trò là giới hạn tiêu thụ của từng tài nguyên.
Chức năng và mục đích của một số opcode trong VM này rất dễ hiểu, nhưng một số thì không, và đây là một số lý do đặc biệt:
ADDMOD,MULMOD: Trong hầu hết các trường hợp, mulmod(a, b, c) = a * b % c, nhưng trong thuật toán đường cong elip, phép toán mô đun 32 byte được sử dụng và việc thực thi trực tiếp a * b % c thực sự nằm trong Thực thi ((a * b) % 2^256) % c sẽ cho một kết quả hoàn toàn khác. Đồng thuận thực hiện tính toán a * b % c của giá trị 32 byte trong không gian 32 byte là khó khăn và tẻ nhạt.
SIGNEXTEND: Mục đích của opcode SIGNEXTEND là tạo thuận lợi cho việc chuyển đổi kiểu từ số nguyên có dấu lớn sang số nguyên có dấu nhỏ. Các số nguyên có dấu nhỏ rất hữu ích vì các máy ảo just-in-time trong tương lai có thể có khả năng phát hiện các khối mã chạy dài chủ yếu xử lý các số nguyên 32 byte và các số nguyên có dấu nhỏ có thể tăng tốc độ xử lý.
SHA3: Trong mã Ethereum, SHA3 được sử dụng rộng rãi như một phương pháp ánh xạ băm dữ liệu có độ dài thay đổi, an toàn, độ bền cao. Nói chung, khi sử dụng bộ nhớ, bạn cần sử dụng các hàm Hash để ngăn chặn các xung đột độc hại và bạn cần sử dụng các hàm Hash khi xác minh cây Merkle và các cấu trúc dữ liệu Ethereum tương tự. Điều quan trọng là các hàm băm tương tự như SHA3, chẳng hạn như SHA256, ECRECVOR, RIPEM160, không được bao gồm ở dạng opcode mà ở dạng hợp đồng giả. Mục đích của việc này là đặt chúng vào một danh mục riêng biệt và nếu sau này khi chúng tôi nghĩ ra một hệ thống "plugin gốc" thích hợp, thì có thể thêm nhiều hợp đồng như vậy mà không cần mã mở rộng.
ORIGIN: Opcode ORIGIN được cung cấp bởi người gửi giao dịch và chức năng chính của nó là cho phép hợp đồng trả lại gas đã thanh toán.
COINBASE: Vai trò chính của COINBASE là: 1) cho phép các đồng tiền phụ đóng góp vào an ninh mạng; 2) cho phép các công ty khai thác hoạt động như một nền kinh tế phi tập trung để thiết lập các ứng dụng dựa trên sự đồng thuận phụ, chẳng hạn như Schellingcoin.
PREVHASH: PREVHASH có thể được sử dụng như một nguồn ngẫu nhiên bán an toàn. Hơn nữa, nó cho phép các hợp đồng đánh giá bằng chứng trạng thái cây Merkle của khối trước đó mà không yêu cầu cấu trúc đệ quy "Ethereum light client" rất phức tạp.
EXTCODESIZE,EXTCODECOPY: Chức năng chính là để hợp đồng kiểm tra mã của các hợp đồng khác theo mẫu và thậm chí mô phỏng chúng trước khi tương tác với các hợp đồng khác. Xem: https://lesswrong.com/lw/aq9/decision_theories_a_less_wrong_primer/
JUMPDEST: Khi đích nhảy bị giới hạn trong một vài chỉ mục (cụ thể, độ phức tạp tính toán của các bước nhảy đích động là O(log (số lượng đích thử thách hợp lệ)), trong khi các bước nhảy tĩnh luôn không đổi), các máy ảo JIT sẽ đơn giản hơn để thực hiện. Do đó, chúng ta cần: 1) hạn chế các đích nhảy biến hợp lệ; 2) khuyến khích sử dụng các bước nhảy tĩnh thay vì động. Để đạt được hai mục tiêu này, chúng tôi đặt ra các quy tắc sau: 1) lần nhảy ngay sau khi đẩy có thể nhảy bất cứ đâu, không chỉ một lần nhảy khác; 2) các lần nhảy khác chỉ có thể nhảy đến JUMPDEST. Các hạn chế về bước nhảy là cần thiết để có thể xác định xem bước nhảy hiện tại là bước nhảy tĩnh hay bước nhảy động bằng cách xem thao tác trước đó trong mã. Việc không cần đến các bước nhảy tĩnh là động lực thúc đẩy việc sử dụng chúng. Vô hiệu hóa các bước nhảy vào dữ liệu đẩy cũng tăng tốc độ biên dịch và thực thi JIT VM.
LOG: LOG là nhật ký các sự kiện.
CALLCODE: Opcode này cho phép một hợp đồng sử dụng các mục lưu trữ của chính nó để gọi "chức năng" của các hợp đồng khác trong một không gian ngăn xếp và bộ nhớ riêng biệt. Điều này cho phép triển khai linh hoạt mã thư viện tiêu chuẩn trên chuỗi khối.
SELFDESTRUCT: Cho phép hợp đồng tự xóa nếu nó không còn tồn tại nữa. SELFDESTRUCT không được thực hiện ngay lập tức mà sau khi giao dịch được thực hiện. Điều này là do việc cho phép SELFDESTRUCT khôi phục sau khi thực thi sẽ làm tăng đáng kể độ phức tạp của bộ nhớ đệm, điều này không có lợi cho việc triển khai VM hiệu quả.
Liên kết gốc:
(qua)
Liên kết gốc:
https://eth.wiki/en/fundamentals/design-rationale
Tác giả: Vitalik
Dịch & hiệu đính: kim & A Jian


