Openbare test: een oplossing voor privacy en schaalbaarheid op Ethereum

Blockchain is een innovatieve technologie die belooft veel gebieden van het menselijk leven te verbeteren. Het brengt echte processen en producten over naar de digitale ruimte, zorgt voor snelheid en betrouwbaarheid van financiële transacties, verlaagt de kosten ervan en stelt u ook in staat moderne DAPP-applicaties te creëren met behulp van slimme contracten in gedecentraliseerde netwerken.

Gezien de vele voordelen en uiteenlopende toepassingen van blockchain lijkt het misschien verrassend dat deze veelbelovende technologie nog niet in elke sector zijn weg heeft gevonden. Het probleem is dat moderne gedecentraliseerde blockchains geen schaalbaarheid hebben. Ethereum verwerkt ongeveer 20 transacties per seconde, wat niet genoeg is om aan de behoeften van de hedendaagse dynamische bedrijven te voldoen. Tegelijkertijd aarzelen bedrijven die blockchain-technologie gebruiken om Ethereum te verlaten vanwege de hoge mate van bescherming tegen hacking en netwerkstoringen.

Om decentralisatie, veiligheid en schaalbaarheid in de blockchain te garanderen, en zo het Scalability Trilemma op te lossen, heeft het ontwikkelteam Opporty creëerde Plasma Cash, een dochterketen bestaande uit een slim contract en een particulier netwerk gebaseerd op Node.js, dat periodiek zijn status overdraagt ​​aan de rootketen (Ethereum).

Openbare test: een oplossing voor privacy en schaalbaarheid op Ethereum

Sleutelprocessen in Plasma Cash

1. De gebruiker noemt de slimme contractfunctie 'deposit' en geeft daarin het bedrag aan ETH door dat hij in het Plasma Cash-token wil storten. De slimme contractfunctie creëert een token en genereert er een gebeurtenis over.

2. Plasma Cash-knooppunten die zijn geabonneerd op slimme contractgebeurtenissen ontvangen een gebeurtenis over het maken van een storting en voegen een transactie over het maken van een token toe aan de pool.

3. Periodiek nemen speciale Plasma Cash-knooppunten alle transacties uit de pool (tot 1 miljoen) en vormen er een blok van, berekenen de Merkle-boom en dienovereenkomstig de hash. Dit blok wordt ter verificatie naar andere knooppunten verzonden. De knooppunten controleren of de Merkle-hash geldig is en of de transacties geldig zijn (bijvoorbeeld of de afzender van het token de eigenaar is). Na verificatie van het blok roept het knooppunt de ‘submitBlock’-functie van het slimme contract aan, waardoor het bloknummer en de Merkle-hash in de edge-keten worden opgeslagen. Het slimme contract genereert een gebeurtenis die de succesvolle toevoeging van een blok aangeeft. Transacties worden uit de pool verwijderd.

4. Knooppunten die de blokindieningsgebeurtenis ontvangen, beginnen de transacties toe te passen die aan het blok zijn toegevoegd.

5. Op een gegeven moment wil de eigenaar (of niet-eigenaar) van het token het uit Plasma Cash opnemen. Om dit te doen roept hij de functie `startExit` aan en geeft daarin informatie door over de laatste twee transacties op het token, die bevestigen dat hij de eigenaar van het token is. Het slimme contract controleert, met behulp van de Merkle-hash, de aanwezigheid van transacties in de blokken en verzendt het token voor opname, wat binnen twee weken zal gebeuren.

6. Als de tokenopname heeft plaatsgevonden met overtredingen (de token is uitgegeven nadat de opnameprocedure is begonnen of de token was al van iemand anders vóór de opname), kan de eigenaar van de token de opname binnen twee weken weerleggen.

Openbare test: een oplossing voor privacy en schaalbaarheid op Ethereum

Privacy wordt op twee manieren bereikt

1. De rootchain weet niets van de transacties die binnen de childchain worden gegenereerd en doorgestuurd. Informatie over wie ETH van Plasma Cash heeft gestort en opgenomen, blijft openbaar.

2. De onderliggende keten maakt anonieme transacties mogelijk met behulp van zk-SNARK's.

Technologie stapel

  • NodeJS
  • Redis
  • Etherium
  • soild

Testen

Tijdens de ontwikkeling van Plasma Cash hebben we de snelheid van het systeem getest en de volgende resultaten verkregen:

  • er worden maximaal 35 transacties per seconde aan de pool toegevoegd;
  • Er kunnen maximaal 1 transacties in een blok worden opgeslagen.

Er zijn tests uitgevoerd op de volgende 3 servers:

1. Intel Core i7-6700 Quad-Core Skylake incl. NVMe SSD – 512 GB, 64 GB DDR4 RAM
Er zijn 3 validerende Plasma Cash-knooppunten opgehaald.

2. AMD Ryzen 7 1700X Octa-Core “Summit Ridge” (Zen), SATA SSD – 500 GB, 64 GB DDR4 RAM
Het Ropsten-testnet ETH-knooppunt is verhoogd.
Er zijn 3 validerende Plasma Cash-knooppunten opgehaald.

3. Intel Core i9-9900K Octa-Core incl. NVMe SSD – 1 TB, 64 GB DDR4 RAM
1 Plasma Cash-indieningsknooppunt is verhoogd.
Er zijn 3 validerende Plasma Cash-knooppunten opgehaald.
Er is een test gelanceerd om transacties toe te voegen aan het Plasma Cash-netwerk.

Totaal: 10 Plasma Cash-knooppunten in een privénetwerk.

Proef 1

Er is een limiet van 1 miljoen transacties per blok. Daarom vallen 1 miljoen transacties in 2 blokken (aangezien het systeem erin slaagt een deel van de transacties op te nemen en in te dienen terwijl ze worden verzonden).


Beginstatus: laatste blok #7; In de database worden 1 miljoen transacties en tokens opgeslagen.

00:00 — start van het script voor het genereren van transacties
01:37 - Er zijn 1 miljoen transacties aangemaakt en het verzenden naar het knooppunt is begonnen
01:46 — Het verzendknooppunt heeft 240 transacties uit de pool en formulierenblok #8 gehaald. We zien ook dat er in 320 seconden 10 transacties aan de pool worden toegevoegd
01:58 — blok #8 is ondertekend en ter validatie verzonden
02:03 — blok #8 wordt gevalideerd en de `submitBlock`-functie van het slimme contract wordt aangeroepen met de Merkle-hash en het bloknummer
02:10 — het demoscript is klaar met werken en heeft in 1 seconden 32 miljoen transacties verzonden
02:33 - knooppunten begonnen informatie te ontvangen dat blok #8 aan de hoofdketen was toegevoegd en begonnen 240 transacties uit te voeren
02:40 - Er zijn 240 transacties uit de pool verwijderd, die zich al in blok #8 bevinden
02:56 – het verzendknooppunt nam de resterende 760 transacties uit de pool en begon de Merkle-hash en ondertekeningsblok #9 te berekenen
03:20 - alle knooppunten bevatten 1 miljoen 240k-transacties en tokens
03:35 – blok #9 wordt ondertekend en ter validatie naar andere knooppunten verzonden
03:41 - Er is een netwerkfout opgetreden
04:40 — wachten op validatie van blok #9 is verstreken
04:54 – het verzendknooppunt nam de resterende 760 transacties uit de pool en begon de Merkle-hash en ondertekeningsblok #9 te berekenen
05:32 – blok #9 wordt ondertekend en ter validatie naar andere knooppunten verzonden
05:53 — blok #9 wordt gevalideerd en naar de rootketen gestuurd
06:17 - knooppunten begonnen informatie te ontvangen dat blok #9 aan de hoofdketen was toegevoegd en begonnen 760 transacties uit te voeren
06:47 — de pool heeft geen transacties meer in blok #9
09:06 - alle knooppunten bevatten 2 miljoen transacties en tokens

Proef 2

Er is een limiet van 350k per blok. Als resultaat hebben we 3 blokken.


Beginstatus: laatste blok #9; In de database worden 2 miljoen transacties en tokens opgeslagen

00:00 — script voor het genereren van transacties is al gelanceerd
00:44 - Er zijn 1 miljoen transacties aangemaakt en het verzenden naar het knooppunt is begonnen
00:56 — Het verzendknooppunt heeft 320 transacties uit de pool en formulierenblok #10 gehaald. We zien ook dat er in 320 seconden 10 transacties aan de pool worden toegevoegd
01:12 — blok #10 wordt ondertekend en ter validatie naar andere knooppunten gestuurd
01:18 — het demoscript is klaar met werken en heeft in 1 seconden 34 miljoen transacties verzonden
01:20 — blok #10 wordt gevalideerd en naar de rootketen gestuurd
01:51 - alle knooppunten ontvingen informatie van de hoofdketen dat blok #10 was toegevoegd en begonnen 320k-transacties toe te passen
02:01 - de pool is vrijgegeven voor 320 transacties die zijn toegevoegd aan blok #10
02:15 – het verzendknooppunt heeft 350 transacties uit de pool en formulierenblok #11 gehaald
02:34 – blok #11 wordt ondertekend en ter validatie naar andere knooppunten gestuurd
02:51 — blok #11 wordt gevalideerd en naar de rootketen gestuurd
02:55 — het laatste knooppunt voltooide transacties uit blok #10
10:59 — de transactie met het indienen van blok #9 duurde erg lang in de rootchain, maar deze was voltooid en alle knooppunten ontvingen er informatie over en begonnen 350 transacties uit te voeren
11:05 - de pool is vrijgegeven voor 320 transacties die zijn toegevoegd aan blok #11
12:10 - alle knooppunten bevatten 1 miljoen 670k-transacties en tokens
12:17 – het verzendknooppunt heeft 330 transacties uit de pool en formulierenblok #12 gehaald
12:32 – blok #12 wordt ondertekend en ter validatie naar andere knooppunten gestuurd
12:39 — blok #12 wordt gevalideerd en naar de rootketen gestuurd
13:44 - alle knooppunten ontvingen informatie van de hoofdketen dat blok #12 was toegevoegd en begonnen 330 transacties toe te passen
14:50 - alle knooppunten bevatten 2 miljoen transacties en tokens

Proef 3

In de eerste en tweede server werd één validerend knooppunt vervangen door een indienend knooppunt.


Beginstatus: laatste blok #84; 0 transacties en tokens opgeslagen in de database

00:00 — Er zijn 3 scripts gelanceerd die elk 1 miljoen transacties genereren en verzenden
01:38 — Er werden 1 miljoen transacties aangemaakt en het verzenden naar knooppunt #3 begon
01:50 — Verzendknooppunt #3 nam 330 transacties uit de pool en formulierenblok #85 (f21). We zien ook dat er in 350 seconden 10 transacties aan de pool worden toegevoegd
01:53 — Er werden 1 miljoen transacties aangemaakt en het verzenden naar knooppunt #1 begon
01:50 — Verzendknooppunt #3 nam 330 transacties uit de pool en formulierenblok #85 (f21). We zien ook dat er in 350 seconden 10 transacties aan de pool worden toegevoegd
02:01 — knooppunt #1 heeft 250 transacties uit de pool en formulierenblok #85 (65e) gehaald
02:06 — blok #85 (f21) wordt ondertekend en ter validatie naar andere knooppunten verzonden
02:08 — demoscript van server #3, dat in 1 seconden 30 miljoen transacties verzond, werkt niet meer
02:14 — blok #85 (f21) wordt gevalideerd en naar de rootketen gestuurd
02:19 — blok #85 (65e) wordt ondertekend en ter validatie naar andere knooppunten verzonden
02:22 — Er werden 1 miljoen transacties aangemaakt en het verzenden naar knooppunt #2 begon
02:27 — blok #85 (65e) gevalideerd en naar de rootketen gestuurd
02:29 — knooppunt #2 heeft 111855 transacties uit de pool en formulierenblok #85 (256) overgenomen.
02:36 — blok #85 (256) wordt ondertekend en ter validatie naar andere knooppunten verzonden
02:36 — demoscript van server #1, dat in 1 seconden 42.5 miljoen transacties verzond, werkt niet meer
02:38 — blok #85 (256) wordt gevalideerd en naar de rootketen gestuurd
03:08 — Het server #2-script is klaar met werken en heeft in 1 seconden 47 miljoen transacties verzonden
03:38 - alle knooppunten ontvingen informatie van de hoofdketen die blokkeert #85 (f21), #86(65e), #87(256) werd toegevoegd en begon 330k, 250k, 111855 transacties toe te passen
03:49 - de pool werd vrijgemaakt bij 330k, 250k, 111855 transacties die werden toegevoegd aan blokken #85 (f21), #86(65e), #87(256)
03:59 — Verzendknooppunt #1 haalde 888145 transacties uit de pool en formulierenblok #88 (214), Verzendknooppunt #2 haalde 750 transacties uit de pool en formulierenblok #88 (50a), Verzendknooppunt #3 haalde 670 transacties uit de pool en formulierenblok #88 (d3b)
04:44 — blok #88 (d3b) wordt ondertekend en ter validatie naar andere knooppunten verzonden
04:58 — blok #88 (214) wordt ondertekend en ter validatie naar andere knooppunten verzonden
05:11 — blok #88 (50a) wordt ondertekend en ter validatie naar andere knooppunten verzonden
05:11 — blok #85 (d3b) wordt gevalideerd en naar de rootketen gestuurd
05:36 — blok #85 (214) wordt gevalideerd en naar de rootketen gestuurd
05:43 - alle knooppunten hebben informatie ontvangen van de hoofdketen die #88 (d3b) blokkeert, #89(214) is toegevoegd en begint 670k, 750k transacties toe te passen
06:50 — vanwege een communicatiefout is blok #85 (50a) niet gevalideerd
06:55 — knooppunt #2 heeft 888145 transacties uit de pool en formulierenblok #90 (50a) opgehaald
08:14 — blok #90 (50a) wordt ondertekend en ter validatie naar andere knooppunten verzonden
09:04 — blok #90 (50a) wordt gevalideerd en naar de rootketen gestuurd
11:23 - alle knooppunten ontvingen informatie van de hoofdketen dat blok #90 (50a) was toegevoegd en begonnen 888145-transacties toe te passen. Tegelijkertijd heeft server #3 al transacties uit blokken #88 (d3b), #89(214) toegepast
12:11 - alle zwembaden zijn leeg
13:41 — alle knooppunten van server #3 bevatten 3 miljoen transacties en tokens
14:35 — alle knooppunten van server #1 bevatten 3 miljoen transacties en tokens
19:24 — alle knooppunten van server #2 bevatten 3 miljoen transacties en tokens

obstakels

Tijdens de ontwikkeling van Plasma Cash zijn we de volgende problemen tegengekomen, die we geleidelijk hebben opgelost en aan het oplossen zijn:

1. Conflict in de interactie van verschillende systeemfuncties. De functie van het toevoegen van transacties aan de pool blokkeerde bijvoorbeeld het werk van het indienen en valideren van blokken, en omgekeerd, wat leidde tot een snelheidsdaling.

2. Het was niet meteen duidelijk hoe je een groot aantal transacties kon versturen en tegelijkertijd de kosten voor gegevensoverdracht tot een minimum kon beperken.

3. Het was niet duidelijk hoe en waar de gegevens moesten worden opgeslagen om hoge resultaten te behalen.

4. Het was niet duidelijk hoe je een netwerk tussen knooppunten moest organiseren, aangezien de grootte van een blok met 1 miljoen transacties ongeveer 100 MB in beslag neemt.

5. Als u in de single-threaded-modus werkt, wordt de verbinding tussen knooppunten verbroken wanneer er lange berekeningen plaatsvinden (bijvoorbeeld het bouwen van een Merkle-boom en het berekenen van de hash ervan).

Hoe zijn wij met dit alles omgegaan?

De eerste versie van het Plasma Cash-knooppunt was een soort combinatie die alles tegelijkertijd kon doen: transacties accepteren, blokken indienen en valideren, en een API bieden voor toegang tot gegevens. Omdat NodeJS native single-threaded is, blokkeerde de zware Merkle-boomberekeningsfunctie de functie voor het toevoegen van transacties. We zagen twee opties om dit probleem op te lossen:

1. Start verschillende NodeJS-processen, die elk specifieke functies uitvoeren.

2. Gebruik worker_threads en verplaats de uitvoering van een deel van de code naar threads.

Als gevolg hiervan hebben we beide opties tegelijkertijd gebruikt: we hebben één knooppunt logisch in 3 delen verdeeld die afzonderlijk, maar tegelijkertijd synchroon kunnen werken

1. Indieningsknooppunt, dat transacties in de pool accepteert en blokken creëert.

2. Een validerend knooppunt dat de geldigheid van knooppunten controleert.

3. API-knooppunt - biedt een API voor toegang tot gegevens.

In dit geval kunt u met elk knooppunt verbinding maken via een Unix-socket met behulp van cli.

We hebben zware bewerkingen, zoals het berekenen van de Merkle-boom, naar een aparte draad verplaatst.

We hebben dus een normale werking van alle Plasma Cash-functies tegelijkertijd en zonder fouten bereikt.

Toen het systeem eenmaal functioneerde, begonnen we de snelheid te testen en kregen we helaas onbevredigende resultaten: 5 transacties per seconde en tot 000 transacties per blok. Ik moest uitzoeken wat er verkeerd was geïmplementeerd.

Om te beginnen zijn we begonnen met het testen van het communicatiemechanisme met Plasma Cash om de maximale capaciteit van het systeem te achterhalen. We schreven eerder dat het Plasma Cash-knooppunt een Unix-socketinterface biedt. Aanvankelijk was het op tekst gebaseerd. json-objecten zijn verzonden met `JSON.parse()` en `JSON.stringify()`.

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

We hebben de overdrachtssnelheid van dergelijke objecten gemeten en vonden ~130k per seconde. We hebben geprobeerd de standaardfuncties voor het werken met json te vervangen, maar de prestaties werden er niet beter op. De V8-motor moet goed geoptimaliseerd zijn voor deze operaties.

We werkten met transacties, tokens en blokken via klassen. Bij het maken van dergelijke klassen daalden de prestaties met 2 keer, wat aangeeft dat OOP niet geschikt is voor ons. Ik moest alles herschrijven naar een puur functionele benadering.

Registratie in de database

In eerste instantie werd Redis gekozen voor data-opslag als een van de meest productieve oplossingen die aan onze eisen voldoet: sleutelwaarde-opslag, werken met hashtabellen, sets. We hebben redis-benchmark gelanceerd en hebben ~80 bewerkingen per seconde uitgevoerd in 1 pipeline-modus.

Voor hoge prestaties hebben we Redis fijner afgesteld:

  • Er is een Unix-socketverbinding tot stand gebracht.
  • We hebben het opslaan van de status op schijf uitgeschakeld (voor de betrouwbaarheid kunt u een replica instellen en deze in een afzonderlijke Redis op schijf opslaan).

In Redis is een pool een hashtabel omdat we alle transacties in één query moeten kunnen ophalen en transacties één voor één moeten kunnen verwijderen. We hebben geprobeerd een gewone lijst te gebruiken, maar deze gaat langzamer als de hele lijst wordt verwijderd.

Bij gebruik van standaard NodeJS behaalden de Redis-bibliotheken een prestatie van 18 transacties per seconde. De snelheid daalde 9 keer.

Omdat de benchmark ons ​​liet zien dat de mogelijkheden duidelijk 5 keer groter waren, zijn we begonnen met optimaliseren. We veranderden de bibliotheek naar ioredis en behaalden een prestatie van 25k per seconde. We hebben transacties één voor één toegevoegd met behulp van het `hset`-commando. We genereerden dus veel zoekopdrachten in Redis. Het idee ontstond om transacties in batches te combineren en deze met één commando `hmset` te versturen. Het resultaat is 32k per seconde.

Om verschillende redenen, die we hieronder zullen beschrijven, werken we met data met behulp van `Buffer` en, zoals blijkt, als je deze naar tekst converteert (`buffer.toString('hex')`) voordat je gaat schrijven, kun je extra prestatie. Zo werd de snelheid verhoogd tot 35k per seconde. Op dit moment hebben we besloten verdere optimalisatie op te schorten.

We moesten overstappen op een binair protocol omdat:

1. Het systeem berekent vaak hashes, handtekeningen, enz., en hiervoor heeft het gegevens in de `Buffer nodig.

2. Wanneer ze tussen services worden verzonden, wegen binaire gegevens minder dan tekst. Bij het verzenden van een blok met 1 miljoen transacties kunnen de gegevens in de tekst bijvoorbeeld meer dan 300 megabytes in beslag nemen.

3. Het voortdurend transformeren van gegevens heeft invloed op de prestaties.

Daarom hebben we ons eigen binaire protocol voor het opslaan en verzenden van gegevens als basis genomen, ontwikkeld op basis van de prachtige 'binaire data'-bibliotheek.

Als resultaat kregen we de volgende datastructuren:

-Transactie

  ```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,
  }
  ```

— Teken

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

-Blok

  ```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,
  }
  ```

Met de gebruikelijke commando's `BD.encode(block, Protocol).slice();` en `BD.decode(buffer, Protocol)` converteren we de gegevens naar `Buffer` om op te slaan in Redis of door te sturen naar een ander knooppunt en het ophalen van de gegevens terug.

We hebben ook 2 binaire protocollen voor het overbrengen van gegevens tussen services:

— Protocol voor interactie met Plasma Node via Unix-socket

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

waar:

  • `Soort` — de uit te voeren actie, bijvoorbeeld 1 — sendTransaction, 2 — getTransaction;
  • `lading` — gegevens die moeten worden doorgegeven aan de juiste functie;
  • `berichtID` — bericht-ID zodat het antwoord kan worden geïdentificeerd.

— Protocol voor interactie tussen knooppunten

  ```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)
  }
  ```

waar:

  • `code` — berichtcode, bijvoorbeeld 6 — PREPARE_NEW_BLOCK, 7 — BLOCK_VALID, 8 — BLOCK_COMMIT;
  • `versieProtocol` — protocolversie, aangezien knooppunten met verschillende versies op het netwerk kunnen worden geplaatst en verschillend kunnen werken;
  • `volg` — berichtidentificatie;
  • `telChunk` и `chunkNummer` noodzakelijk voor het splitsen van grote berichten;
  • `lengte` и `lading` lengte en de gegevens zelf.

Omdat we de gegevens vooraf hebben getypt, is het uiteindelijke systeem veel sneller dan de `rlp`-bibliotheek van Ethereum. Helaas hebben we het nog niet kunnen weigeren, omdat het nodig is om het slimme contract af te ronden, wat we in de toekomst van plan zijn te doen.

Als het ons lukte om de snelheid te halen 35 000 transacties per seconde, we moeten ze ook op de optimale tijd verwerken. Omdat de geschatte blokvormingstijd 30 seconden duurt, moeten we deze in het blok opnemen 1 000 000 transacties, wat betekent dat er meer moet worden verzonden 100 MB aan gegevens.

Aanvankelijk gebruikten we de `ethereumjs-devp2p`-bibliotheek om tussen knooppunten te communiceren, maar deze kon niet zoveel gegevens verwerken. Als gevolg hiervan hebben we de `ws`-bibliotheek gebruikt en het verzenden van binaire gegevens via de websocket geconfigureerd. Natuurlijk kwamen we ook problemen tegen bij het verzenden van grote datapakketten, maar we hebben ze in stukken verdeeld en nu zijn deze problemen verdwenen.

Ook het vormen van een Merkle-boom en het berekenen van de hash 1 000 000 transacties vereisen ongeveer 10 seconden continu rekenen. Gedurende deze tijd slaagt de verbinding met alle knooppunten erin te verbreken. Er is besloten om deze berekening naar een aparte thread te verplaatsen.

Conclusies:

In feite zijn onze bevindingen niet nieuw, maar om de een of andere reden vergeten veel experts ze tijdens het ontwikkelen.

  • Het gebruik van functioneel programmeren in plaats van objectgeoriënteerd programmeren verbetert de productiviteit.
  • De monoliet is slechter dan een servicearchitectuur voor een productief NodeJS-systeem.
  • Het gebruik van `worker_threads` voor zware berekeningen verbetert de reactiesnelheid van het systeem, vooral als het gaat om i/o-bewerkingen.
  • Unix-socket is stabieler en sneller dan http-verzoeken.
  • Als u snel grote hoeveelheden gegevens over het netwerk moet overbrengen, kunt u beter websockets gebruiken en binaire gegevens verzenden, opgedeeld in stukjes, die kunnen worden doorgestuurd als ze niet aankomen, en vervolgens worden gecombineerd tot één bericht.

Wij nodigen u uit voor een bezoek GitHub project: https://github.com/opporty-com/Plasma-Cash/tree/new-version

Het artikel is mede geschreven door Alexander Nashivan, senior ontwikkelaar Slimme Oplossing Inc.

Bron: www.habr.com

Voeg een reactie