Açık Test: Ethereum'da Gizlilik ve Ölçeklenebilirlik İçin Bir Çözüm

Blokcheyn insan yaşamının birçok alanını iyileştirmeyi vaat eden yenilikçi bir teknolojidir. Gerçek süreçleri ve ürünleri dijital alana aktarır, finansal işlemlerin hızını ve güvenilirliğini sağlar, maliyetlerini azaltır ve ayrıca merkezi olmayan ağlarda akıllı sözleşmeleri kullanarak modern DAPP uygulamaları oluşturmanıza olanak tanır.

Blockchain'in birçok faydası ve çeşitli uygulamaları göz önüne alındığında, bu gelecek vaat eden teknolojinin henüz her sektöre girmemiş olması şaşırtıcı görünebilir. Sorun, modern merkezi olmayan blok zincirlerinin ölçeklenebilirlikten yoksun olmasıdır. Ethereum saniyede yaklaşık 20 işlem gerçekleştiriyor ve bu da günümüzün dinamik işletmelerinin ihtiyaçlarını karşılamaya yetmiyor. Aynı zamanda blockchain teknolojisini kullanan şirketler, hacklenmeye ve ağ arızalarına karşı yüksek derecede koruma sağlaması nedeniyle Ethereum'u terk etmekte tereddüt ediyor.

Geliştirme ekibi, blok zincirinde merkeziyetsizliği, güvenliği ve ölçeklenebilirliği sağlamak ve böylece Ölçeklenebilirlik Üçlemini çözmek için Opporty akıllı bir sözleşme ve durumunu periyodik olarak kök zincire (Ethereum) aktaran Node.js tabanlı özel bir ağdan oluşan bir yan zincir olan Plasma Cash'i yarattı.

Açık Test: Ethereum'da Gizlilik ve Ölçeklenebilirlik İçin Bir Çözüm

Plasma Cash'teki temel süreçler

1. Kullanıcı akıllı sözleşme fonksiyonunu "para yatırma" olarak adlandırır ve Plasma Cash tokenına yatırmak istediği ETH miktarını bu fonksiyona aktarır. Akıllı sözleşme işlevi bir token oluşturur ve bununla ilgili bir etkinlik üretir.

2. Akıllı sözleşme etkinliklerine abone olan Plazma Nakit düğümleri, depozito oluşturmayla ilgili bir etkinlik alır ve havuza token oluşturmayla ilgili bir işlem ekler.

3. Periyodik olarak, özel Plazma Nakit düğümleri havuzdaki tüm işlemleri (1 milyona kadar) alır ve bunlardan bir blok oluşturur, Merkle ağacını ve buna göre hash'ı hesaplar. Bu blok doğrulama için diğer düğümlere gönderilir. Düğümler, Merkle karmasının geçerli olup olmadığını ve işlemlerin geçerli olup olmadığını (örneğin, tokeni gönderenin tokenın sahibi olup olmadığını) kontrol eder. Bloğu doğruladıktan sonra düğüm, blok numarasını ve Merkle karmasını kenar zincirine kaydeden akıllı sözleşmenin "submitBlock" işlevini çağırır. Akıllı sözleşme, bir bloğun başarıyla eklendiğini gösteren bir olay üretir. İşlemler havuzdan kaldırılır.

4. Blok gönderme olayını alan düğümler, bloğa eklenen işlemleri uygulamaya başlar.

5. Bir noktada tokenın sahibi (veya sahibi olmayan) onu Plasma Cash'ten çekmek ister. Bunu yapmak için, tokenın sahibi olduğunu doğrulayan token üzerindeki son 2 işlem hakkındaki bilgileri bu fonksiyona aktararak 'startExit' fonksiyonunu çağırır. Akıllı sözleşme, Merkle karma değerini kullanarak bloklardaki işlemlerin varlığını kontrol eder ve iki hafta içinde gerçekleşecek olan para çekme işlemi için tokeni gönderir.

6. Token çekme işlemi ihlallerle gerçekleşmişse (token, para çekme prosedürü başladıktan sonra harcanmışsa veya token, çekilmeden önce zaten başka birine aitmişse), tokenın sahibi iki hafta içinde çekilmeyi reddedebilir.

Açık Test: Ethereum'da Gizlilik ve Ölçeklenebilirlik İçin Bir Çözüm

Gizlilik iki şekilde sağlanır

1. Kök zincir, alt zincirde oluşturulan ve iletilen işlemler hakkında hiçbir şey bilmez. ETH'yi Plasma Cash'e kimin yatırdığı ve çektiğine ilişkin bilgiler halka açık olmaya devam ediyor.

2. Alt zincir, zk-SNARK'ları kullanarak anonim işlemlere izin verir.

Teknoloji yığını

  • NodeJS
  • Redis
  • Etherium
  • Toprak

Test

Plasma Cash'i geliştirirken sistemin hızını test ettik ve aşağıdaki sonuçları elde ettik:

  • havuza saniyede 35'e kadar işlem eklenir;
  • Bir blokta 1'e kadar işlem saklanabilir.

Testler aşağıdaki 3 sunucuda gerçekleştirildi:

1. Intel Core i7-6700 Dört Çekirdekli Skylake dahil. NVMe SSD – 512 GB, 64 GB DDR4 RAM
3 doğrulayıcı Plazma Nakit düğümü yükseltildi.

2. AMD Ryzen 7 1700X Sekiz Çekirdekli “Summit Ridge” (Zen), SATA SSD – 500 GB, 64 GB DDR4 RAM
Ropsten test ağı ETH düğümü yükseltildi.
3 doğrulayıcı Plazma Nakit düğümü yükseltildi.

3. Intel Core i9-9900K Sekiz Çekirdekli dahil. NVMe SSD – 1 TB, 64 GB DDR4 RAM
1 Plazma Nakit gönderme düğümü yükseltildi.
3 doğrulayıcı Plazma Nakit düğümü yükseltildi.
Plasma Cash ağına işlem eklemek için test başlatıldı.

Toplam: Özel bir ağda 10 Plazma Nakit düğümü.

Test 1

Blok başına 1 milyon işlem sınırı bulunmaktadır. Dolayısıyla 1 milyon işlem 2 bloğa düşüyor (çünkü sistem işlemlerin bir kısmını alıp gönderilirken göndermeyi başarıyor).


Başlangıç ​​durumu: son blok #7; Veritabanında 1 milyon işlem ve token saklanıyor.

00:00 — işlem oluşturma komut dosyasının başlangıcı
01:37 - 1 milyon işlem oluşturuldu ve düğüme gönderim başladı
01:46 — Gönderim düğümü havuzdan 240 bin işlem aldı ve 8 numaralı bloğu oluşturdu. Ayrıca havuza 320 saniyede 10 bin işlemin eklendiğini görüyoruz.
01:58 — 8 numaralı blok imzalandı ve doğrulama için gönderildi
02:03 — 8 numaralı blok doğrulanır ve akıllı sözleşmenin "submitBlock" işlevi Merkle karma değeri ve blok numarasıyla çağrılır
02:10 — 1 saniyede 32 milyon işlem gönderen demo komut dosyası çalışmayı tamamladı
02:33 - düğümler, 8 numaralı bloğun kök zincire eklendiği ve 240 bin işlem gerçekleştirmeye başladığı bilgisini almaya başladı
02:40 - Zaten 240. blokta bulunan 8 bin işlem havuzdan kaldırıldı
02:56 — gönderim düğümü havuzdan kalan 760 bin işlemi aldı ve Merkle hash'ini hesaplamaya ve 9 numaralı bloğu imzalamaya başladı
03:20 - tüm düğümler 1 milyon 240 bin işlem ve token içeriyor
03:35 — 9 numaralı blok imzalanır ve doğrulama için diğer düğümlere gönderilir
03:41 - ağ hatası oluştu
04:40 — blok #9'un doğrulanmasının beklenmesi zaman aşımına uğradı
04:54 — gönderim düğümü havuzdan kalan 760 bin işlemi aldı ve Merkle hash'ini hesaplamaya ve 9 numaralı bloğu imzalamaya başladı
05:32 — 9 numaralı blok imzalanır ve doğrulama için diğer düğümlere gönderilir
05:53 — 9 numaralı blok doğrulandı ve kök zincire gönderildi
06:17 - düğümler, 9 numaralı bloğun kök zincire eklendiği ve 760 bin işlem gerçekleştirmeye başladığı bilgisini almaya başladı
06:47 — havuz 9. bloktaki işlemlerden temizlendi
09:06 - tüm düğümler 2 milyon işlem ve token içeriyor

Test 2

Blok başına 350k sınırı vardır. Sonuç olarak 3 bloğumuz var.


Başlangıç ​​durumu: son blok #9; Veritabanında 2 milyon işlem ve token saklanıyor

00:00 — işlem oluşturma komut dosyası zaten başlatıldı
00:44 - 1 milyon işlem oluşturuldu ve düğüme gönderim başladı
00:56 — Gönderim düğümü havuzdan 320 bin işlem aldı ve 10 numaralı bloğu oluşturdu. Ayrıca havuza 320 saniyede 10 bin işlemin eklendiğini görüyoruz.
01:12 — 10 numaralı blok imzalanır ve doğrulama için diğer düğümlere gönderilir
01:18 — 1 saniyede 34 milyon işlem gönderen demo komut dosyası çalışmayı tamamladı
01:20 — blok #10 doğrulanır ve kök zincire gönderilir
01:51 - tüm düğümler kök zincirden 10 numaralı bloğun eklendiği ve 320 bin işlemi uygulamaya başladığı bilgisini aldı
02:01 - havuz, 320 numaralı bloğa eklenen 10 bin işlem için temizlendi
02:15 — gönderim düğümü havuzdan 350 bin işlem aldı ve 11 numaralı bloğu oluşturdu
02:34 — 11 numaralı blok imzalanır ve doğrulama için diğer düğümlere gönderilir
02:51 — blok #11 doğrulanır ve kök zincire gönderilir
02:55 — son düğüm 10. bloktan işlemleri tamamladı
10:59 — 9 numaralı bloğun gönderilmesiyle ilgili işlem kök zincirde çok uzun sürdü, ancak tamamlandı ve tüm düğümler bu konuda bilgi aldı ve 350 bin işlem gerçekleştirmeye başladı
11:05 - havuz, 320 numaralı bloğa eklenen 11 bin işlem için temizlendi
12:10 - tüm düğümler 1 milyon 670 bin işlem ve token içeriyor
12:17 — gönderim düğümü havuzdan 330 bin işlem aldı ve 12 numaralı bloğu oluşturdu
12:32 — 12 numaralı blok imzalanır ve doğrulama için diğer düğümlere gönderilir
12:39 — blok #12 doğrulanır ve kök zincire gönderilir
13:44 - tüm düğümler kök zincirden 12 numaralı bloğun eklendiği ve 330 bin işlemi uygulamaya başladığı bilgisini aldı
14:50 - tüm düğümler 2 milyon işlem ve token içeriyor

Test 3

Birinci ve ikinci sunucularda, bir doğrulama düğümünün yerini gönderen bir düğüm aldı.


Başlangıç ​​durumu: son blok #84; Veritabanına kaydedilen 0 işlem ve jeton

00:00 — Her biri 3 milyon işlem oluşturup gönderen 1 komut dosyası başlatıldı
01:38 — 1 milyon işlem oluşturuldu ve 3 numaralı düğüme gönderim başladı
01:50 — 3 numaralı gönderim düğümü havuzdan 330 bin işlem aldı ve 85 numaralı bloğu (f21) oluşturdu. Ayrıca havuza 350 saniyede 10 bin işlemin eklendiğini görüyoruz.
01:53 — 1 milyon işlem oluşturuldu ve 1 numaralı düğüme gönderim başladı
01:50 — 3 numaralı gönderim düğümü havuzdan 330 bin işlem aldı ve 85 numaralı bloğu (f21) oluşturdu. Ayrıca havuza 350 saniyede 10 bin işlemin eklendiğini görüyoruz.
02:01 — 1 numaralı gönderim düğümü havuzdan 250 bin işlem aldı ve 85 numaralı bloğu (65e) oluşturdu
02:06 — blok #85 (f21) imzalanır ve doğrulama için diğer düğümlere gönderilir
02:08 — 3 saniyede 1 milyon işlem gönderen 30 numaralı sunucunun demo komut dosyası çalışmayı tamamladı
02:14 — blok #85 (f21) doğrulanır ve kök zincire gönderilir
02:19 — 85 numaralı blok (65e) imzalanır ve doğrulama için diğer düğümlere gönderilir
02:22 — 1 milyon işlem oluşturuldu ve 2 numaralı düğüme gönderim başladı
02:27 — blok #85 (65e) doğrulandı ve kök zincire gönderildi
02:29 — gönderim düğümü #2, havuzdan 111855 işlem aldı ve #85 (256) bloğunu oluşturdu.
02:36 — blok #85 (256) imzalanır ve doğrulama için diğer düğümlere gönderilir
02:36 — 1 saniyede 1 milyon işlem gönderen 42.5 numaralı sunucunun demo komut dosyası çalışmayı tamamladı
02:38 — blok #85 (256) doğrulanır ve kök zincire gönderilir
03:08 — 2 saniyede 1 milyon işlem gönderen sunucu #47 komut dosyası çalışmayı tamamladı
03:38 - #85 (f21), #86(65e), #87(256) bloklarının eklendiği kök zincirden bilgi alan tüm düğümler, 330 bin, 250 bin, 111855 işlemi uygulamaya başladı
03:49 - #330 (f250), #111855(85e), #21(86) bloklarına eklenen 65 bin, 87 bin, 256 işlemde havuz temizlendi
03:59 — 1 numaralı gönderim düğümü havuzdan 888145 işlem aldı ve 88 numaralı bloğu (214) oluşturdu, 2 numaralı gönderim düğümü havuzdan 750 bin işlem aldı ve 88 numaralı bloğu (50a) oluşturdu, 3 numaralı gönderim düğümü havuzdan 670 bin işlem aldı havuz ve form bloğu #88 (d3b)
04:44 — 88 numaralı blok (d3b) imzalanır ve doğrulama için diğer düğümlere gönderilir
04:58 — blok #88 (214) imzalanır ve doğrulama için diğer düğümlere gönderilir
05:11 — blok #88 (50a) imzalanır ve doğrulama için diğer düğümlere gönderilir
05:11 — blok #85 (d3b) doğrulanır ve kök zincire gönderilir
05:36 — blok #85 (214) doğrulanır ve kök zincire gönderilir
05:43 - #88 (d3b), #89(214) bloklarını kök zincirden alan tüm düğümler eklendi ve 670 bin, 750 bin işlemi uygulamaya başlıyor
06:50 — iletişim hatası nedeniyle blok #85 (50a) doğrulanamadı
06:55 — gönderim düğümü #2, havuzdan 888145 işlem aldı ve #90 (50a) bloğunu oluşturdu
08:14 — blok #90 (50a) imzalanır ve doğrulama için diğer düğümlere gönderilir
09:04 — blok #90 (50a) doğrulanır ve kök zincire gönderilir
11:23 - tüm düğümler kök zincirden blok #90'ın (50a) eklendiği bilgisini aldı ve 888145 işlemi uygulamaya başladı. Aynı zamanda, 3 numaralı sunucu, 88 (d3b), 89(214) numaralı bloklardan işlemleri zaten uygulamıştır.
12:11 - tüm havuzlar boş
13:41 — 3 numaralı sunucunun tüm düğümleri 3 milyon işlem ve jeton içeriyor
14:35 — 1 numaralı sunucunun tüm düğümleri 3 milyon işlem ve jeton içeriyor
19:24 — 2 numaralı sunucunun tüm düğümleri 3 milyon işlem ve jeton içeriyor

engeller

Plasma Cash'in geliştirilmesi sırasında yavaş yavaş çözdüğümüz ve çözmekte olduğumuz aşağıdaki sorunlarla karşılaştık:

1. Çeşitli sistem işlevlerinin etkileşiminde çatışma. Örneğin, havuza işlem ekleme işlevi, blokların gönderilmesi ve doğrulanması işini engelledi ve bunun tersi de hızın düşmesine neden oldu.

2. Veri aktarım maliyetlerini en aza indirirken çok sayıda işlemin nasıl gönderileceği hemen belli değildi.

3. Yüksek sonuçlara ulaşmak için verilerin nasıl ve nerede saklanacağı belli değildi.

4. 1 milyon işlem içeren bir bloğun boyutu yaklaşık 100 MB yer kapladığından, düğümler arasında bir ağın nasıl organize edileceği net değildi.

5. Tek iş parçacıklı modda çalışmak, uzun hesaplamalar gerçekleştiğinde (örneğin, Merkle ağacı oluşturmak ve karmasını hesaplamak) düğümler arasındaki bağlantıyı keser.

Bütün bunlarla nasıl başa çıktık?

Plasma Cash düğümünün ilk versiyonu, her şeyi aynı anda yapabilen bir tür birleştirmeydi: işlemleri kabul etmek, blokları göndermek ve doğrulamak ve verilere erişim için bir API sağlamak. NodeJS doğal olarak tek iş parçacıklı olduğundan, ağır Merkle ağacı hesaplama işlevi, işlem ekleme işlevini engelledi. Bu sorunu çözmek için iki seçenek gördük:

1. Her biri belirli işlevleri gerçekleştiren birkaç NodeJS işlemi başlatın.

2. Worker_threads kullanın ve kodun bir kısmının yürütülmesini iş parçacıklarına taşıyın.

Sonuç olarak, her iki seçeneği de aynı anda kullandık: mantıksal olarak bir düğümü ayrı ayrı çalışabilen ancak aynı anda eşzamanlı olarak çalışabilen 3 parçaya böldük.

1. Havuza işlemleri kabul eden ve bloklar oluşturan gönderim düğümü.

2. Düğümlerin geçerliliğini kontrol eden bir doğrulama düğümü.

3. API düğümü - verilere erişim için bir API sağlar.

Bu durumda, her düğüme cli kullanarak bir unix soketi aracılığıyla bağlanabilirsiniz.

Merkle ağacının hesaplanması gibi ağır işlemleri ayrı bir konuya taşıdık.

Böylece tüm Plazma Nakit fonksiyonlarının aynı anda ve hatasız normal çalışmasını sağladık.

Sistem işlevsel hale geldikten sonra hızı test etmeye başladık ve ne yazık ki tatmin edici olmayan sonuçlar aldık: saniyede 5 işlem ve blok başına 000'e kadar işlem. Neyin yanlış uygulandığını bulmam gerekiyordu.

Başlangıç ​​olarak sistemin en yüksek kapasitesini bulmak için Plasma Cash ile iletişim mekanizmasını test etmeye başladık. Daha önce Plasma Cash düğümünün unix soket arayüzü sağladığını yazmıştık. Başlangıçta metin tabanlıydı. json nesneleri "JSON.parse()" ve "JSON.stringify()" kullanılarak gönderildi.

```json
{
  "action": "sendTransaction",
  "payload":{
    "prevHash": "0x8a88cc4217745fd0b4eb161f6923235da10593be66b841d47da86b9cd95d93e0",
    "prevBlock": 41,
    "tokenId": "57570139642005649136210751546585740989890521125187435281313126554130572876445",
    "newOwner": "0x200eabe5b26e547446ae5821622892291632d4f4",
    "type": "pay",
    "data": "",
    "signature": "0xd1107d0c6df15e01e168e631a386363c72206cb75b233f8f3cf883134854967e1cd9b3306cc5c0ce58f0a7397ae9b2487501b56695fe3a3c90ec0f61c7ea4a721c"
  }
}
```

Bu tür nesnelerin aktarım hızını ölçtük ve saniyede ~130k bulduk. Json ile çalışmak için standart işlevleri değiştirmeye çalıştık, ancak performans iyileşmedi. V8 motorunun bu işlemler için iyi optimize edilmesi gerekir.

Sınıflar aracılığıyla işlemler, jetonlar ve bloklarla çalıştık. Bu tür sınıflar oluştururken performans 2 kat düştü, bu da OOP'nin bize uygun olmadığını gösteriyor. Her şeyi tamamen işlevsel bir yaklaşımla yeniden yazmak zorunda kaldım.

Veritabanına kayıt

Başlangıçta Redis, veri depolama için gereksinimlerimizi karşılayan en verimli çözümlerden biri olarak seçildi: anahtar-değer depolama, karma tablolarla çalışma, kümeler. Redis-benchmark'ı başlattık ve 80 ardışık düzen modunda saniyede ~1 bin işlem elde ettik.

Yüksek performans için Redis'i daha hassas bir şekilde ayarladık:

  • Unix soket bağlantısı kuruldu.
  • Durumu diske kaydetmeyi devre dışı bıraktık (güvenilirlik için bir kopya ayarlayabilir ve ayrı bir Redis'te diske kaydedebilirsiniz).

Redis'te havuz bir karma tablosudur çünkü tüm işlemleri tek bir sorguda alabilmemiz ve işlemleri tek tek silebilmemiz gerekir. Normal bir liste kullanmayı denedik, ancak listenin tamamını boşaltırken daha yavaş oluyor.

Redis kütüphaneleri, standart NodeJS kullanıldığında saniyede 18 bin işlem performansına ulaştı. Hız 9 kez düştü.

Karşılaştırmalı değerlendirme bize olasılıkların açıkça 5 kat daha fazla olduğunu gösterdiğinden, optimizasyona başladık. Kütüphaneyi ioredis olarak değiştirdik ve saniyede 25k performans elde ettik. `hset` komutunu kullanarak işlemleri tek tek ekledik. Bu yüzden Redis'te çok sayıda sorgu oluşturuyorduk. İşlemleri gruplar halinde birleştirmek ve tek bir 'hmset' komutuyla göndermek fikri ortaya çıktı. Sonuç saniyede 32 bindir.

Aşağıda açıklayacağımız çeşitli nedenlerden dolayı verilerle "Buffer" kullanarak çalışıyoruz ve görünen o ki, yazmadan önce onu metne ("buffer.toString('hex')") dönüştürürseniz, ek veriler elde edebilirsiniz. verim. Böylece hız saniyede 35k’ya çıkarıldı. Şu anda daha fazla optimizasyonu askıya almaya karar verdik.

İkili protokole geçmek zorunda kaldık çünkü:

1. Sistem sıklıkla karmaları, imzaları vb. hesaplar ve bunun için 'Tampon'daki verilere ihtiyacı vardır.

2. Hizmetler arasında gönderildiğinde ikili veriler metinden daha hafiftir. Örneğin 1 milyon işlem içeren bir blok gönderilirken metindeki veriler 300 megabayttan fazla yer kaplayabiliyor.

3. Verilerin sürekli dönüştürülmesi performansı etkiler.

Bu nedenle, harika "ikili veri" kütüphanesi temelinde geliştirilen, verileri depolamak ve iletmek için kendi ikili protokolümüzü temel aldık.

Sonuç olarak aşağıdaki veri yapılarını elde ettik:

—İşlem

  ```json
  {
    prevHash: BD.types.buffer(20),
    prevBlock: BD.types.uint24le,
    tokenId: BD.types.string(null),
    type: BD.types.uint8,
    newOwner: BD.types.buffer(20),
    dataLength: BD.types.uint24le,
    data: BD.types.buffer(({current}) => current.dataLength),
    signature: BD.types.buffer(65),
    hash: BD.types.buffer(32),
    blockNumber: BD.types.uint24le,
    timestamp: BD.types.uint48le,
  }
  ```

- Jeton

  ```json
  {
    id: BD.types.string(null),
    owner: BD.types.buffer(20),
    block: BD.types.uint24le,
    amount: BD.types.string(null),
  }
  ```

-Engellemek

  ```json
  {
    number: BD.types.uint24le,
    merkleRootHash: BD.types.buffer(32),
    signature: BD.types.buffer(65),
    countTx: BD.types.uint24le,
    transactions: BD.types.array(Transaction.Protocol, ({current}) => current.countTx),
    timestamp: BD.types.uint48le,
  }
  ```

Her zamanki gibi `BD.encode(block, Protokol).slice();` ve `BD.decode(buffer, Protokol)` komutlarıyla verileri Redis'e kaydetmek veya başka bir düğüme iletmek ve almak için `Buffer'a dönüştürürüz. veri geri.

Ayrıca hizmetler arasında veri aktarımı için 2 ikili protokolümüz var:

— Unix soketi aracılığıyla Plazma Düğümü ile etkileşim protokolü

  ```json
  {
    type: BD.types.uint8,
    messageId: BD.types.uint24le,
    error: BD.types.uint8,
    length: BD.types.uint24le,
    payload: BD.types.buffer(({node}) => node.length)
  }
  ```

burada:

  • "tür" — gerçekleştirilecek eylem, örneğin, 1 — sendTransaction, 2 — getTransaction;
  • 'yük' — uygun fonksiyona iletilmesi gereken veriler;
  • 'mesaj kimliği' — Yanıtın tanımlanabilmesi için mesaj kimliği.

— Düğümler arasındaki etkileşim protokolü

  ```json
  {
    code: BD.types.uint8,
    versionProtocol: BD.types.uint24le,
    seq: BD.types.uint8,
    countChunk: BD.types.uint24le,
    chunkNumber: BD.types.uint24le,
    length: BD.types.uint24le,
    payload: BD.types.buffer(({node}) => node.length)
  }
  ```

burada:

  • "kod" — mesaj kodu, örneğin 6 — PREPARE_NEW_BLOCK, 7 — BLOCK_VALID, 8 — BLOCK_COMMIT;
  • 'sürümProtokolü' — protokol sürümü, çünkü farklı sürümlere sahip düğümler ağda yükseltilebilir ve farklı şekilde çalışabilirler;
  • 'sıra' — mesaj tanımlayıcı;
  • 'SaymaChunk' и 'yığınNumara' büyük mesajları bölmek için gerekli;
  • 'uzunluk' и 'yük' uzunluk ve verinin kendisi.

Verileri önceden yazdığımız için son sistem Ethereum'un "rlp" kütüphanesinden çok daha hızlıdır. İleride yapmayı planladığımız akıllı sözleşmeyi sonuçlandırmak gerektiğinden ne yazık ki henüz reddedemedik.

Eğer hıza ulaşmayı başarabilseydik 35 000 Saniyede işlem yapabilmemiz için bunları en uygun sürede işlememiz de gerekiyor. Yaklaşık blok oluşturma süresi 30 saniye sürdüğü için bloğa dahil etmemiz gerekiyor +1 000 000 daha fazla göndermek anlamına gelen işlemler 100 MB veri.

Başlangıçta, düğümler arasında iletişim kurmak için "ethereumjs-devp2p" kütüphanesini kullandık, ancak bu kadar çok veriyi işleyemedi. Sonuç olarak `ws` kütüphanesini kullandık ve ikili verinin websocket üzerinden gönderilmesini yapılandırdık. Elbette büyük veri paketlerini gönderirken de sorunlarla karşılaştık ama bunları parçalara ayırdık ve artık bu sorunlar ortadan kalktı.

Ayrıca bir Merkle ağacı oluşturmak ve hash'i hesaplamak +1 000 000 işlemler hakkında gerektirir 10 saniyelik sürekli hesaplama. Bu süre zarfında tüm düğümlerle bağlantı kopmayı başarır. Bu hesaplamanın ayrı bir konuya taşınmasına karar verildi.

Sonuç:

Aslında bulgularımız yeni değil ama bazı nedenlerden dolayı birçok uzman geliştirme aşamasında bunları unutuyor.

  • Nesneye Dayalı Programlama yerine İşlevsel Programlamayı kullanmak üretkenliği artırır.
  • Monolit, üretken bir NodeJS sistemi için hizmet mimarisinden daha kötüdür.
  • Yoğun hesaplamalar için "worker_threads" kullanımı, özellikle giriş/çıkış işlemleriyle uğraşırken sistemin yanıt verme hızını artırır.
  • unix soketi http isteklerinden daha kararlı ve daha hızlıdır.
  • Büyük verileri ağ üzerinden hızlı bir şekilde aktarmanız gerekiyorsa, websockets kullanmak ve ikili verileri parçalara bölünmüş, ulaşmazlarsa iletilebilecek ve ardından tek bir mesajda birleştirilebilecek şekilde göndermek daha iyidir.

Sizi ziyarete davet ediyoruz GitHub proje: https://github.com/opporty-com/Plasma-Cash/tree/new-version

Makalenin ortak yazarı Alexander Naşivan, kıdemli geliştirici Akıllı Çözüm A.Ş..

Kaynak: habr.com

Yorum ekle