Özyinelemeli uzunluk ön eki (RLP) serileştirmesi
Son düzenleme: @Berke37(opens in a new tab), Invalid DateTime
Özyinelemeli Uzunluk Ön Eki (RLP), Ethereum'un yürütüm istemcilerinde yaygın şekilde kullanılan bir serileştirme yoludur. RLP, düğümler arasında veri transferini, alan açısından verimli bir biçimde standartlaştırır. RLP'nin amacı, rastgele iç içe geçmiş ikili veri dizilerini kodlamaktır. RLP, Ethereum'un yürütüm katmanında nesneleri serileştirmek için kullanılan temel kodlama yöntemidir. RLP'nin tek amacı yapıyı kodlamaktır; spesifik veri çeşitlerinin kodlanması (örn. dizeler, değişkenler) daha üst düzey protokollere bırakılır, ancak pozitif RLP tam sayıları başında sıfır olmadan yüksek son haneli ikili biçimde temsil edilmelidir (böylece tam sayı değeri sıfır, boş bayt dizisine eşdeğer olmuş olur). Seri durumundan çıkarılmış başında sıfır olan pozitif tam sayılar geçersiz kabul edilir. Dize uzunluğunun tam sayı gösteriminin yanı sıra yükteki tam sayılar da bu şekilde kodlanmalıdır.
Daha fazla bilgi için bkz. Ethereum sarı kağıdı (Appendix B)(opens in a new tab).
Bir sözlüğü kodlamak için RLP kullanmanın iki kabul edilmiş yolu:
- sözlüksel bir sırada anahtarlarla
[[k1,v1],[k2,v2]...]
kullanmak - Ethereum'un yaptığı gibi kodlama için üst düzey Patricia Ağacını kullanmak
Tanım
RLP kodlama fonksiyonu bir öğeyi içine alır. Bir öğe aşağıdaki gibi tanımlanır:
- bir dize (yani bayt dizisi), bir öğedir
- öğelerin listesi, bir öğedir
Örneğin, aşağıdakilerin tümü öğelerdir:
- boş dize;
- "cat" kelimesini içeren dize;
- herhangi bir sayıda dize içeren bir liste;
["cat", ["puppy", "cow"], "horse", [[]], "pig", [""], "sheep"]
gibi daha karmaşık veri yapıları.
Bu sayfanın geri kalanı bağlamında "dize", "belirli sayıda ikili veri baytı" anlamına gelir; hiçbir özel kodlama kullanılmaz ve dizelerin içeriği hakkında hiçbir bilgiye sahip olunduğu ima edilmez.
RLP kodlaması şu şekilde tanımlanır:
- Değer aralığı
[0x00, 0x7f]
(ondalık[0, 127]
) olan tek bir bayt söz konusu olduğunda, bu bayt kendisinin RLP kodlamasıdır. - Aksi takdirde, eğer bir dize 0-55 bayt uzunluğunda ise RLP kodlaması, (0x80, ondalık olarak 128) değerine sahip bir tek bayt ile dizenin uzunluğu ve onu takip eden dizeden oluşur. Bu nedenle, ilk baytın aralığı
[0x80, 0xb7]
(ondalık olarak[128, 183]
)'dir. - Eğer bir dize 55 bayttan daha uzunsa, RLP kodlaması bir tane 0xb7 (ondalık 183) değerine sahip tek bir bayt ile başlar. Ardından, dizenin uzunluğunun ikili formundaki uzunluğu bayt cinsinden eklenir, ardından dizenin uzunluğu ve en sonunda dizenin kendisi eklenir. Örneğin, 1024 bayt uzunluğundaki bir dize
\xb9\x04\x00
(ondalık185, 4, 0
) olarak kodlanır ve ardından dize gelir. Burada, ilk bayt olarak0xb9
(183 + 2 = 185) ve ardından gerçek dizenin uzunluğunu belirten 2 bayt0x0400
(ondalık olarak 1024) gelir. Bu nedenle, ilk baytın aralığı[0xb8, 0xbf]
(ondalık olarak[184, 191]
) şeklindedir. - Bir listenin toplam yükü (yani tüm öğelerinin RLP kodlanmış toplam uzunluğu) 0-55 bayt arasında ise RLP kodlaması, 0xc0 değerine sahip tek bir bayt ile listenin uzunluğu ve ardından öğelerin RLP kodlamalarının birleştirilmiş halinden oluşur. Bu nedenle, ilk baytın aralığı
[0xc0, 0xf7]
(ondalık olarak[192, 247]
) şeklindedir. - Bir listenin toplam yükü 55 bayttan daha uzunsa RLP kodlaması, 0xf7 değerine sahip tek bir bayt ile ikili biçimde yükün uzunluğunun bayt cinsinden uzunluğu ve ardından yükün uzunluğu ve onun da ardından öğelerin RLP kodlamalarının birleştirilmiş halinden oluşur. Bu nedenle, ilk baytın aralığı
[0xb8, 0xbf]
(ondalık olarak[248, 255]
) şeklindedir.
Kodda, bu:
1def rlp_encode(input):2 if isinstance(input,str):3 if len(input) == 1 and ord(input) < 0x80:4 return input5 return encode_length(len(input), 0x80) + input6 elif isinstance(input, list):7 output = ''8 for item in input:9 output += rlp_encode(item)10 return encode_length(len(output), 0xc0) + output1112def encode_length(L, offset):13 if L < 56:14 return chr(L + offset)15 elif L < 256**8:16 BL = to_binary(L)17 return chr(len(BL) + offset + 55) + BL18 raise Exception("input too long")1920def to_binary(x):21 if x == 0:22 return ''23 return to_binary(int(x / 256)) + chr(x % 256)Tümünü gösterKopyala
Örnekler
- "dog" dizesi = = [ 0x83, 'd', 'o', 'g' ]
- [ "cat", "dog" ] listesi =
[ 0xc8, 0x83, 'c', 'a', 't', 0x83, 'd', 'o', 'g' ]
- boş dize ('null') =
[ 0x80 ]
- boş liste =
[ 0xc0 ]
- tam sayı 0 =
[ 0x80 ]
- kodlanmış tam sayı 0 ('\x00') =
[ 0x0f ]
- kodlanmış tam sayı 15 ('\x0f') =
[ 0x0f ]
- kodlanmış tam sayı 1024 ('\x04') =
[ 0x82, 0x04, 0x00 ]
- ağacın küme teorisi ile gösterimi(opens in a new tab),
[ [], [[]], [ [], [[]] ] ] = [ 0xc7, 0xc0, 0xc1, 0xc0, 0xc3, 0xc0, 0xc1, 0xc0 ]
- "Lorem ipsum dolor sit amet, consectetur adipisicing elit" dizesi =
[ 0xb8, 0x38, 'L', 'o', 'r', 'e', 'm', ' ', ... , 'e', 'l', 'ı', 't' ]
RLP kodunu çözme
RLP'nin kodlaması kurallarına ve sürecine göre RLP kod çözme girdisi, bir ikili veri dizisi olarak kabul edilir. RLP kod çözme süreci aşağıdaki gibidir:
giriş verilerinin ilk baytına (yani önek) ve veri tipinin kodunun çözülmesine göre, gerçek verilerin uzunluğu ve kayma;
verinin türüne ve kaymasına göre verilerin kodunu uygun şekilde çözün;
girdinin geri kalanını çözmeye devam edin;
Bunların yanında veri tiplerini ve kaymaları kodlamanın kuralları şu şekildedir:
i̇lk baytın (yani, önek) aralığı [0x00, 0x7f] ise, veri bir dizedir ve dize, doğrudan ilk baytın kendisidir;
i̇lk baytın aralığı [0x80, 0xb7] ise veri bir dizedir ve dizenin uzunluğu ilk bayttan 0x80 çıkarıldığında elde edilen değere eşit uzunluktadır;
veri, ilk baytın aralığı [0xf8, 0xff] ise ve uzunluğu ilk bayt eksi 0xf7'ye eşit olan listenin toplam yükü ilk baytı takip ediyorsa ve hepsini kodlamalarının birleşimi bir listedir. listenin öğeleri, listenin toplam yükünü takip eder;
ilk bayt aralığı [0xc0, 0xf7] ise veriler bir listedir ve toplam yükün ilk bayta eşit olduğu listenin tüm öğelerinin RLP kodlamalarının sıralanması eksi 0xc0 ilk baytı takip eder;
ilk baytın aralığı [0xf8, 0xff] ise veri bir listedir ve uzunluğu ilk bayt eksi 0xf7'ye eşit olan listenin toplam yükü ilk baytı takip eder ve tümünün RLP kodlamalarının birleşimi listenin öğeleri listenin toplam yükünü takip eder;
Kodda, bu:
1def rlp_decode(input):2 if len(input) == 0:3 return4 output = ''5 (offset, dataLen, type) = decode_length(input)6 if type is str:7 output = instantiate_str(substr(input, offset, dataLen))8 elif type is list:9 output = instantiate_list(substr(input, offset, dataLen))10 output += rlp_decode(substr(input, offset + dataLen))11 return output1213def decode_length(input):14 length = len(input)15 if length == 0:16 raise Exception("input is null")17 prefix = ord(input[0])18 if prefix <= 0x7f:19 return (0, 1, str)20 elif prefix <= 0xb7 and length > prefix - 0x80:21 strLen = prefix - 0x8022 return (1, strLen, str)23 elif prefix <= 0xbf and length > prefix - 0xb7 and length > prefix - 0xb7 + to_integer(substr(input, 1, prefix - 0xb7)):24 lenOfStrLen = prefix - 0xb725 strLen = to_integer(substr(input, 1, lenOfStrLen))26 return (1 + lenOfStrLen, strLen, str)27 elif prefix <= 0xf7 and length > prefix - 0xc0:28 listLen = prefix - 0xc0;29 return (1, listLen, list)30 elif prefix <= 0xff and length > prefix - 0xf7 and length > prefix - 0xf7 + to_integer(substr(input, 1, prefix - 0xf7)):31 lenOfListLen = prefix - 0xf732 listLen = to_integer(substr(input, 1, lenOfListLen))33 return (1 + lenOfListLen, listLen, list)34 raise Exception("input does not conform to RLP encoding form")3536def to_integer(b):37 length = len(b)38 if length == 0:39 raise Exception("input is null")40 elif length == 1:41 return ord(b[0])42 return ord(substr(b, -1)) + to_integer(substr(b, 0, -1)) * 256Tümünü gösterKopyala
Daha fazla okuma
- Ethereum'da RLP(opens in a new tab)
- Yakın planda Ethereum: RLP(opens in a new tab)
- Coglio, A. (2020). Ethereum ACL2'deki Özyinelemeli Uzunluk Ön Eki. arXiv ön baskı arXiv:2009.13769.(opens in a new tab)