Ana içeriğe geç
Change page

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

Son düzenleme: @Berke37(opens in a new tab), 8 Mayıs 2024

Ö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 ana amacı, yapıyı kodlamaktır; RLP, pozitif tamsayılar hariç olmak üzere belirli veri tiplerinin (örneğin dizeler, yüzer veriler) kodlanmasını daha yüksek düzeyli protokollere devreder. Pozitif tamsayılar, başlarında sıfır olmadan big-endian ikili biçiminde gösterilmelidir (böylece sıfır tamsayı değeri boş bayt dizisine eşdeğer olur). Başında sıfır bulunan seri duruma getirilmiş pozitif tamsayılar, RLP kullanan herhangi bir üst düzey protokol tarafından geçersiz olarak değerlendirilmelidir.

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
  • bir pozitif tamsayı 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ı.
  • 100 sayısı

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 (minimum olmayan pozitif tamsayılara karşın kuralın gerektirdiği durumlar hariç).

RLP kodlaması şu şekilde tanımlanır:

  • Pozitif bir tamsayı için big-endian yorumu tam sayı olan en kısa bayt dizisine dönüştürülür ve ardından aşağıdaki kurallar uyarınca bir dize olarak kodlanı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 dize 2^64 bayt uzunluğunda veya daha uzunsa kodlanamayabilir.
  • 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 yükün 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

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. verilerin türüne ve kaymasına göre, pozitif tamsayılar için minimum kodlama kuralına uyarak, 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

  • Patricia merkle dijital ağacı

Bu makale yararlı oldu mu?