Ana içeriğe geç
Change page

Özyinelemeli uzunluk ön eki (RLP) serileştirmesi

Son düzenleme: @Berke37(opens in a new tab), 23 Kasım 2023

Ö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ık 185, 4, 0) olarak kodlanır ve ardından dize gelir. Burada, ilk bayt olarak 0xb9 (183 + 2 = 185) ve ardından gerçek dizenin uzunluğunu belirten 2 bayt 0x0400 (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 input
5 return encode_length(len(input), 0x80) + input
6 elif isinstance(input, list):
7 output = ''
8 for item in input:
9 output += rlp_encode(item)
10 return encode_length(len(output), 0xc0) + output
11
12def 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) + BL
18 raise Exception("input too long")
19
20def to_binary(x):
21 if x == 0:
22 return ''
23 return to_binary(int(x / 256)) + chr(x % 256)
Tümünü göster
Kopyala

Ö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:

  1. giriş verilerinin ilk baytına (yani önek) ve veri tipinin kodunun çözülmesine göre, gerçek verilerin uzunluğu ve kayma;

  2. verinin türüne ve kaymasına göre verilerin kodunu uygun şekilde çözün;

  3. girdinin geri kalanını çözmeye devam edin;

Bunların yanında veri tiplerini ve kaymaları kodlamanın kuralları şu şekildedir:

  1. i̇lk baytın (yani, önek) aralığı [0x00, 0x7f] ise, veri bir dizedir ve dize, doğrudan ilk baytın kendisidir;

  2. 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;

  3. 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;

  4. 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;

  5. 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 return
4 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 output
12
13def 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 - 0x80
22 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 - 0xb7
25 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 - 0xf7
32 listLen = to_integer(substr(input, 1, lenOfListLen))
33 return (1 + lenOfListLen, listLen, list)
34 raise Exception("input does not conform to RLP encoding form")
35
36def 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)) * 256
Tümünü göster
Kopyala

Daha fazla okuma

Bu makale yararlı oldu mu?