跳至主要內容
Change page

遞迴長度前綴 (RLP) 序列化

遞迴長度前綴 (RLP) 序列化廣泛用於以太坊的執行用戶端中。RLP 以節省空間的格式標準化了節點之間的資料傳輸。RLP 的目的是對任意嵌套的二進位資料陣列進行編碼,且 RLP 是以太坊執行層中用於序列化物件的主要編碼方法。RLP 的主要目的是對結構進行編碼;除了正整數之外,RLP 將特定資料類型(例如字串、浮點數)的編碼委託給高階協定。正整數必須以沒有前導零的大端序二進位形式表示(因此使整數值零等同於空位元組陣列)。任何使用 RLP 的高階協定都必須將帶有前導零的反序列化正整數視為無效。

更多資訊請見以太坊黃皮書(附錄 B) (opens in a new tab)

若要使用 RLP 對字典進行編碼,建議的兩種規範形式為:

  • 使用 [[k1,v1],[k2,v2]...] 並按字典順序排列鍵值
  • 以太坊一樣使用更高階的帕特里夏樹 (Patricia Tree) 編碼

定義

RLP 編碼函式接收一個項目 (item)。項目的定義如下:

  • 字串(即位元組陣列)是一個項目
  • 項目列表是一個項目
  • 正整數是一個項目

例如,以下所有都是項目:

  • 空字串;
  • 包含單字 "cat" 的字串;
  • 包含任意數量字串的列表;
  • 以及更複雜的資料結構,例如 ["cat", ["puppy", "cow"], "horse", [[]], "pig", [""], "sheep"]
  • 數字 100

請注意,在本頁其餘部分的上下文中,「字串」指的是「一定數量的二進位資料位元組」;不使用任何特殊編碼,也不暗示對字串內容有任何了解(除非反對非最小正整數的規則有所要求)。

RLP 編碼定義如下:

  • 對於正整數,它會被轉換為大端序解釋為該整數的最短位元組陣列,然後根據以下規則編碼為字串。
  • 對於值在 [0x00, 0x7f](十進位 [0, 127])範圍內的單一位元組,該位元組就是其本身的 RLP 編碼。
  • 否則,如果字串長度為 0-55 個位元組,則 RLP 編碼由一個值為 0x80(十進位 128)加上字串長度的單一位元組組成,後面接著該字串。因此,第一個位元組的範圍是 [0x80, 0xb7](十進位 [128, 183])。
  • 如果字串長度超過 55 個位元組,則 RLP 編碼由一個值為 0xb7(十進位 183)加上字串長度的二進位形式的位元組長度的單一位元組組成,後面接著字串的長度,再接著該字串。例如,一個 1024 位元組長的字串將被編碼為 \xb9\x04\x00(十進位 185, 4, 0),後面接著該字串。這裡,0xb9 (183 + 2 = 185) 作為第一個位元組,後面接著表示實際字串長度的 2 個位元組 0x0400(十進位 1024)。因此,第一個位元組的範圍是 [0xb8, 0xbf](十進位 [184, 191])。
  • 如果字串長度為 2^64 個位元組或更長,則可能無法進行編碼。
  • 如果列表的總有效負載(即其所有被 RLP 編碼的項目的組合長度)為 0-55 個位元組長,則 RLP 編碼由一個值為 0xc0 加上有效負載長度的單一位元組組成,後面接著項目 RLP 編碼的串聯。因此,第一個位元組的範圍是 [0xc0, 0xf7](十進位 [192, 247])。
  • 如果列表的總有效負載長度超過 55 個位元組,則 RLP 編碼由一個值為 0xf7 加上有效負載長度的二進位形式的位元組長度的單一位元組組成,後面接著有效負載的長度,再接著項目 RLP 編碼的串聯。因此,第一個位元組的範圍是 [0xf8, 0xff](十進位 [248, 255])。

簡而言之:

範圍位元組 1位元組 2...位元組 9位元組 10意義
0x00-0x7f0ppppppp單一位元組字串
0x80-0xb710nnnnnnpppppppp...短字串 (0-55 位元組)
0xb8-0xbf10111NNNnnnnnnnn...nnnnnnnn/pppppppppppppppp長字串,N+1 個位元組表示長度,然後是有效負載
0xc0-0xf711nnnnnnpppppppp...短列表 (0-55 位元組)
0xf8-0xff11111NNNnnnnnnnn...nnnnnnnn/pppppppppppppppp長列表,N+1 個位元組表示長度,然後是有效負載
  • p = 有效負載
  • n = 長度(有效負載位元組數)
  • N = 長度的長度偏移量(後面跟著 N+1 個 n 位元組)

在程式碼中,這表示為:

範例

  • 字串 "dog" = [ 0x83, 'd', 'o', 'g' ]
  • 列表 [ "cat", "dog" ] = [ 0xc8, 0x83, 'c', 'a', 't', 0x83, 'd', 'o', 'g' ]
  • 空字串 ('null') = [ 0x80 ]
  • 空列表 = [ 0xc0 ]
  • 整數 0 = [ 0x80 ]
  • 位元組 '\x00' = [ 0x00 ]
  • 位元組 '\x0f' = [ 0x0f ]
  • 位元組 '\x04\x00' = [ 0x82, 0x04, 0x00 ]
  • 數字 3 的集合論表示法 (opens in a new tab)[ [], [[]], [ [], [[]] ] ] = [ 0xc7, 0xc0, 0xc1, 0xc0, 0xc3, 0xc0, 0xc1, 0xc0 ]
  • 字串 "Lorem ipsum dolor sit amet, consectetur adipisicing elit" = [ 0xb8, 0x38, 'L', 'o', 'r', 'e', 'm', ' ', ... , 'e', 'l', 'i', 't' ]

RLP 解碼

根據 RLP 編碼的規則和過程,RLP 解碼的輸入被視為二進位資料陣列。RLP 解碼過程如下:

  1. 根據輸入資料的第一個位元組(即前綴)並解碼資料類型、實際資料的長度和偏移量;

  2. 根據資料的類型和偏移量,相應地解碼資料,並遵守正整數的最小編碼規則;

  3. 繼續解碼輸入的其餘部分;

其中,解碼資料類型和偏移量的規則如下:

  1. 如果第一個位元組(即前綴)的範圍是 [0x00, 0x7f],則資料為字串,且該字串正是第一個位元組本身;

  2. 如果第一個位元組的範圍是 [0x80, 0xb7],則資料為字串,且長度等於第一個位元組減去 0x80 的字串緊跟在第一個位元組之後;

  3. 如果第一個位元組的範圍是 [0xb8, 0xbf],則資料為字串,且以位元組為單位的長度等於第一個位元組減去 0xb7 的字串長度緊跟在第一個位元組之後,而字串緊跟在字串長度之後;

  4. 如果第一個位元組的範圍是 [0xc0, 0xf7],則資料為列表,且總有效負載等於第一個位元組減去 0xc0 的列表所有項目 RLP 編碼的串聯緊跟在第一個位元組之後;

  5. 如果第一個位元組的範圍是 [0xf8, 0xff],則資料為列表,且長度等於第一個位元組減去 0xf7 的列表總有效負載緊跟在第一個位元組之後,而列表所有項目 RLP 編碼的串聯緊跟在列表的總有效負載之後;

在程式碼中,這表示為:

延伸閱讀