Blokklánc — egy innovatív technológia, amely ígéretet tesz arra, hogy javítja az emberi élet számos területét. Ez a technológia a valós folyamatokat és termékeket áthelyezi a digitális térbe, biztosítja a pénzügyi tranzakciók sebességét és megbízhatóságát, csökkenti azok költségeit, valamint lehetővé teszi modern DAPP-alkalmazások létrehozását intelligens szerződések segítségével decentralizált hálózatokban.
Figyelembe véve a blockchain számos előnyét és alkalmazási területét, furcsának tűnhet, hogy ez a sokat ígérő technológia még nem hatolt be minden iparágba. A probléma az, hogy a modern decentralizált blockchainek méretezhetősége hiányzik. Az Ethereum körülbelül 20 tranzakciót kezel másodpercenként, ami nem elegendő a modern dinamikus üzleti igények kielégítésére. Ugyanakkor a blockchain technológiát használó vállalatok nem mernek lemondani az Ethereumról a magas fokú védelme és a hálózati leállások elleni védelem miatt.
A decentralizáció, a biztonság és a méretezhetőség biztosítása érdekében a blockchainben, ezáltal megoldva a Skálázhatósági Háromszögöt, a fejlesztőcsapat létrehozta a Plasma Casht - egy alhálózatot, amely egy okosszerződésből és egy Node.js alapú privát hálózatból áll, amely időszakosan átadja állapotát a gyökérláncnak (Ethereum).

A Plasma Cash kulcsfolyamatai
1. A felhasználó meghív egy okosszerződés `deposit` funkciót, átadva azt az összeget ETH-ban, amelyet a Plasma Cash tokenbe szeretne elhelyezni. Az okosszerződés funkció tokent hoz létre, és eseményt generál erről.
2. A Plasma Cash csomópontok, amelyek feliratkoztak az okosszerződés eseményeire, megkapják a betét létrehozásáról szóló eseményt, és hozzáadják a token létrehozásáról szóló tranzakciót a medencéhez.
3. Időszakosan speciális Plasma Cash csomópontok összegyűjtik az összes tranzakciót a medencéből (maximum 1 millió) és blokkokká alakítják őket, kiszámolják a Merkle-fát és ennek megfelelően a hash-t. Ezt a blokkot más csomópontoknak küldik ellenőrzésre. A csomópontok ellenőrzik, hogy a Merkle hash érvényes-e, és érvényesek-e a tranzakciók (például, hogy a token küldője a token birtokosa-e). A blokk ellenőrzése után a csomópont meghívja az okosszerződés `submitBlock` funkcióját, amely elmenti a gyökérláncra a blokk számát és a Merkle hash-t. Az okosszerződés eseményt generál a blokk sikeres hozzáadásáról. A tranzakciók eltávolításra kerülnek a medencéből.
4. A csomópontok, amelyek megkapták a blokk beküldési eseményét, elkezdik alkalmazni azokat a tranzakciókat, amelyeket a blokkhoz adtak.
5. Egy bizonyos pillanatban a token tulajdonosa (vagy nem tulajdonosa) szeretné kivenni azt a Plasma Cash-ból. Ehhez meghívja a `startExit` funkciót, amelybe átadja az utolsó 2 tranzakció információját a tokenről, amelyek megerősítik, hogy valóban ő a token tulajdonosa. Az okos szerződés a Merkle hash segítségével ellenőrzi a tranzakciók meglétét a blokkokban, és a tokent kikerülheti, ami két hét múlva fog megtörténni.
6. Ha a token kivonási művelete szabálytalanságokkal történt (a tokent a kivonás elindítása után költötték el, vagy a token kivonás előtt már másé volt), a token tulajdonosa akár két héten belül megcáfolhatja a kivonást.

A magánélet két módszerrel érhető el.
1. A gyökérlánc semmit sem tud a tranzakciókról, amelyek a gyermekláncon belül létrejönnek és továbbítódnak. A nyilvános információ arról szól, hogy ki helyezett el és vett ki ETH-t a Plasma Cash-be és onnan.
2. A gyermeklánc lehetővé teszi az anonimitás biztosítását zk-SNARKs használatával.
Technológiai háttér
- NodeJS
- Redis
- Etherium
- Soild
Tesztelés
A Plasma Cash fejlesztése során teszteltük a rendszer sebességét, és a következő eredményeket kaptuk:
- legfeljebb 35 000 tranzakció másodpercenként kerül hozzáadásra a poolhoz;
- legfeljebb 1 000 000 tranzakció tárolható egy blokkban.
A teszteket az alábbi 3 szerveren végeztük:
1. Intel Core i7-6700 Quad-Core Skylake NVMe SSD-vel — 512 GB, 64 GB DDR4 RAM
3 érvényes Plasma Cash csomópontot állítottunk fel.
2. AMD Ryzen 7 1700X Octa-Core «Summit Ridge» (Zen), SATA SSD — 500 GB, 64 GB DDR4 RAM
Egy Ropsten testnet ETH csomópontot állítottunk fel.
3 érvényes Plasma Cash csomópontot állítottunk fel.
3. Intel Core i9-9900K Octa-Core NVMe SSD-vel — 1 TB, 64 GB DDR4 RAM
Egy Plasma Cash beküldő csomópontot állítottunk fel.
3 érvényes Plasma Cash csomópontot állítottunk fel.
Teszt indult a tranzakciók hozzáadására a Plasma Cash hálózathoz.
Összesen: 10 Plasma Cash csomópont a privát hálózatban.
1. teszt
1 millió tranzakciós korlát van egy blokkban. Ezért 1 millió tranzakció 2 blokkba kerül be (mivel a rendszer időben képes részt venni egyes tranzakciókban a beküldés során).

Kezdeti állapot: utolsó blokk #7; az adatbázisban 1 millió tranzakció és token tárolva.
00:00 — a tranzakciók generálásához szükséges szkript indítása
01:37 — 1 millió tranzakció létrejött és elkezdődött a küldés a csomópontra
01:46 — a beküldő csomópont 240 ezer tranzakciót vett fel a poolból, és formálja a #8 blokkot. Emellett látjuk, hogy 320 ezer tranzakció adódik hozzá a poolhoz 10 másodperc alatt
01:58 — a #8 blokk aláírásra került és küldésre került a validációhoz
02:03 — a #8 blokk validálva lett, és a Merkle hash és a blokkszám alapján meghívta a `submitBlock` funkciót a okos szerződésben
02:10 — a demó szkript befejezte működését, amely 1 millió tranzakciót küldött el 32 másodperc alatt
02:33 — a node-ok elkezdték megkapni az információt, hogy a #8 blokk hozzá lett adva a gyökérlánchoz, és 240 ezer tranzakciót kezdtek el végrehajtani
02:40 — a pool-ból eltávolították a 240 ezer tranzakciót, amelyek már a #8 blokkban voltak
02:56 — a submit node vette a maradék 760 ezer tranzakciót a pool-ból, és elkezdte számítani a Merkle hasht, valamint aláírni a #9 blokkot
03:20 — minden node tartalmaz 1 millió 240 ezer tranzakciót és tokent
03:35 — a #9 blokk aláírva lett és validálásra küldték más node-okhoz
03:41 — hálózati hiba történt
04:40 — időtúllépés miatt megszűnt a #9 blokk validálásának várakozása
04:54 — a submit node vette a maradék 760 ezer tranzakciót a pool-ból, és elkezdte számítani a Merkle hasht és aláírni a #9 blokkot
05:32 — a #9 blokk aláírva lett és validálásra küldték más node-okhoz
05:53 — a #9 blokk validálva lett és elküldték a gyökérlánchoz
06:17 — a node-ok elkezdték megkapni az információt, hogy a #9 blokk hozzá lett adva a gyökérlánchoz, és 760 ezer tranzakciót kezdtek el végrehajtani
06:47 — a pool megtisztult a транзакcióktól, amelyek a #9 blokkban voltak
09:06 — minden node tartalmaz 2 millió tranzakciót és tokent
Teszt 2
350 ezer a blokk határa. Ennek eredményeként 3 blokkot kapunk.

Kezdeti állapot: utolsó blokk #9; az adatbázisban 2 millió tranzakció és token van tárolva
00:00 — a tranzakciók generálására szolgáló szkript már fut
00:44 — létrejött 1 millió tranzakció, és elkezdődött a node-hoz való küldés
00:56 — a submit node vette a pool-ból a 320 ezer tranzakciót és formálja a #10 blokkot. Azt is látjuk, hogy a pool-ba 320 ezer tranzakció érkezik 10 másodperc alatt
01:12 — a #10 blokk aláírva lett és validálásra küldik más node-okhoz
01:18 — befejezte működését a demó szkript, amely 1 millió tranzakciót küldött el 34 másodperc alatt
01:20 — a #10 blokk validálva lett és elküldték a gyökérlánchoz
01:51 — minden node megkapta a gyökérláncból az információt, hogy a #10 blokk hozzá lett adva, és elkezdik alkalmazni a 320 ezer tranzakciót
02:01 — a pool megtisztult 320 ezer tranzakciótól, amelyeket a #10 blokkba adtak hozzá
02:15 — a submit node vette a pool-ból a 350 ezer tranzakciót és formálja a #11 blokkot
02:34 — a #11 blokk aláírva lett és más node-okhoz küldték validálásra
02:51 — a #11 blokk validálva lett és elküldték a gyökérlánchoz
02:55 — az utolsó node végrehajtotta a tranzakciókat a #10 blokkban
10:59 — A nagyon hosszú tranzakció végrehajtása történt a gyökér láncban a #9-es blokk benyújtásával, de sikerült befejezni, és minden csomópont értesült róla, majd elindították a 350 ezer tranzakciót.
11:05 — A pool 320 ezer tranzakcióval megtisztult, amelyeket a #11-es blokkhoz adtak hozzá.
12:10 — Minden csomópont 1 millió 670 ezer tranzakciót és tokent tartalmaz.
12:17 — A benyújtó csomópont 330 ezer tranzakciót vett a poolból, és a #12-es blokkot képezi.
12:32 — A #12-es blokk aláírásra került és más csomópontokhoz küldték validálásra.
12:39 — A #12-es blokk validálva lett és elküldték a gyökér láncba.
13:44 — Minden csomópont értesítést kapott a gyökér láncból arról, hogy a #12-es blokk hozzá lett adva, és elkezdték alkalmazni a 330 ezer tranzakciót.
14:50 — Minden csomópont 2 millió tranzakciót és tokent tartalmaz.
Teszt 3
Az első és a második szerveren egy validáló csomópontot benyújtó csomóponttal helyettesítettek.

Kezdő állapot: utolsó blokk #84; az adatbázisban 0 tranzakció és token van tárolva.
00:00 — 3 szkript indult, amelyek 1 millió tranzakciót generálnak és küldenek.
01:38 — 1 millió tranzakció jött létre és elkezdődött a küldés a #3-as benyújtó csomópontba.
01:50 — A #3-as benyújtó csomópont 330 ezer tranzakciót vett a poolból és a #85-ös blokkot képezi (f21). Szintén láthatjuk, hogy 350 ezer tranzakció kerül hozzáadásra 10 másodperc alatt.
01:53 — 1 millió tranzakció jött létre és elkezdődött a küldés a #1-es benyújtó csomópontba.
01:50 — A #3-as benyújtó csomópont 330 ezer tranzakciót vett a poolból és a #85-ös blokkot képezi (f21). Szintén láthatjuk, hogy 350 ezer tranzakció kerül hozzáadásra 10 másodperc alatt.
02:01 — A #1-es benyújtó csomópont 250 ezer tranzakciót vett a poolból és a #85-ös blokkot képezi (65e).
02:06 — A #85-ös blokk (f21) aláírásra került és más csomópontokhoz küldték validálásra.
02:08 — A #3-as szerver demó szkriptje befejezte működését, amely 1 millió tranzakciót küldött 30 másodperc alatt.
02:14 — A #85-ös blokk (f21) validálva lett és elküldték a gyökér láncba.
02:19 — A #85-ös blokk (65e) aláírásra került és más csomópontokhoz küldték validálásra.
02:22 — 1 millió tranzakció jött létre és elkezdődött a küldés a #2-es benyújtó csomópontba.
02:27 — A #85-ös blokk (65e) validálva lett és elküldték a gyökér láncba.
02:29 — A #2-es benyújtó csomópont 111855 tranzakciót vett a poolból és a #85-ös blokkot képezi (256).
02:36 — A #85-ös blokk (256) aláírásra került és más csomópontokhoz küldték validálásra.
02:36 — A #1-es szerver demó szkriptje befejezte működését, amely 1 millió tranzakciót küldött 42,5 másodperc alatt.
02:38 — A #85-ös blokk (256) validálva lett és elküldték a gyökér láncba.
03:08 — A #2-es szerver demó szkriptje befejezte működését, amely 1 millió tranzakciót küldött 47 másodperc alatt.
03:38 — Minden csomópont értesítést kapott a gyökér láncból arról, hogy a #85 (f21), #86 (65e), #87 (256) blokkok hozzá lettek adva, és elkezdik alkalmazni a 330 ezer, 250 ezer, 111855 tranzakciót.
03:49 — a medence 330k-ra, 250k-ra, 111855 tranzakcióra tisztult, amelyek a #85 (f21), #86(65e), #87(256) blokkokba kerültek
03:59 — az első node 888145 tranzakciót vett a medencéből, és a #88 (214) blokkot alakítja, a második node 750k tranzakciót vett a medencéből, és a #88 (50a) blokkot alakítja, a harmadik node 670k tranzakciót vett a medencéből, és a #88 (d3b) blokkot alakítja
04:44 — a #88 (d3b) blokk aláírásra került, és validálásra elküldésre került a többi node-hoz
04:58 — a #88 (214) blokk aláírásra került, és validálásra elküldésre került a többi node-hoz
05:11 — a #88 (50a) blokk aláírásra került, és validálásra elküldésre került a többi node-hoz
05:11 — a #85 (d3b) blokk validálva lett, és elküldték a gyökér láncba
05:36 — a #85 (214) blokk validálva lett, és elküldték a gyökér láncba
05:43 — az összes node megkapta a gyökér láncból az információt, hogy a #88 (d3b), #89(214) blokkok hozzá lettek adva, és elkezdik alkalmazni a 670k, 750k tranzakciókat
06:50 — a kapcsolat megszakadása miatt a #85 (50a) blokk nem lett validálva
06:55 — a második node 888145 tranzakciót vett a medencéből, és a #90 (50a) blokkot alakítja
08:14 — a #90 (50a) blokk aláírásra került, és validálásra elküldésre került a többi node-hoz
09:04 — a #90 (50a) blokk validálva lett, és elküldték a gyökér láncba
11:23 — az összes node megkapta a gyökér láncból az információt, hogy a #90 (50a) blokk hozzá lett adva, és elkezdik alkalmazni a 888145 tranzakciót. Ekkor már régen a #3 szerver alkalmazta a tranzakciókat a #88 (d3b), #89(214) blokkokból
12:11 — az összes medence üres
13:41 — az összes #3 szerver node 3 millió tranzakciót és tokent tartalmaz
14:35 — az összes #1 szerver node 3 millió tranzakciót és tokent tartalmaz
19:24 — az összes #2 szerver node 3 millió tranzakciót és tokent tartalmaz
Akadályok
A Plasma Cash fejlesztése során a következő problémákkal találkoztunk, amelyeket fokozatosan megoldottunk és megoldunk:
1. A rendszer különböző funkcióinak kölcsönhatása okozta konfliktus. Például a tranzakciók medencébe való felvétele blokkolta a blokkok aláírását és validálását, és fordítva, ami sebességcsökkenéshez vezetett.
2. Nem volt világos, hogyan lehetne óriási mennyiségű tranzakciót küldeni, miközben minimalizáljuk az adatátviteli költségeket.
3. Nem volt világos, hogyan és hol tároljuk az adatokat a magas eredmények elérése érdekében.
4. Nem volt világos, hogyan szervezhető a hálózat a node-ok között, mivel az 1 millió tranzakciót tartalmazó blokk körülbelül 100 MB méretű.
5. Az egy szálon történő munka megszakítja a kapcsolatot a node-ok között, amikor hosszú számítások történnek (például a Merkle fa felépítése és a hash számítása).
Hogyan birkóztunk meg mindezzel?
A Plasma Cash node első verziója egyfajta kombájn volt, amely egyszerre tudott mindent elvégezni: tranzakciókat fogadni, blokkot létrehozni és érvényesíteni, API-t biztosítani az adatok eléréséhez. Mivel a NodeJS eredetileg egy szálú, a nehéz Merkle-fa számító funkció blokkolta a tranzakció hozzáadási funkciót. Két lehetőséget láttunk ennek a problémának a megoldására:
1. Több NodeJS folyamat indítása, mindegyik egy adott funkciót lát el.
2. Worker_threads használata, és a kód egy részének a szálakba történő kiemelése.
Végül mindkét megoldást egyszerre alkalmaztuk: logikailag három részre bontottuk az egyetlen node-t, amelyek külön működhetnek, de egyidejűleg szinkron módon is.
1. A submit node, amely a tranzakciókat fogadja a poolba és blokkokat kreál.
2. Az érvényesítő node, amely ellenőrzi a node-ok érvényességét.
3. API node — API-t biztosít az adatok eléréséhez.
Minden node-hoz hozzá tudunk kapcsolódni unix socket-en keresztül a cli-n.
A nehéz műveleteket, mint a Merkle-fa számítását, külön szálba helyeztük.
Így sikerült elérni, hogy a Plasma Cash összes funkciója egyidejűleg és zökkenőmentesen működjön.
Amint a rendszer funkcionálisan működni kezdett, tesztelni kezdtük a sebességet, és sajnos elégedetlen eredményeket kaptunk: 5 000 tranzakció másodpercenként és akár 50 000 tranzakció blokkban. Ki kellett derítenünk, mi valósult meg helytelenül.
Először a Plasma Cash-sel való kommunikációs mechanizmust kezdtük tesztelni, hogy kiderítsük a rendszer csúcs teljesítményét. Korábban már írtuk, hogy a Plasma Cash node unix socket interfészt biztosít. Kezdetben szöveges formátumú volt. A json objektumokat `JSON.parse()` és `JSON.stringify()` használatával küldtük.
{
"action": "sendTransaction",
"payload":{
"prevHash": "0x8a88cc4217745fd0b4eb161f6923235da10593be66b841d47da86b9cd95d93e0",
"prevBlock": 41,
"tokenId": "57570139642005649136210751546585740989890521125187435281313126554130572876445",
"newOwner": "0x200eabe5b26e547446ae5821622892291632d4f4",
"type": "pay",
"data": "",
"signature": "0xd1107d0c6df15e01e168e631a386363c72206cb75b233f8f3cf883134854967e1cd9b3306cc5c0ce58f0a7397ae9b2487501b56695fe3a3c90ec0f61c7ea4a721c"
}
}
Megmértük az ilyen objektumok átküldési sebességét, és ~ 130k másodpercenként eredményt kaptunk. Megpróbáltuk lecserélni az alapértelmezett json kezelő funkciókat, de a teljesítmény nem javult. Valószínűleg a V8 motor jól optimalizált ezeken a műveleteken.
A tranzakciókkal, tokenekkel és blokkokkal való munka osztályokon keresztül zajlott nálunk. Az ilyen osztályok létrehozásakor a teljesítmény a felére csökkent, ami azt jelzi, hogy az OOP nem megfelelő számunkra. Újra kellett írni mindent tiszta funkcionális megközelítésre.
Adatbázisba írás
Kezdetben a Redis-t választottuk az adatok tárolására, mint az egyik legteljesítményigényesebb megoldást, ami megfelel az elvárásainknak: key-value tárolás, hash-táblák kezelése, halmazok. Futtattuk a redis-benchmarkot és ~80k műveletet kaptunk másodpercenként pipelining módban.
A magas teljesítmény érdekében a Redis-t finomabban állítottuk be:
- Unix socket kapcsolatot állítottunk be.
- Kikapcsoltuk a lemezre mentést (megbízhatóság érdekében be lehet állítani egy replikát, és már egy külön Redis alapján végezni a lemezre mentést).
A Redis-ben a pool hash-tábla, mivel szükségünk van arra, hogy az összes tranzakciót egyetlen kérésben megkapjuk, és egyesével töröljük a tranzakciókat. Megpróbáltuk a szokásos listát használni, de az lassabban működik, ha az egész listát szeretnénk kiüríteni.
A standard NodeJS Redis könyvtár használatakor 18k tranzakciót kaptunk másodpercenként. A sebesség 9-szeresére csökkent.
Mivel a benchmark világosan megmutatta a lehetőségek 5-szörösét, kezdettük az optimalizálást. Megváltoztattuk a könyvtárat ioredis-re, és így elértük a 25k-t másodpercenként. A tranzakciókat egyesével adtuk hozzá, az `hset` parancsot használva. Így sok kérés keletkezett a Redis felé. Felmerült az ötlet, hogy a tranzakciókat csomagokba egyesítjük, és egyetlen `hmset` parancsot küldünk. Az eredmény — 32k másodpercenként.
Több okból, amelyeket lentebb ismertetünk, a `Buffer`-rel dolgozunk az adatokkal, és kiderült, hogy ha a szövegre alakítjuk (`buffer.toString('hex')`) írás előtt, plusz teljesítményt érhetünk el. Így a sebességet 35k-ra sikerült növelni. Jelenleg úgy döntöttünk, hogy felfüggesztjük a további optimalizálást.
Át kellett térnünk a bináris protokollra, mivel:
1. A rendszer gyakran számít hash-eket, aláírásokat stb., és ehhez bináris adatokra van szüksége.
2. Szolgáltatások közötti adatátvitelkor a bináris adatok kevesebb helyet foglalnak, mint a szöveges adatok. Például, amikor 1 millió tranzakciót tartalmazó blokkot küldünk, a szöveges adatok több mint 300 megabájtot is elfoglalhatnak.
3. Az adatok folyamatos átkonvertálása befolyásolja a teljesítményt.
Ezért alapul saját bináris adat tárolási és továbbítási protokollt vettünk, amely a kiváló `binary-data` könyvtár alapján készült.
Ennek eredményeként a következő adatszerkezetek jöttek létre:
— Transaction
```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,
}
```
— Token
```json
{
id: BD.types.string(null),
owner: BD.types.buffer(20),
block: BD.types.uint24le,
amount: BD.types.string(null),
}
```
— Block
```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,
}
```
A `BD.encode(block, Protocol).slice();` és a `BD.decode(buffer, Protocol)` parancsokkal adatokat alakítunk át `Buffer` formátumra, a Redis tárolására vagy másik node-nak való továbbítására és az adatok visszanyerésére.
Két bináris protokollunk is van az adatok átadására a szolgáltatások között:
— Protokoll a Plasma Node-dal való kommunikációhoz unix socket-en keresztül
```json
{
type: BD.types.uint8,
messageId: BD.types.uint24le,
error: BD.types.uint8,
length: BD.types.uint24le,
payload: BD.types.buffer(({node}) => node.length)
}
```
ahol:
- `type` — a végrehajtandó művelet, például 1 — sendTransaction, 2 — getTransaction;
- `payload` — az adatok, amelyeket a megfelelő funkciónak kell átadni;
- `messageId` — a üzenet azonosítója, amely lehetővé teszi a válasz azonosítását.
— Protokoll a node-ok közötti interakcióhoz
```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)
}
```
ahol:
- `code` — az üzenet kódja, például 6 — PREPARE_NEW_BLOCK, 7 — BLOCK_VALID, 8 — BLOCK_COMMIT;
- `versionProtocol` — a protokoll verziója, mivel a hálózaton különböző verziójú node-ok is működhetnek, amelyek eltérően működnek;
- `seq` — az üzenet azonosítója;
- `countChunk` és `chunkNumber` szükségesek nagy üzenetek hasításához;
- `length` és `payload` a hosszúság és maguk az adatok.
Mivel előre típusosítottuk az adatokat, a végső rendszer sokkal gyorsabban működik, mint az Ethereum `rlp` könyvtára. Sajnos eddig nem sikerült lemondanunk róla, mivel a okos szerződést még ki kell dolgozni, amit a jövőben tervezünk megtenni.
Ha sikerült elérnünk a sebességet 35 000 másodpercenként kell tranzakciókat feldolgoznunk, és ezt optimális időn belül kell megtennünk. Mivel egy blokk létrehozásának körülbelül 30 másodpercbe telik, be kell építenünk a blokkba 1 000 000 tranzakciókat, ami több mint 100 MB adat továbbítását jelenti.
Eredetileg az `ethereumjs-devp2p` könyvtárat használtuk a csomópontok közötti kapcsolatra, de ez nem bírta el a mennyiségű adatot. Ezért a `ws` könyvtárra váltottunk, és beállítottuk a bináris adatok továbbítását websocketen. Természetesen problémákkal is szembesültünk a nagy adatcsomagok átadásakor, de ezeket chunkokra osztottuk, és a problémák megszűntek.
A Merkle-fa létrehozása és a hash kiszámítása 1 000 000 tranzakciónként körülbelül 10 másodpercre van szükség a folyamatos számításhoz. Ez idő alatt a kapcsolat megszakad az összes csomóponttal. Úgy döntöttünk, hogy ezt a számítást egy külön szálra helyezzük.
Következtetések:
Valójában a megállapításaink nem újjak, de valamiért sok szakértő megfeledkezik róluk a fejlesztés során.
- A funkcionális programozás használata az objektum-orientált programozás helyett növeli a teljesítményt.
- A monolitikus architektúra rosszabb, mint a szolgáltatás-architektúra egy teljesítményorientált NodeJS rendszer számára.
- A `worker_threads` használata a nehéz számításokhoz javítja a rendszer válaszkészségét, különösen az I/O műveletek során.
- A unix socket stabilabb és gyorsabb, mint a http kérések.
- Ha nagy mennyiségű adatot szeretnénk gyorsan átadni a hálózaton, a websocketek használata a legjobb megoldás, bináris adatok chunkokra osztva, amelyeket újra tudunk küldeni, ha nem érkeznek meg, és utána egy üzenetbe egyesíthetjük őket.
Ön is szeretettel várjuk GitHub a projektre:
A cikk társszerzője volt Alexander Nashivan, a .
Forrás: habr.com
