Nói ngắn gọn là RLP, RLP là gói Ethereum được sử dụng để tuần tự hóa tất cả các đối tượng thành mảng byte. Nó được mô tả trên Giấy vàng với nhiều công thức và rất khó hiểu.
Bởi vì Ethereum là một chuỗi khối phi tập trung, cho phép thực hiện các hợp đồng thông minh và lưu trữ dữ liệu trên chuỗi khối, nên nó cần phải được tuần tự hóa hoặc chuyển đổi thành định dạng nhị phân, được lưu trữ trong một lượng không gian tối thiểu trong chuỗi khối.
RLP là lược đồ mã hóa dựa trên tiền tố mã hóa dữ liệu nhị phân có cấu trúc tùy ý (mảng byte) theo cách dễ mã hóa và giải mã. Thuật toán RLP hoạt động bằng cách mã hóa đệ quy một danh sách các mục.
Một mục được định nghĩa như sau:
- Một chuỗi (mảng byte)
- Một danh sách các “mặt hàng” chính nó
Ví dụ:
- Một chuỗi (mảng byte), bao gồm một chuỗi rỗng
- Một danh sách chứa bất kỳ số chuỗi nào
- Một cấu trúc dữ liệu phức tạp như
["cat", ["dog", "mouse"], [], ["""]]
Đi qua Sách vàng (Phụ lục B)
Chúng tôi có ba công thức mô tả dữ liệu nhị phân có cấu trúc tùy ý (mảng byte) :
- T: Dữ liệu nhị phân có cấu trúc tùy ý, là tập hợp các mảng byte và chuỗi cấu trúc
- L: Tập hợp tất cả các cấu trúc dạng cây không phải là một lá
- O: Tập hợp các byte 8 bit
- B: Tập hợp tất cả các chuỗi byte (mảng byte hoặc lá trong cây)
- Chúng tôi sử dụng liên kết rời rạc để phân biệt mảng byte trống (trong B) với danh sách trống (trong L).
Chúng tôi xác định chức năng RLP là RLP thông qua hai chức năng con:
- Việc xử lý đầu tiên của các mảng byte
- Cái thứ hai xử lý chuỗi các giá trị khác
Chúng ta sẽ đi sâu vào hàm đầu tiên xử lý mảng byte, RLP(B) . Nếu giá trị được sắp xếp theo thứ tự là một mảng byte, thì RLP(B) sẽ có một trong ba dạng:
- Một byte nhỏ hơn 128 (thập phân), đầu ra giống với đầu vào
- Nếu các byte mảng chứa ít hơn 56 byte, thì đầu ra bằng với đầu vào có tiền tố là byte bằng với độ dài của byte mảng + 128
- Mặt khác, đầu ra bằng với biểu diễn đầu lớn của độ dài đầu vào ở phía trước đầu vào và sau đó là (183 + độ dài của đầu lớn của đầu vào)
Thứ hai, chúng ta sẽ xem cách hoạt động của RLP(L). Chúng tôi sử dụng RLP(L) để mã hóa từng mục, sau đó nối đầu ra.
- Nếu chiều dài nhỏ hơn 56 thì xuất ra bằng: 192 + chiều dài mặt hàng + mặt hàng
- Mặt khác, đầu ra bằng: 247 + chiều dài của phần cuối lớn của chiều dài mục + phần cuối lớn của chiều dài của mục + mục
Bạn có thể thấy s(x) là đệ quy của RLP với mỗi mục.
Thuật toán RLP dưới dạng mã như (ví dụ từ ethereum.org ):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | <span class="token keyword">def</span> <span class="token function">rlp_encode</span> <span class="token punctuation">(</span> <span class="token builtin">input</span> <span class="token punctuation">)</span> <span class="token punctuation">:</span> <span class="token keyword">if</span> <span class="token builtin">isinstance</span> <span class="token punctuation">(</span> <span class="token builtin">input</span> <span class="token punctuation">,</span> <span class="token builtin">str</span> <span class="token punctuation">)</span> <span class="token punctuation">:</span> <span class="token operator">//</span> <span class="token number">0x80</span> <span class="token operator">=</span> <span class="token number">128</span> <span class="token punctuation">(</span> decimal <span class="token punctuation">)</span> <span class="token keyword">if</span> <span class="token builtin">len</span> <span class="token punctuation">(</span> <span class="token builtin">input</span> <span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token number">1</span> <span class="token keyword">and</span> <span class="token builtin">ord</span> <span class="token punctuation">(</span> <span class="token builtin">input</span> <span class="token punctuation">)</span> <span class="token operator"><</span> <span class="token number">0x80</span> <span class="token punctuation">:</span> <span class="token keyword">return</span> <span class="token builtin">input</span> <span class="token keyword">else</span> <span class="token punctuation">:</span> <span class="token keyword">return</span> encode_length <span class="token punctuation">(</span> <span class="token builtin">len</span> <span class="token punctuation">(</span> <span class="token builtin">input</span> <span class="token punctuation">)</span> <span class="token punctuation">,</span> <span class="token number">0x80</span> <span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token builtin">input</span> <span class="token keyword">elif</span> <span class="token builtin">isinstance</span> <span class="token punctuation">(</span> <span class="token builtin">input</span> <span class="token punctuation">,</span> <span class="token builtin">list</span> <span class="token punctuation">)</span> <span class="token punctuation">:</span> output <span class="token operator">=</span> <span class="token string">''</span> <span class="token keyword">for</span> item <span class="token keyword">in</span> <span class="token builtin">input</span> <span class="token punctuation">:</span> output <span class="token operator">+=</span> rlp_encode <span class="token punctuation">(</span> item <span class="token punctuation">)</span> <span class="token keyword">return</span> encode_length <span class="token punctuation">(</span> <span class="token builtin">len</span> <span class="token punctuation">(</span> output <span class="token punctuation">)</span> <span class="token punctuation">,</span> <span class="token number">0xc0</span> <span class="token punctuation">)</span> <span class="token operator">+</span> output <span class="token keyword">def</span> <span class="token function">encode_length</span> <span class="token punctuation">(</span> L <span class="token punctuation">,</span> offset <span class="token punctuation">)</span> <span class="token punctuation">:</span> <span class="token keyword">if</span> L <span class="token operator"><</span> <span class="token number">56</span> <span class="token punctuation">:</span> <span class="token keyword">return</span> <span class="token builtin">chr</span> <span class="token punctuation">(</span> L <span class="token operator">+</span> offset <span class="token punctuation">)</span> <span class="token keyword">elif</span> L <span class="token operator"><</span> <span class="token number">256</span> <span class="token operator">**</span> <span class="token number">8</span> <span class="token punctuation">:</span> BL <span class="token operator">=</span> to_binary <span class="token punctuation">(</span> L <span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token builtin">chr</span> <span class="token punctuation">(</span> <span class="token builtin">len</span> <span class="token punctuation">(</span> BL <span class="token punctuation">)</span> <span class="token operator">+</span> offset <span class="token operator">+</span> <span class="token number">55</span> <span class="token punctuation">)</span> <span class="token operator">+</span> BL <span class="token keyword">else</span> <span class="token punctuation">:</span> <span class="token keyword">raise</span> Exception <span class="token punctuation">(</span> <span class="token string">"input too long"</span> <span class="token punctuation">)</span> <span class="token keyword">def</span> <span class="token function">to_binary</span> <span class="token punctuation">(</span> x <span class="token punctuation">)</span> <span class="token punctuation">:</span> <span class="token keyword">if</span> x <span class="token operator">==</span> <span class="token number">0</span> <span class="token punctuation">:</span> <span class="token keyword">return</span> <span class="token string">''</span> <span class="token keyword">else</span> <span class="token punctuation">:</span> <span class="token keyword">return</span> to_binary <span class="token punctuation">(</span> <span class="token builtin">int</span> <span class="token punctuation">(</span> x <span class="token operator">/</span> <span class="token number">256</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token builtin">chr</span> <span class="token punctuation">(</span> x <span class="token operator">%</span> <span class="token number">256</span> <span class="token punctuation">)</span> |
Bạn có thể xem ví dụ trong tài liệu Ethereum với một số đầu vào:
- Chuỗi “ethereum” => [“0x88”, “e”, “t”, “h”, “e”, “r”, “e”, “u”, “m”] => vì độ dài của chuỗi này có 8 ký tự, nhỏ hơn 56. Vì vậy, đầu ra là encoded_length(8, 128) + input = chr(136) + “ethereum” = [“0x88”, “e”, “t”, “h”, “e”, “r”, “e”, “u”, “m”]
- Một danh sách [“ethereum”, “nền tảng”]:
rlp_encode("ethereum") = ["0x88", "e", "t", "h", "e", "r", "e", "u", "m"]
rlp_encode("foundation") = ["0x8A", "f", "o", "u", "n", "d", "a", "t", "i", "o", "n"]
rlp_encode(["ethereum", "foundation"]) = encode_length(20, 192) + ["0x88", "e", "t", "h", "e", "r", "e", "u", "m", "0x8A", "f", "o", "u", "n", "d", "a", "t", "i", "o", "n"] = ["0xD4", "0x88", "e", "t", "h", "e", "r", "e", "u", "m", "0x8A", "f", "o", "u", "n", "d", "a", "t", "i", "o", "n"]
giải mã RLP
Do các quy tắc mã hóa RLP, đầu vào của giải mã RLP là một mảng dữ liệu nhị phân.
- Tùy thuộc vào byte đầu tiên trong đầu vào, chúng ta có thể xác định loại dữ liệu và độ dài của dữ liệu và độ lệch.
- Tùy theo kiểu dữ liệu và offset của dữ liệu mà giải mã dữ liệu tương ứng.
- Tiếp tục vòng lặp để giải mã phần còn lại của đầu vào.
Với các công thức RLP, chúng ta có thể xác định các quy tắc giải mã kiểu dữ liệu và bù đắp bằng cách sau:
- Nếu phạm vi của byte đầu tiên là từ [0x00, 0x7f] và độ dài của đầu vào là 1, thì kiểu dữ liệu là một chuỗi và dữ liệu chính là chuỗi đó.
- Nếu phạm vi của byte đầu tiên là từ [0x80, 0xb7], thì kiểu dữ liệu là một chuỗi và độ dài của chuỗi bằng byte đầu tiên trừ đi 0x80
- Nếu phạm vi của byte đầu tiên là [0xb8, 0xbf] và độ dài của chuỗi có độ dài tính bằng byte bằng byte đầu tiên trừ 0xb7 theo sau byte đầu tiên và chuỗi theo sau độ dài của chuỗi;
- Nếu phạm vi của byte đầu tiên là [0xc0, 0xf7] và phép nối mã hóa RLP của tất cả các mục trong danh sách có tổng tải trọng bằng byte đầu tiên trừ đi 0xc0 theo sau byte đầu tiên;
- Nếu phạm vi của byte đầu tiên là [0xf8, 0xff] và tổng tải trọng của danh sách có độ dài bằng byte đầu tiên trừ đi 0xf7 theo sau byte đầu tiên và nối mã hóa RLP của tất cả các mục trong danh sách theo sau tổng trọng tải của danh sách;
Nguồn: Tài liệu Ethereum
Mã giả từ Tài liệu Ethereum:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | <span class="token keyword">def</span> <span class="token function">rlp_decode</span> <span class="token punctuation">(</span> <span class="token builtin">input</span> <span class="token punctuation">)</span> <span class="token punctuation">:</span> <span class="token keyword">if</span> <span class="token builtin">len</span> <span class="token punctuation">(</span> <span class="token builtin">input</span> <span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token number">0</span> <span class="token punctuation">:</span> <span class="token keyword">return</span> output <span class="token operator">=</span> <span class="token string">''</span> <span class="token punctuation">(</span> offset <span class="token punctuation">,</span> dataLen <span class="token punctuation">,</span> <span class="token builtin">type</span> <span class="token punctuation">)</span> <span class="token operator">=</span> decode_length <span class="token punctuation">(</span> <span class="token builtin">input</span> <span class="token punctuation">)</span> <span class="token keyword">if</span> <span class="token builtin">type</span> <span class="token keyword">is</span> <span class="token builtin">str</span> <span class="token punctuation">:</span> output <span class="token operator">=</span> instantiate_str <span class="token punctuation">(</span> substr <span class="token punctuation">(</span> <span class="token builtin">input</span> <span class="token punctuation">,</span> offset <span class="token punctuation">,</span> dataLen <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token keyword">elif</span> <span class="token builtin">type</span> <span class="token keyword">is</span> <span class="token builtin">list</span> <span class="token punctuation">:</span> output <span class="token operator">=</span> instantiate_list <span class="token punctuation">(</span> substr <span class="token punctuation">(</span> <span class="token builtin">input</span> <span class="token punctuation">,</span> offset <span class="token punctuation">,</span> dataLen <span class="token punctuation">)</span> <span class="token punctuation">)</span> output <span class="token operator">+</span> rlp_decode <span class="token punctuation">(</span> substr <span class="token punctuation">(</span> <span class="token builtin">input</span> <span class="token punctuation">,</span> offset <span class="token operator">+</span> dataLen <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token keyword">return</span> output <span class="token keyword">def</span> <span class="token function">decode_length</span> <span class="token punctuation">(</span> <span class="token builtin">input</span> <span class="token punctuation">)</span> <span class="token punctuation">:</span> length <span class="token operator">=</span> <span class="token builtin">len</span> <span class="token punctuation">(</span> <span class="token builtin">input</span> <span class="token punctuation">)</span> <span class="token keyword">if</span> length <span class="token operator">==</span> <span class="token number">0</span> <span class="token punctuation">:</span> <span class="token keyword">raise</span> Exception <span class="token punctuation">(</span> <span class="token string">"input is null"</span> <span class="token punctuation">)</span> prefix <span class="token operator">=</span> <span class="token builtin">ord</span> <span class="token punctuation">(</span> <span class="token builtin">input</span> <span class="token punctuation">[</span> <span class="token number">0</span> <span class="token punctuation">]</span> <span class="token punctuation">)</span> <span class="token keyword">if</span> prefix <span class="token operator"><=</span> <span class="token number">0x7f</span> <span class="token punctuation">:</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token number">0</span> <span class="token punctuation">,</span> <span class="token number">1</span> <span class="token punctuation">,</span> <span class="token builtin">str</span> <span class="token punctuation">)</span> <span class="token keyword">elif</span> prefix <span class="token operator"><=</span> <span class="token number">0xb7</span> <span class="token keyword">and</span> length <span class="token operator">></span> prefix <span class="token operator">-</span> <span class="token number">0x80</span> <span class="token punctuation">:</span> strLen <span class="token operator">=</span> prefix <span class="token operator">-</span> <span class="token number">0x80</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token number">1</span> <span class="token punctuation">,</span> strLen <span class="token punctuation">,</span> <span class="token builtin">str</span> <span class="token punctuation">)</span> <span class="token keyword">elif</span> prefix <span class="token operator"><=</span> <span class="token number">0xbf</span> <span class="token keyword">and</span> length <span class="token operator">></span> prefix <span class="token operator">-</span> <span class="token number">0xb7</span> <span class="token keyword">and</span> length <span class="token operator">></span> prefix <span class="token operator">-</span> <span class="token number">0xb7</span> <span class="token operator">+</span> to_integer <span class="token punctuation">(</span> substr <span class="token punctuation">(</span> <span class="token builtin">input</span> <span class="token punctuation">,</span> <span class="token number">1</span> <span class="token punctuation">,</span> prefix <span class="token operator">-</span> <span class="token number">0xb7</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">:</span> lenOfStrLen <span class="token operator">=</span> prefix <span class="token operator">-</span> <span class="token number">0xb7</span> strLen <span class="token operator">=</span> to_integer <span class="token punctuation">(</span> substr <span class="token punctuation">(</span> <span class="token builtin">input</span> <span class="token punctuation">,</span> <span class="token number">1</span> <span class="token punctuation">,</span> lenOfStrLen <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token number">1</span> <span class="token operator">+</span> lenOfStrLen <span class="token punctuation">,</span> strLen <span class="token punctuation">,</span> <span class="token builtin">str</span> <span class="token punctuation">)</span> <span class="token keyword">elif</span> prefix <span class="token operator"><=</span> <span class="token number">0xf7</span> <span class="token keyword">and</span> length <span class="token operator">></span> prefix <span class="token operator">-</span> <span class="token number">0xc0</span> <span class="token punctuation">:</span> listLen <span class="token operator">=</span> prefix <span class="token operator">-</span> <span class="token number">0xc0</span> <span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token number">1</span> <span class="token punctuation">,</span> listLen <span class="token punctuation">,</span> <span class="token builtin">list</span> <span class="token punctuation">)</span> <span class="token keyword">elif</span> prefix <span class="token operator"><=</span> <span class="token number">0xff</span> <span class="token keyword">and</span> length <span class="token operator">></span> prefix <span class="token operator">-</span> <span class="token number">0xf7</span> <span class="token keyword">and</span> length <span class="token operator">></span> prefix <span class="token operator">-</span> <span class="token number">0xf7</span> <span class="token operator">+</span> to_integer <span class="token punctuation">(</span> substr <span class="token punctuation">(</span> <span class="token builtin">input</span> <span class="token punctuation">,</span> <span class="token number">1</span> <span class="token punctuation">,</span> prefix <span class="token operator">-</span> <span class="token number">0xf7</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">:</span> lenOfListLen <span class="token operator">=</span> prefix <span class="token operator">-</span> <span class="token number">0xf7</span> listLen <span class="token operator">=</span> to_integer <span class="token punctuation">(</span> substr <span class="token punctuation">(</span> <span class="token builtin">input</span> <span class="token punctuation">,</span> <span class="token number">1</span> <span class="token punctuation">,</span> lenOfListLen <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token number">1</span> <span class="token operator">+</span> lenOfListLen <span class="token punctuation">,</span> listLen <span class="token punctuation">,</span> <span class="token builtin">list</span> <span class="token punctuation">)</span> <span class="token keyword">else</span> <span class="token punctuation">:</span> <span class="token keyword">raise</span> Exception <span class="token punctuation">(</span> <span class="token string">"input does not conform to RLP encoding form"</span> <span class="token punctuation">)</span> <span class="token keyword">def</span> <span class="token function">to_integer</span> <span class="token punctuation">(</span> b <span class="token punctuation">)</span> <span class="token punctuation">:</span> length <span class="token operator">=</span> <span class="token builtin">len</span> <span class="token punctuation">(</span> b <span class="token punctuation">)</span> <span class="token keyword">if</span> length <span class="token operator">==</span> <span class="token number">0</span> <span class="token punctuation">:</span> <span class="token keyword">raise</span> Exception <span class="token punctuation">(</span> <span class="token string">"input is null"</span> <span class="token punctuation">)</span> <span class="token keyword">elif</span> length <span class="token operator">==</span> <span class="token number">1</span> <span class="token punctuation">:</span> <span class="token keyword">return</span> <span class="token builtin">ord</span> <span class="token punctuation">(</span> b <span class="token punctuation">[</span> <span class="token number">0</span> <span class="token punctuation">]</span> <span class="token punctuation">)</span> <span class="token keyword">else</span> <span class="token punctuation">:</span> <span class="token keyword">return</span> <span class="token builtin">ord</span> <span class="token punctuation">(</span> substr <span class="token punctuation">(</span> b <span class="token punctuation">,</span> <span class="token operator">-</span> <span class="token number">1</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token operator">+</span> to_integer <span class="token punctuation">(</span> substr <span class="token punctuation">(</span> b <span class="token punctuation">,</span> <span class="token number">0</span> <span class="token punctuation">,</span> <span class="token operator">-</span> <span class="token number">1</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token operator">*</span> <span class="token number">256</span> |
Rất khó hiểu đầy đủ với các công thức này, vì vậy chúng ta cần gỡ lỗi để biết kết quả đầu ra khi chúng ta sử dụng RLP để mã hóa/giải mã dữ liệu nhị phân có cấu trúc tùy ý.
Go-ethereum RLP
Bạn nào chưa rành về Golang có thể đọc các bản khác do Typescript viết Với mình thì bản này dễ hiểu hơn bản gốc do Golang viết
Cấu trúc gói RLP:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | ├── decode <span class="token punctuation">.</span> go ├── decode_tail_test <span class="token punctuation">.</span> go ├── decode_test <span class="token punctuation">.</span> go ├── doc <span class="token punctuation">.</span> go ├── encbuffer <span class="token punctuation">.</span> go ├── encbuffer_example_test <span class="token punctuation">.</span> go ├── encode <span class="token punctuation">.</span> go ├── encode_test <span class="token punctuation">.</span> go ├── encoder_example_test <span class="token punctuation">.</span> go ├── internal │ └── rlpstruct │ └── rlpstruct <span class="token punctuation">.</span> go ├── iterator <span class="token punctuation">.</span> go ├── iterator_test <span class="token punctuation">.</span> go ├── raw <span class="token punctuation">.</span> go ├── raw_test <span class="token punctuation">.</span> go ├── rlpgen │ ├── gen <span class="token punctuation">.</span> go │ ├── gen_test <span class="token punctuation">.</span> go │ ├── main <span class="token punctuation">.</span> go │ ├── testdata │ │ ├── bigint <span class="token punctuation">.</span> in <span class="token punctuation">.</span> txt │ │ ├── bigint <span class="token punctuation">.</span> out <span class="token punctuation">.</span> txt │ │ ├── nil <span class="token punctuation">.</span> in <span class="token punctuation">.</span> txt │ │ ├── nil <span class="token punctuation">.</span> out <span class="token punctuation">.</span> txt │ │ ├── optional <span class="token punctuation">.</span> in <span class="token punctuation">.</span> txt │ │ ├── optional <span class="token punctuation">.</span> out <span class="token punctuation">.</span> txt │ │ ├── rawvalue <span class="token punctuation">.</span> in <span class="token punctuation">.</span> txt │ │ ├── rawvalue <span class="token punctuation">.</span> out <span class="token punctuation">.</span> txt │ │ ├── uint256 <span class="token punctuation">.</span> in <span class="token punctuation">.</span> txt │ │ ├── uint256 <span class="token punctuation">.</span> out <span class="token punctuation">.</span> txt │ │ ├── uints <span class="token punctuation">.</span> in <span class="token punctuation">.</span> txt │ │ └── uints <span class="token punctuation">.</span> out <span class="token punctuation">.</span> txt │ └── types <span class="token punctuation">.</span> go ├── safe <span class="token punctuation">.</span> go ├── typecache <span class="token punctuation">.</span> go └── unsafe <span class="token punctuation">.</span> go |
mã hóa.go
Đầu tiên chúng ta hãy xem giao diện Encode
1 2 3 4 | <span class="token keyword">type</span> Encoder <span class="token keyword">interface</span> <span class="token punctuation">{</span> <span class="token function">EncodeRLP</span> <span class="token punctuation">(</span> io <span class="token punctuation">.</span> Writer <span class="token punctuation">)</span> <span class="token builtin">error</span> <span class="token punctuation">}</span> |
Giao diện này chỉ có một chức năng, lấy io.Writer
làm đầu vào và ghi trực tiếp đầu ra vào io.Writer
. Mọi thứ được lưu trữ trên chuỗi khối Ethereum nên sử dụng RLP để mã hóa. Có rất nhiều triển khai:
Tiếp theo, chúng ta có một hàm gọi là func Encode(w io.Writer, val interface{}) error
, hàm này sẽ lấy w
và v
để mã hóa thành dữ liệu nhị phân.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | <span class="token keyword">func</span> <span class="token function">Encode</span> <span class="token punctuation">(</span> w io <span class="token punctuation">.</span> Writer <span class="token punctuation">,</span> val <span class="token keyword">interface</span> <span class="token punctuation">{</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token builtin">error</span> <span class="token punctuation">{</span> <span class="token comment">// Optimization: reuse *encBuffer when called by EncodeRLP.</span> <span class="token keyword">if</span> buf <span class="token operator">:=</span> <span class="token function">encBufferFromWriter</span> <span class="token punctuation">(</span> w <span class="token punctuation">)</span> <span class="token punctuation">;</span> buf <span class="token operator">!=</span> <span class="token boolean">nil</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> buf <span class="token punctuation">.</span> <span class="token function">encode</span> <span class="token punctuation">(</span> val <span class="token punctuation">)</span> <span class="token punctuation">}</span> buf <span class="token operator">:=</span> <span class="token function">getEncBuffer</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token keyword">defer</span> encBufferPool <span class="token punctuation">.</span> <span class="token function">Put</span> <span class="token punctuation">(</span> buf <span class="token punctuation">)</span> <span class="token keyword">if</span> err <span class="token operator">:=</span> buf <span class="token punctuation">.</span> <span class="token function">encode</span> <span class="token punctuation">(</span> val <span class="token punctuation">)</span> <span class="token punctuation">;</span> err <span class="token operator">!=</span> <span class="token boolean">nil</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> err <span class="token punctuation">}</span> <span class="token keyword">return</span> buf <span class="token punctuation">.</span> <span class="token function">writeTo</span> <span class="token punctuation">(</span> w <span class="token punctuation">)</span> <span class="token punctuation">}</span> |
Đây là chức năng chính được gọi bởi các triển khai để mã hóa đầu vào. Go-ethereum sử dụng encBufferFromWriter
để giảm phân bổ, chúng ta sẽ đi sâu vào vấn đề này.
1 2 3 4 5 6 7 8 9 10 11 12 13 | <span class="token keyword">func</span> <span class="token function">encBufferFromWriter</span> <span class="token punctuation">(</span> w io <span class="token punctuation">.</span> Writer <span class="token punctuation">)</span> <span class="token operator">*</span> encBuffer <span class="token punctuation">{</span> <span class="token keyword">switch</span> w <span class="token operator">:=</span> w <span class="token punctuation">.</span> <span class="token punctuation">(</span> <span class="token keyword">type</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">case</span> EncoderBuffer <span class="token punctuation">:</span> <span class="token keyword">return</span> w <span class="token punctuation">.</span> buf <span class="token keyword">case</span> <span class="token operator">*</span> EncoderBuffer <span class="token punctuation">:</span> <span class="token keyword">return</span> w <span class="token punctuation">.</span> buf <span class="token keyword">case</span> <span class="token operator">*</span> encBuffer <span class="token punctuation">:</span> <span class="token keyword">return</span> w <span class="token keyword">default</span> <span class="token punctuation">:</span> <span class="token keyword">return</span> <span class="token boolean">nil</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
Lý do chính vì nhóm tác giả đang sử dụng cấu trúc encBuffer
để mã hóa dữ liệu đầu vào. Vì vậy, nếu w
là loại encBuffer
, chúng tôi sử dụng lại nó để mã hóa đầu vào.
Nhưng tôi có một câu hỏi, tại sao họ cần tạo một struct encBuffer
mới để mã hóa? Hãy xem nào. Trong một số phiên bản trước của Go-ethereum, họ không sử dụng cấu trúc này. Cấu trúc encBuffer
là:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | <span class="token comment">// EncoderBuffer is a buffer for incremental encoding.</span> <span class="token comment">//</span> <span class="token comment">// The zero value is NOT ready for use. To get a usable buffer,</span> <span class="token comment">// create it using NewEncoderBuffer or call Reset.</span> <span class="token keyword">type</span> EncoderBuffer <span class="token keyword">struct</span> <span class="token punctuation">{</span> buf <span class="token operator">*</span> encBuffer dst io <span class="token punctuation">.</span> Writer ownBuffer <span class="token builtin">bool</span> <span class="token punctuation">}</span> <span class="token keyword">type</span> listhead <span class="token keyword">struct</span> <span class="token punctuation">{</span> offset <span class="token builtin">int</span> <span class="token comment">// index of this header in string data</span> size <span class="token builtin">int</span> <span class="token comment">// total size of encoded data (including list headers)</span> <span class="token punctuation">}</span> <span class="token keyword">type</span> encBuffer <span class="token keyword">struct</span> <span class="token punctuation">{</span> str <span class="token punctuation">[</span> <span class="token punctuation">]</span> <span class="token builtin">byte</span> <span class="token comment">// string data, contains everything except list headers</span> lheads <span class="token punctuation">[</span> <span class="token punctuation">]</span> listhead <span class="token comment">// all list headers</span> lhsize <span class="token builtin">int</span> <span class="token comment">// sum of sizes of all encoded list headers</span> sizebuf <span class="token punctuation">[</span> <span class="token number">9</span> <span class="token punctuation">]</span> <span class="token builtin">byte</span> <span class="token comment">// auxiliary buffer for uint encoding</span> <span class="token punctuation">}</span> |
và trong encbuffer.go
, chúng tôi có một nhóm đồng bộ lưu trữ encBuffer
1 2 3 4 5 6 | <span class="token comment">// The global encBuffer pool.</span> <span class="token keyword">var</span> encBufferPool <span class="token operator">=</span> sync <span class="token punctuation">.</span> Pool <span class="token punctuation">{</span> New <span class="token punctuation">:</span> <span class="token keyword">func</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token keyword">interface</span> <span class="token punctuation">{</span> <span class="token punctuation">}</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token function">new</span> <span class="token punctuation">(</span> encBuffer <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token punctuation">}</span> |
Tóm lại, chúng tôi có một số điểm:
go-ethereum
sử dụngencBuffer
để lưu trữ đầu ra nhị phân được mã hóa- Họ sử dụng
a pool
để lưu trữencBuffer
để tái sử dụng trong bước tiếp theo
Bước tiếp theo, chúng ta có một hàm buf.encode(val)
để mã hóa val
dựa trên loại val
1 2 3 4 5 6 7 8 9 | <span class="token keyword">func</span> <span class="token punctuation">(</span> buf <span class="token operator">*</span> encBuffer <span class="token punctuation">)</span> <span class="token function">encode</span> <span class="token punctuation">(</span> val <span class="token keyword">interface</span> <span class="token punctuation">{</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token builtin">error</span> <span class="token punctuation">{</span> rval <span class="token operator">:=</span> reflect <span class="token punctuation">.</span> <span class="token function">ValueOf</span> <span class="token punctuation">(</span> val <span class="token punctuation">)</span> writer <span class="token punctuation">,</span> err <span class="token operator">:=</span> <span class="token function">cachedWriter</span> <span class="token punctuation">(</span> rval <span class="token punctuation">.</span> <span class="token function">Type</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token keyword">if</span> err <span class="token operator">!=</span> <span class="token boolean">nil</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> err <span class="token punctuation">}</span> <span class="token keyword">return</span> <span class="token function">writer</span> <span class="token punctuation">(</span> rval <span class="token punctuation">,</span> buf <span class="token punctuation">)</span> <span class="token punctuation">}</span> |
Bạn có thể thấy, go-ethereum
sử dụng sự phản chiếu và mã hóa RLP dựa trên loại Go của giá trị. writer
là một hàm sẽ mã hóa dựa trên loại và ghi vào encBuffer
Chúng ta có một hàm cachedWriter
khác sẽ trả về hàm writer
với kiểu Go.
1 2 3 4 5 | <span class="token keyword">func</span> <span class="token function">cachedWriter</span> <span class="token punctuation">(</span> typ reflect <span class="token punctuation">.</span> Type <span class="token punctuation">)</span> <span class="token punctuation">(</span> writer <span class="token punctuation">,</span> <span class="token builtin">error</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> info <span class="token operator">:=</span> theTC <span class="token punctuation">.</span> <span class="token function">info</span> <span class="token punctuation">(</span> typ <span class="token punctuation">)</span> <span class="token keyword">return</span> info <span class="token punctuation">.</span> writer <span class="token punctuation">,</span> info <span class="token punctuation">.</span> writerErr <span class="token punctuation">}</span> |
Họ sử dụng cấu trúc typeCache
để lưu trữ trình ghi của loại Go. Chi tiết hơn bạn có thể vào typecache.go
để xem.
1 2 3 4 5 6 7 8 | <span class="token keyword">type</span> typeCache <span class="token keyword">struct</span> <span class="token punctuation">{</span> cur atomic <span class="token punctuation">.</span> Value <span class="token comment">// This lock synchronizes writers.</span> mu sync <span class="token punctuation">.</span> Mutex next <span class="token keyword">map</span> <span class="token punctuation">[</span> typekey <span class="token punctuation">]</span> <span class="token operator">*</span> typeinfo <span class="token punctuation">}</span> |
Chúng ta có:
cur
: để lưu trữ trình ghi bản đồ. Giá trị củacur
làmap[typekey]*typeinfo
mu
: sử dụngsync.Mutex
để khóa trình ghi đồng bộ hóanext
: bản đồ lưu trữ bản đồ tiếp theo
go-ethereum
sử dụng bản đồ để lưu trữ hàm ghi dựa trên loại Go. Bản đồ này sẽ lưu trữ trong mem khi geth
đang chạy.
Đi qua nhiều chức năng hơn bên trong theTC.info(typ)
, chúng ta sẽ thấy chức năng chính xác định chức năng của người viết dựa trên typ
là gì
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | <span class="token comment">// encode.go</span> <span class="token keyword">func</span> <span class="token function">makeWriter</span> <span class="token punctuation">(</span> typ reflect <span class="token punctuation">.</span> Type <span class="token punctuation">,</span> ts rlpstruct <span class="token punctuation">.</span> Tags <span class="token punctuation">)</span> <span class="token punctuation">(</span> writer <span class="token punctuation">,</span> <span class="token builtin">error</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> kind <span class="token operator">:=</span> typ <span class="token punctuation">.</span> <span class="token function">Kind</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token keyword">switch</span> <span class="token punctuation">{</span> <span class="token keyword">case</span> typ <span class="token operator">==</span> rawValueType <span class="token punctuation">:</span> <span class="token keyword">return</span> writeRawValue <span class="token punctuation">,</span> <span class="token boolean">nil</span> <span class="token keyword">case</span> typ <span class="token punctuation">.</span> <span class="token function">AssignableTo</span> <span class="token punctuation">(</span> reflect <span class="token punctuation">.</span> <span class="token function">PtrTo</span> <span class="token punctuation">(</span> bigInt <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">:</span> <span class="token keyword">return</span> writeBigIntPtr <span class="token punctuation">,</span> <span class="token boolean">nil</span> <span class="token keyword">case</span> typ <span class="token punctuation">.</span> <span class="token function">AssignableTo</span> <span class="token punctuation">(</span> bigInt <span class="token punctuation">)</span> <span class="token punctuation">:</span> <span class="token keyword">return</span> writeBigIntNoPtr <span class="token punctuation">,</span> <span class="token boolean">nil</span> <span class="token keyword">case</span> typ <span class="token operator">==</span> reflect <span class="token punctuation">.</span> <span class="token function">PtrTo</span> <span class="token punctuation">(</span> u256Int <span class="token punctuation">)</span> <span class="token punctuation">:</span> <span class="token keyword">return</span> writeU256IntPtr <span class="token punctuation">,</span> <span class="token boolean">nil</span> <span class="token keyword">case</span> typ <span class="token operator">==</span> u256Int <span class="token punctuation">:</span> <span class="token keyword">return</span> writeU256IntNoPtr <span class="token punctuation">,</span> <span class="token boolean">nil</span> <span class="token keyword">case</span> kind <span class="token operator">==</span> reflect <span class="token punctuation">.</span> Ptr <span class="token punctuation">:</span> <span class="token keyword">return</span> <span class="token function">makePtrWriter</span> <span class="token punctuation">(</span> typ <span class="token punctuation">,</span> ts <span class="token punctuation">)</span> <span class="token keyword">case</span> reflect <span class="token punctuation">.</span> <span class="token function">PtrTo</span> <span class="token punctuation">(</span> typ <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">Implements</span> <span class="token punctuation">(</span> encoderInterface <span class="token punctuation">)</span> <span class="token punctuation">:</span> <span class="token keyword">return</span> <span class="token function">makeEncoderWriter</span> <span class="token punctuation">(</span> typ <span class="token punctuation">)</span> <span class="token punctuation">,</span> <span class="token boolean">nil</span> <span class="token keyword">case</span> <span class="token function">isUint</span> <span class="token punctuation">(</span> kind <span class="token punctuation">)</span> <span class="token punctuation">:</span> <span class="token keyword">return</span> writeUint <span class="token punctuation">,</span> <span class="token boolean">nil</span> <span class="token keyword">case</span> kind <span class="token operator">==</span> reflect <span class="token punctuation">.</span> Bool <span class="token punctuation">:</span> <span class="token keyword">return</span> writeBool <span class="token punctuation">,</span> <span class="token boolean">nil</span> <span class="token keyword">case</span> kind <span class="token operator">==</span> reflect <span class="token punctuation">.</span> String <span class="token punctuation">:</span> <span class="token keyword">return</span> writeString <span class="token punctuation">,</span> <span class="token boolean">nil</span> <span class="token keyword">case</span> kind <span class="token operator">==</span> reflect <span class="token punctuation">.</span> Slice <span class="token operator">&&</span> <span class="token function">isByte</span> <span class="token punctuation">(</span> typ <span class="token punctuation">.</span> <span class="token function">Elem</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">:</span> <span class="token keyword">return</span> writeBytes <span class="token punctuation">,</span> <span class="token boolean">nil</span> <span class="token keyword">case</span> kind <span class="token operator">==</span> reflect <span class="token punctuation">.</span> Array <span class="token operator">&&</span> <span class="token function">isByte</span> <span class="token punctuation">(</span> typ <span class="token punctuation">.</span> <span class="token function">Elem</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">:</span> <span class="token keyword">return</span> <span class="token function">makeByteArrayWriter</span> <span class="token punctuation">(</span> typ <span class="token punctuation">)</span> <span class="token punctuation">,</span> <span class="token boolean">nil</span> <span class="token keyword">case</span> kind <span class="token operator">==</span> reflect <span class="token punctuation">.</span> Slice <span class="token operator">||</span> kind <span class="token operator">==</span> reflect <span class="token punctuation">.</span> Array <span class="token punctuation">:</span> <span class="token keyword">return</span> <span class="token function">makeSliceWriter</span> <span class="token punctuation">(</span> typ <span class="token punctuation">,</span> ts <span class="token punctuation">)</span> <span class="token keyword">case</span> kind <span class="token operator">==</span> reflect <span class="token punctuation">.</span> Struct <span class="token punctuation">:</span> <span class="token keyword">return</span> <span class="token function">makeStructWriter</span> <span class="token punctuation">(</span> typ <span class="token punctuation">)</span> <span class="token keyword">case</span> kind <span class="token operator">==</span> reflect <span class="token punctuation">.</span> Interface <span class="token punctuation">:</span> <span class="token keyword">return</span> writeInterface <span class="token punctuation">,</span> <span class="token boolean">nil</span> <span class="token keyword">default</span> <span class="token punctuation">:</span> <span class="token keyword">return</span> <span class="token boolean">nil</span> <span class="token punctuation">,</span> fmt <span class="token punctuation">.</span> <span class="token function">Errorf</span> <span class="token punctuation">(</span> <span class="token string">"rlp: type %v is not RLP-serializable"</span> <span class="token punctuation">,</span> typ <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
Tóm lại, chúng tôi có một số điểm:
go-ethereum
sử dụng bản đồ trong mem để lưu trữ chức năng mã hóa người ghi dựa trên loại Gogo-etherem
sử dụng cấu trúcencBuffer
để lưu trữ dữ liệu nhị phân được mã hóa bởiwriter
- Sau khi chúng tôi mã hóa đầu vào, họ sẽ ghi lại đầu ra vào
w
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | <span class="token comment">// writeTo writes the encoder output to w.</span> <span class="token keyword">func</span> <span class="token punctuation">(</span> buf <span class="token operator">*</span> encBuffer <span class="token punctuation">)</span> <span class="token function">writeTo</span> <span class="token punctuation">(</span> w io <span class="token punctuation">.</span> Writer <span class="token punctuation">)</span> <span class="token punctuation">(</span> err <span class="token builtin">error</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> strpos <span class="token operator">:=</span> <span class="token number">0</span> <span class="token keyword">for</span> <span class="token boolean">_</span> <span class="token punctuation">,</span> head <span class="token operator">:=</span> <span class="token keyword">range</span> buf <span class="token punctuation">.</span> lheads <span class="token punctuation">{</span> <span class="token comment">// write string data before header</span> <span class="token keyword">if</span> head <span class="token punctuation">.</span> offset <span class="token operator">-</span> strpos <span class="token operator">></span> <span class="token number">0</span> <span class="token punctuation">{</span> n <span class="token punctuation">,</span> err <span class="token operator">:=</span> w <span class="token punctuation">.</span> <span class="token function">Write</span> <span class="token punctuation">(</span> buf <span class="token punctuation">.</span> str <span class="token punctuation">[</span> strpos <span class="token punctuation">:</span> head <span class="token punctuation">.</span> offset <span class="token punctuation">]</span> <span class="token punctuation">)</span> strpos <span class="token operator">+=</span> n <span class="token keyword">if</span> err <span class="token operator">!=</span> <span class="token boolean">nil</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> err <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token comment">// write the header</span> enc <span class="token operator">:=</span> head <span class="token punctuation">.</span> <span class="token function">encode</span> <span class="token punctuation">(</span> buf <span class="token punctuation">.</span> sizebuf <span class="token punctuation">[</span> <span class="token punctuation">:</span> <span class="token punctuation">]</span> <span class="token punctuation">)</span> <span class="token keyword">if</span> <span class="token boolean">_</span> <span class="token punctuation">,</span> err <span class="token operator">=</span> w <span class="token punctuation">.</span> <span class="token function">Write</span> <span class="token punctuation">(</span> enc <span class="token punctuation">)</span> <span class="token punctuation">;</span> err <span class="token operator">!=</span> <span class="token boolean">nil</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> err <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">if</span> strpos <span class="token operator"><</span> <span class="token function">len</span> <span class="token punctuation">(</span> buf <span class="token punctuation">.</span> str <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// write string data after the last list header</span> <span class="token boolean">_</span> <span class="token punctuation">,</span> err <span class="token operator">=</span> w <span class="token punctuation">.</span> <span class="token function">Write</span> <span class="token punctuation">(</span> buf <span class="token punctuation">.</span> str <span class="token punctuation">[</span> strpos <span class="token punctuation">:</span> <span class="token punctuation">]</span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> err <span class="token punctuation">}</span> |
Gói RLP do Go viết rất khó hiểu hơn bản
Typescript
. Nhưng họ thêm nhiều kỹ thuật hơn vào đó để giảm phân bổ và giảm thời gian mã hóa bằng cách sử dụng bản đồ trong bộ nhớ để lưu trữ chức năng mã hóa củawriter
dựa trên loại Go.
giải mã.go
Chúng tôi có cách tiếp cận tương tự như encode
với giao diện Decode, nhưng bây giờ, đầu vào của giải mã là Stream
chứ không phải io.Writer
như mã hóa.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | <span class="token comment">// ByteReader must be implemented by any input reader for a Stream. It</span> <span class="token comment">// is implemented by e.g. bufio.Reader and bytes.Reader.</span> <span class="token keyword">type</span> ByteReader <span class="token keyword">interface</span> <span class="token punctuation">{</span> io <span class="token punctuation">.</span> Reader io <span class="token punctuation">.</span> ByteReader <span class="token punctuation">}</span> <span class="token comment">// Stream can be used for piecemeal decoding of an input stream. This</span> <span class="token comment">// is useful if the input is very large or if the decoding rules for a</span> <span class="token comment">// type depend on the input structure. Stream does not keep an</span> <span class="token comment">// internal buffer. After decoding a value, the input reader will be</span> <span class="token comment">// positioned just before the type information for the next value.</span> <span class="token comment">//</span> <span class="token comment">// When decoding a list and the input position reaches the declared</span> <span class="token comment">// length of the list, all operations will return error EOL.</span> <span class="token comment">// The end of the list must be acknowledged using ListEnd to continue</span> <span class="token comment">// reading the enclosing list.</span> <span class="token comment">//</span> <span class="token comment">// Stream is not safe for concurrent use.</span> <span class="token keyword">type</span> Stream <span class="token keyword">struct</span> <span class="token punctuation">{</span> r ByteReader remaining <span class="token builtin">uint64</span> <span class="token comment">// number of bytes remaining to be read from r</span> size <span class="token builtin">uint64</span> <span class="token comment">// size of value ahead</span> kinderr <span class="token builtin">error</span> <span class="token comment">// error from last readKind</span> stack <span class="token punctuation">[</span> <span class="token punctuation">]</span> <span class="token builtin">uint64</span> <span class="token comment">// list sizes</span> uintbuf <span class="token punctuation">[</span> <span class="token number">32</span> <span class="token punctuation">]</span> <span class="token builtin">byte</span> <span class="token comment">// auxiliary buffer for integer decoding</span> kind Kind <span class="token comment">// kind of value ahead</span> byteval <span class="token builtin">byte</span> <span class="token comment">// value of single byte in type tag</span> limited <span class="token builtin">bool</span> <span class="token comment">// true if input limit is in effect</span> <span class="token punctuation">}</span> |
Bởi vì decode
hoạt động theo cùng một cách tiếp cận với encode
. Tôi không đi sâu ngay bây giờ. Nhưng tôi có một số điểm:
decode
sử dụng bản đồ được lưu trong bộ nhớ cache- Chúng tôi có chức năng
decoder
dựa trên độ dài và phần tử đầu tiên của đầu vào
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | <span class="token keyword">func</span> <span class="token function">makeDecoder</span> <span class="token punctuation">(</span> typ reflect <span class="token punctuation">.</span> Type <span class="token punctuation">,</span> tags rlpstruct <span class="token punctuation">.</span> Tags <span class="token punctuation">)</span> <span class="token punctuation">(</span> dec decoder <span class="token punctuation">,</span> err <span class="token builtin">error</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> kind <span class="token operator">:=</span> typ <span class="token punctuation">.</span> <span class="token function">Kind</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token keyword">switch</span> <span class="token punctuation">{</span> <span class="token keyword">case</span> typ <span class="token operator">==</span> rawValueType <span class="token punctuation">:</span> <span class="token keyword">return</span> decodeRawValue <span class="token punctuation">,</span> <span class="token boolean">nil</span> <span class="token keyword">case</span> typ <span class="token punctuation">.</span> <span class="token function">AssignableTo</span> <span class="token punctuation">(</span> reflect <span class="token punctuation">.</span> <span class="token function">PtrTo</span> <span class="token punctuation">(</span> bigInt <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">:</span> <span class="token keyword">return</span> decodeBigInt <span class="token punctuation">,</span> <span class="token boolean">nil</span> <span class="token keyword">case</span> typ <span class="token punctuation">.</span> <span class="token function">AssignableTo</span> <span class="token punctuation">(</span> bigInt <span class="token punctuation">)</span> <span class="token punctuation">:</span> <span class="token keyword">return</span> decodeBigIntNoPtr <span class="token punctuation">,</span> <span class="token boolean">nil</span> <span class="token keyword">case</span> typ <span class="token operator">==</span> reflect <span class="token punctuation">.</span> <span class="token function">PtrTo</span> <span class="token punctuation">(</span> u256Int <span class="token punctuation">)</span> <span class="token punctuation">:</span> <span class="token keyword">return</span> decodeU256 <span class="token punctuation">,</span> <span class="token boolean">nil</span> <span class="token keyword">case</span> typ <span class="token operator">==</span> u256Int <span class="token punctuation">:</span> <span class="token keyword">return</span> decodeU256NoPtr <span class="token punctuation">,</span> <span class="token boolean">nil</span> <span class="token keyword">case</span> kind <span class="token operator">==</span> reflect <span class="token punctuation">.</span> Ptr <span class="token punctuation">:</span> <span class="token keyword">return</span> <span class="token function">makePtrDecoder</span> <span class="token punctuation">(</span> typ <span class="token punctuation">,</span> tags <span class="token punctuation">)</span> <span class="token keyword">case</span> reflect <span class="token punctuation">.</span> <span class="token function">PtrTo</span> <span class="token punctuation">(</span> typ <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">Implements</span> <span class="token punctuation">(</span> decoderInterface <span class="token punctuation">)</span> <span class="token punctuation">:</span> <span class="token keyword">return</span> decodeDecoder <span class="token punctuation">,</span> <span class="token boolean">nil</span> <span class="token keyword">case</span> <span class="token function">isUint</span> <span class="token punctuation">(</span> kind <span class="token punctuation">)</span> <span class="token punctuation">:</span> <span class="token keyword">return</span> decodeUint <span class="token punctuation">,</span> <span class="token boolean">nil</span> <span class="token keyword">case</span> kind <span class="token operator">==</span> reflect <span class="token punctuation">.</span> Bool <span class="token punctuation">:</span> <span class="token keyword">return</span> decodeBool <span class="token punctuation">,</span> <span class="token boolean">nil</span> <span class="token keyword">case</span> kind <span class="token operator">==</span> reflect <span class="token punctuation">.</span> String <span class="token punctuation">:</span> <span class="token keyword">return</span> decodeString <span class="token punctuation">,</span> <span class="token boolean">nil</span> <span class="token keyword">case</span> kind <span class="token operator">==</span> reflect <span class="token punctuation">.</span> Slice <span class="token operator">||</span> kind <span class="token operator">==</span> reflect <span class="token punctuation">.</span> Array <span class="token punctuation">:</span> <span class="token keyword">return</span> <span class="token function">makeListDecoder</span> <span class="token punctuation">(</span> typ <span class="token punctuation">,</span> tags <span class="token punctuation">)</span> <span class="token keyword">case</span> kind <span class="token operator">==</span> reflect <span class="token punctuation">.</span> Struct <span class="token punctuation">:</span> <span class="token keyword">return</span> <span class="token function">makeStructDecoder</span> <span class="token punctuation">(</span> typ <span class="token punctuation">)</span> <span class="token keyword">case</span> kind <span class="token operator">==</span> reflect <span class="token punctuation">.</span> Interface <span class="token punctuation">:</span> <span class="token keyword">return</span> decodeInterface <span class="token punctuation">,</span> <span class="token boolean">nil</span> <span class="token keyword">default</span> <span class="token punctuation">:</span> <span class="token keyword">return</span> <span class="token boolean">nil</span> <span class="token punctuation">,</span> fmt <span class="token punctuation">.</span> <span class="token function">Errorf</span> <span class="token punctuation">(</span> <span class="token string">"rlp: type %v is not RLP-serializable"</span> <span class="token punctuation">,</span> typ <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
Bản tóm tắt
RLP là một thuật toán được sử dụng trong Ethereum để mã hóa/giải mã dữ liệu nhị phân có cấu trúc tùy ý. RLP được đề cập trong Yellow Paper
nhưng lúc đầu rất khó hiểu đầy đủ.
Thẩm quyền giải quyết
- Go-ethereum được viết bởi Go
- phân tích Go-ethereum
- giấy vàng
- Tài liệu
- Trung bình
- Go-ethereum monorepo được viết bởi JS
Ghi chú
Một trong những bài viết public đầu tiên mình viết bằng tiếng Anh nên có lẽ bài viết này có sai sót gì về tiếng Anh hay kiến thức, các bạn thấy có gì cứ góp ý cho mình nhé. Yêu tất cả các bạn.