以太坊:底層序列化編碼方式RLP
轉載請註明出處:https://www.cnblogs.com/zhizaixingzou/p/10122380.html
目錄
1. RLP:以太坊底層序列化編碼方式
1.1. 簡介
https://segmentfault.com/a/1190000011763339
https://github.com/ethereum/wiki/wiki/RLP
RLP,Recursive Length Prefix,遞迴長度字首。它是以太坊底層序列化採用的編碼方式。RLP主要用於以太坊中資料的網路傳輸和持久化儲存。它的設計目的就是編碼任意巢狀的二進位制陣列或列表。
序列化物件的編碼方式有很多種,為什麼還要重複發明輪子呢?常見的JSON編碼,有個明顯的缺點,就是引入了太多冗餘資訊,編碼結果比較大。而其他的編碼方式,要麼不為以太坊設計者所知,要麼看起來都不如自己設計的編碼來的合適。
1.2. 原理
RLP編碼只對3種資料型別編碼:
型別1:值在[0,127]之間的單個位元組。使用下面的規則1。
型別2:位元組陣列(元素數可為0)。使用下面的規則2和規則3。
型別3:列表(列表是以陣列或列表為元素的陣列,元素數不可為0)。使用下面的規則4和規則5。
RLP編碼的編碼規則:
規則1:對於值在[0,127]之間的單個位元組,其編碼是位元組自身。
9->9
規則2:對於長度len<=55的位元組陣列,其編碼是128+len,緊接著位元組陣列自身。
[9]->[129,9] len=1 129=128+len
規則3:對於長度len>55的位元組陣列,其編碼是183+len編碼的長度,緊接著len的編碼,緊接著位元組陣列自身。len的大小不能超過8位元組能表示的值。
[97,97,...,97]->[185,4,0,97,97,...,97] len=1024 [4,0]=len的編碼(編碼涉及多位元組的數值表示時,使用大端模式) 185=183+[4,0]的長度
規則4:如果列表長度len<=55,其編碼是192+len,緊接著各子列表的編碼。列表長度是指子列表編碼後的長度之和。這是遞迴定義。
[[97,98,99],[100,101,102]]->[200,131,97,98,99,131,100,101,102] 131=128+3 200=192+4+4
規則5:如果列表長度len>55,其編碼是247+len的編碼的長度,緊接著len的編碼,緊接著各子列表的編碼。len的大小不能超過8位元組能表示的值。這是遞迴定義。
["The length of this sentence is more than 55 bytes, ", "I know it because I pre-designed it"]->[248 88 179 84 104 101 32 108 101 110 103 116 104 32 111 102 32 116 104 105 115 32 115 101 110 116 101 110 99 101 32 105 115 32 109 111 114 101 32 116 104 97 110 32 53 53 32 98 121 116 101 115 44 32 163 73 32 107 110 111 119 32 105 116 32 98 101 99 97 117 115 101 32 73 32 112 114 101 45 100 101 115 105 103 110 101 100 32 105 116] 179 = 128 + 51 163 = 128 + 35 88 = 51+35 + 2 248 = 247 +1
從編碼規則可以看出:編碼的結果是一個位元組陣列。編碼結果的長度不能超過8位元組能表示的值,也就是2的64次方,2ZB的資料,這是很大的資料了。
各種程式設計語言在實現RLP編碼時,需要首先將物件轉換為3種資料型別中的一種,具體怎麼轉換則自己定義。
RLP編碼的解碼規則是編碼規則的逆運算。首先根據編碼結果的第一個位元組f,執行以下的規則判斷:
判斷1:如果f∈[0,127],那麼反序列化後是一個位元組,就是f。
判斷2:如果f∈[128,183],那麼反序列化後是一個長度len<=55的位元組陣列,位元組陣列的長度為len=f-128。
判斷3:如果f∈[184,192],那麼反序列化後是一個長度len>55的位元組陣列,位元組陣列長度的編碼的長度lenOfLen=f-183,然後從第二個位元組開始讀取lenOfLen個位元組,按照大端模式轉換成整數len,len即為位元組陣列的長度。
判斷4:如果f∈[193,247],那麼反序列化後是一個編碼後長度len<=55的列表,列表長度為len=f-192。遞迴使用判斷1~4進行解碼。
判斷5:如果f∈[247,255],那麼反序列化後是編碼後長度len>55的列表,列表長度的編碼的長度lenOfLen=f-247,然後從第二個位元組開始讀取lenOfLen個位元組,按照大端模式轉換成整數len,len即為子列表總長度。然後遞迴使用判斷1~5進行解碼。
可以看到,接收到編碼的資料後,1)就能根據第一個位元組推斷出資料的型別,2)並且最多再讀幾個位元組就能知道資料的大小,這就解釋了“長度字首”的意義。加之解碼時使用了遞迴演算法,因而此編碼方式就叫遞迴長度字首編碼。
1.3. 原始碼實現
原始碼見:org.ethereum.util.RLP
原始碼實現與原理描述有兩點稍有不同:
1)實際上不只提供了3種資料型別,但其他型別都轉換成這3種後才編碼,且每種型別都對應了編碼和解密方法。也就是說,收方知道收到的資料是用什麼方法編碼的,它會呼叫對應的方法解密。
2)實際使用的規則可能稍有出入,也更瑣碎些。