Test publik: Një zgjidhje për privatësinë dhe shkallëzueshmërinë në Ethereum

Zinxhiri i bllokuar është një teknologji inovative që premton të përmirësojë shumë fusha të jetës njerëzore. Ai transferon procese dhe produkte reale në hapësirën dixhitale, siguron shpejtësi dhe besueshmëri të transaksioneve financiare, zvogëlon koston e tyre dhe gjithashtu ju lejon të krijoni aplikacione moderne DAPP duke përdorur kontrata inteligjente në rrjete të decentralizuara.

Duke pasur parasysh përfitimet e shumta dhe aplikimet e shumëllojshme të blockchain, mund të duket e habitshme që kjo teknologji premtuese nuk ka hyrë ende në çdo industri. Problemi është se blockchains moderne të decentralizuara nuk kanë shkallëzueshmëri. Ethereum përpunon rreth 20 transaksione në sekondë, gjë që nuk mjafton për të plotësuar nevojat e bizneseve dinamike të sotme. Në të njëjtën kohë, kompanitë që përdorin teknologjinë blockchain hezitojnë të braktisin Ethereum për shkak të shkallës së lartë të mbrojtjes nga hakimet dhe dështimet e rrjetit.

Për të siguruar decentralizimin, sigurinë dhe shkallëzimin në blockchain, duke zgjidhur kështu Trilemën e Scalability, ekipi i zhvillimit Mundësi krijoi Plasma Cash, një zinxhir filial i përbërë nga një kontratë inteligjente dhe një rrjet privat i bazuar në Node.js, i cili në mënyrë periodike e transferon gjendjen e tij në zinxhirin rrënjë (Ethereum).

Test publik: Një zgjidhje për privatësinë dhe shkallëzueshmërinë në Ethereum

Proceset kryesore në paratë e plazmës

1. Përdoruesi e quan funksionin e kontratës inteligjente "depozitë", duke kaluar në të shumën e ETH që dëshiron të depozitojë në tokenin e parave të plazmës. Funksioni i kontratës inteligjente krijon një shenjë dhe gjeneron një ngjarje në lidhje me të.

2. Nyjet Plasma Cash të abonuara në ngjarjet e kontratës inteligjente marrin një ngjarje në lidhje me krijimin e një depozite dhe shtojnë një transaksion në lidhje me krijimin e një token në pishinë.

3. Periodikisht, nyjet speciale Plasma Cash marrin të gjitha transaksionet nga pishina (deri në 1 milion) dhe formojnë një bllok prej tyre, llogarisin pemën Merkle dhe, në përputhje me rrethanat, hash-in. Ky bllok dërgohet në nyje të tjera për verifikim. Nyjet kontrollojnë nëse hash-i Merkle është i vlefshëm dhe nëse transaksionet janë të vlefshme (për shembull, nëse dërguesi i tokenit është pronari i tij). Pas verifikimit të bllokut, nyja thërret funksionin `submitBlock` të kontratës inteligjente, e cila ruan numrin e bllokut dhe Merkle hash-in në zinxhirin e skajit. Kontrata inteligjente gjeneron një ngjarje që tregon shtimin e suksesshëm të një blloku. Transaksionet hiqen nga grupi.

4. Nyjet që marrin ngjarjen e paraqitjes së bllokut fillojnë të aplikojnë transaksionet që janë shtuar në bllok.

5. Në një moment, pronari (ose jo pronari) i tokenit dëshiron ta tërheqë atë nga Plasma Cash. Për ta bërë këtë, ai e quan funksionin 'startExit', duke i dhënë informacion për 2 transaksionet e fundit në token, të cilat konfirmojnë se ai është pronari i tokenit. Kontrata inteligjente, duke përdorur hash Merkle, kontrollon praninë e transaksioneve në blloqe dhe dërgon tokenin për tërheqje, e cila do të ndodhë brenda dy javësh.

6. Nëse operacioni i tërheqjes së tokenit ka ndodhur me shkelje (tokeni është shpenzuar pasi ka filluar procedura e tërheqjes ose token ishte tashmë i dikujt tjetër përpara tërheqjes), pronari i tokenit mund të refuzojë tërheqjen brenda dy javësh.

Test publik: Një zgjidhje për privatësinë dhe shkallëzueshmërinë në Ethereum

Privatësia arrihet në dy mënyra

1. Zinxhiri rrënjësor nuk di asgjë për transaksionet që gjenerohen dhe përcillen brenda zinxhirit fëmijë. Informacioni se kush depozitoi dhe tërhoqi ETH nga Plasma Cash mbetet publik.

2. Zinxhiri fëmijë lejon transaksione anonime duke përdorur zk-SNARK.

Rafte teknologjike

  • NodeJS
  • Redis
  • Eteriumi
  • Toka

Testimi

Gjatë zhvillimit të Plasma Cash, ne testuam shpejtësinë e sistemit dhe morëm rezultatet e mëposhtme:

  • deri në 35 transaksione në sekondë i shtohen grupit;
  • deri në 1 transaksione mund të ruhen në një bllok.

Testet u kryen në 3 serverët e mëposhtëm:

1. Intel Core i7-6700 Quad-Core Skylake përfshirë. NVMe SSD – 512 GB, 64 GB RAM DDR4
U ngritën 3 nyje të vlefshmërisë së parave të plazmës.

2. AMD Ryzen 7 1700X Octa-Core "Summit Ridge" (Zen), SATA SSD - 500 GB, 64 GB DDR4 RAM
Nyja ETH e rrjetit testues Ropsten u ngrit.
U ngritën 3 nyje të vlefshmërisë së parave të plazmës.

3. Intel Core i9-9900K Octa-Core përfshirë. NVMe SSD – 1 TB, 64 GB RAM DDR4
U ngrit 1 nyje e paraqitjes së parave të gatshme në plazma.
U ngritën 3 nyje të vlefshmërisë së parave të plazmës.
U lançua një test për të shtuar transaksione në rrjetin Plasma Cash.

Total: 10 nyje Plasma Cash në një rrjet privat.

Testi 1

Ekziston një kufi prej 1 milion transaksionesh për bllok. Prandaj, 1 milion transaksione bien në 2 blloqe (pasi sistemi arrin të marrë një pjesë të transaksioneve dhe të dorëzojë gjatë dërgimit të tyre).


Gjendja fillestare: blloku i fundit #7; 1 milion transaksione dhe argumente ruhen në bazën e të dhënave.

00:00 — fillimi i skriptit të gjenerimit të transaksioneve
01:37 - U krijuan 1 milion transaksione dhe filloi dërgimi në nyje
01:46 — nyja e dorëzimit mori 240 mijë transaksione nga grupi dhe formon bllokun #8. Ne gjithashtu shohim se 320 mijë transaksione i shtohen grupit në 10 sekonda
01:58 — blloku #8 nënshkruhet dhe dërgohet për vërtetim
02:03 — blloku #8 është vërtetuar dhe funksioni `submitBlock` i kontratës inteligjente thirret me hash dhe numrin e bllokut Merkle
02:10 — mbaroi së punuari skripti demo, i cili dërgoi 1 milion transaksione në 32 sekonda
02:33 - nyjet filluan të marrin informacion se blloku #8 u shtua në zinxhirin rrënjë dhe filloi të kryente 240 mijë transaksione
02:40 - 240 mijë transaksione u hoqën nga grupi, të cilat tashmë janë në bllokun #8
02:56 — nyja e dorëzimit mori 760 mijë transaksionet e mbetura nga grupi dhe filloi të llogaritte hash-in Merkle dhe të nënshkruante bllokun #9
03:20 - të gjitha nyjet përmbajnë 1 milion 240 mijë transaksione dhe argumente
03:35 — blloku #9 nënshkruhet dhe dërgohet për vërtetim në nyje të tjera
03:41 - Ndodhi një gabim në rrjet
04:40 — koha e pritjes për vlefshmërinë e bllokut #9 ka mbaruar
04:54 — nyja e dorëzimit mori 760 mijë transaksionet e mbetura nga grupi dhe filloi të llogaritte hash-in Merkle dhe të nënshkruante bllokun #9
05:32 — blloku #9 nënshkruhet dhe dërgohet për vërtetim në nyje të tjera
05:53 — blloku #9 vërtetohet dhe dërgohet në zinxhirin rrënjë
06:17 - nyjet filluan të marrin informacion se blloku #9 u shtua në zinxhirin rrënjë dhe filloi të kryente 760 mijë transaksione
06:47 — grupi është pastruar nga transaksionet që janë në bllokun #9
09:06 - të gjitha nyjet përmbajnë 2 milion transaksione dhe argumente

Testi 2

Ekziston një kufi prej 350 mijë për bllok. Si rezultat, ne kemi 3 blloqe.


Gjendja fillestare: blloku i fundit #9; 2 milion transaksione dhe argumente ruhen në bazën e të dhënave

00:00 — skripti i gjenerimit të transaksioneve tashmë është nisur
00:44 - U krijuan 1 milion transaksione dhe filloi dërgimi në nyje
00:56 — nyja e dorëzimit mori 320 mijë transaksione nga grupi dhe formon bllokun #10. Ne gjithashtu shohim se 320 mijë transaksione i shtohen grupit në 10 sekonda
01:12 — blloku #10 nënshkruhet dhe dërgohet në nyje të tjera për vërtetim
01:18 — mbaroi së punuari skripti demo, i cili dërgoi 1 milion transaksione në 34 sekonda
01:20 — blloku #10 vërtetohet dhe dërgohet në zinxhirin rrënjë
01:51 - të gjitha nyjet morën informacion nga zinxhiri rrënjë që blloku #10 u shtua dhe fillon të aplikojë 320 mijë transaksione
02:01 - grupi është pastruar për 320 mijë transaksione që janë shtuar në bllokun #10
02:15 — dorëzoni nyjen mori 350 mijë transaksione nga grupi dhe formon bllokun #11
02:34 — blloku #11 nënshkruhet dhe dërgohet në nyje të tjera për vërtetim
02:51 — blloku #11 vërtetohet dhe dërgohet në zinxhirin rrënjë
02:55 - nyja e fundit përfundoi transaksionet nga blloku #10
10:59 — transaksioni me paraqitjen e bllokut #9 mori një kohë shumë të gjatë në zinxhirin rrënjë, por ai u përfundua dhe të gjitha nyjet morën informacion në lidhje me të dhe filluan të kryejnë 350 mijë transaksione
11:05 - grupi është pastruar për 320 mijë transaksione që janë shtuar në bllokun #11
12:10 - të gjitha nyjet përmbajnë 1 milion 670 mijë transaksione dhe argumente
12:17 — dorëzoni nyjen mori 330 mijë transaksione nga grupi dhe formon bllokun #12
12:32 — blloku #12 nënshkruhet dhe dërgohet në nyje të tjera për vërtetim
12:39 — blloku #12 vërtetohet dhe dërgohet në zinxhirin rrënjë
13:44 - të gjitha nyjet morën informacion nga zinxhiri rrënjë që blloku #12 u shtua dhe fillon të aplikojë 330 mijë transaksione
14:50 - të gjitha nyjet përmbajnë 2 milion transaksione dhe argumente

Testi 3

Në serverin e parë dhe të dytë, një nyje vërtetuese u zëvendësua nga një nyje dërguese.


Gjendja fillestare: blloku i fundit #84; 0 transaksione dhe shenja të ruajtura në bazën e të dhënave

00:00 — Janë lansuar 3 skripta që gjenerojnë dhe dërgojnë 1 milion transaksione secili
01:38 - U krijuan 1 milion transaksione dhe filloi dërgimi për të dorëzuar nyjen #3
01:50 — dorëzoni nyjen #3 mori 330 mijë transaksione nga grupi dhe formon bllokun #85 (f21). Ne gjithashtu shohim se 350 mijë transaksione i shtohen grupit në 10 sekonda
01:53 - U krijuan 1 milion transaksione dhe filloi dërgimi për të dorëzuar nyjen #1
01:50 — dorëzoni nyjen #3 mori 330 mijë transaksione nga grupi dhe formon bllokun #85 (f21). Ne gjithashtu shohim se 350 mijë transaksione i shtohen grupit në 10 sekonda
02:01 — dorëzoni nyjen #1 mori 250 mijë transaksione nga grupi dhe formon bllokun #85 (65e)
02:06 — blloku #85 (f21) nënshkruhet dhe dërgohet në nyje të tjera për vërtetim
02:08 — skripti demo i serverit #3, i cili dërgoi 1 milion transaksione në 30 sekonda, përfundoi punën
02:14 — blloku #85 (f21) vërtetohet dhe dërgohet në zinxhirin rrënjë
02:19 — blloku #85 (65e) nënshkruhet dhe dërgohet në nyje të tjera për vërtetim
02:22 - U krijuan 1 milion transaksione dhe filloi dërgimi për të dorëzuar nyjen #2
02:27 — blloku #85 (65e) i vërtetuar dhe dërguar në zinxhirin rrënjë
02:29 — dorëzoni nyjen #2 mori 111855 transaksione nga grupi dhe formon bllokun #85 (256).
02:36 — blloku #85 (256) nënshkruhet dhe dërgohet në nyje të tjera për vërtetim
02:36 — skripti demo i serverit #1, i cili dërgoi 1 milion transaksione në 42.5 sekonda, përfundoi punën
02:38 — blloku #85 (256) vërtetohet dhe dërgohet në zinxhirin rrënjë
03:08 — Skripti i serverit #2 përfundoi duke punuar, i cili dërgoi 1 milion transaksione në 47 sekonda
03:38 - të gjitha nyjet morën informacion nga zinxhiri rrënjë që blloqet #85 (f21), #86(65e), #87(256) u shtuan dhe filluan të aplikojnë 330k, 250k, 111855 transaksione
03:49 - grupi u pastrua në 330k, 250k, 111855 transaksione që u shtuan në blloqet #85 (f21), #86(65e), #87(256)
03:59 — dorëzo nyja #1 mori 888145 transaksione nga grupi dhe formon bllokun #88 (214), dorëzo nyja #2 mori 750 mijë transaksione nga grupi dhe formon bllokun #88 (50a), dorëzo nyjen #3 mori 670 mijë transaksione nga pishina dhe forma e bllokut #88 (d3b)
04:44 — blloku #88 (d3b) nënshkruhet dhe dërgohet në nyje të tjera për vërtetim
04:58 — blloku #88 (214) nënshkruhet dhe dërgohet në nyje të tjera për vërtetim
05:11 — blloku #88 (50a) nënshkruhet dhe dërgohet në nyje të tjera për vërtetim
05:11 — blloku #85 (d3b) vërtetohet dhe dërgohet në zinxhirin rrënjë
05:36 — blloku #85 (214) vërtetohet dhe dërgohet në zinxhirin rrënjë
05:43 - të gjitha nyjet morën informacion nga zinxhiri rrënjë që blloqet #88 (d3b), #89(214) janë shtuar dhe kanë filluar të aplikojnë 670k, 750k transaksione
06:50 — për shkak të një dështimi komunikimi, blloku #85 (50a) nuk u vërtetua
06:55 — dorëzoni nyjen #2 mori 888145 transaksione nga grupi dhe formon bllokun #90 (50a)
08:14 — blloku #90 (50a) nënshkruhet dhe dërgohet në nyje të tjera për vërtetim
09:04 — blloku #90 (50a) vërtetohet dhe dërgohet në zinxhirin rrënjë
11:23 - të gjitha nyjet morën informacion nga zinxhiri rrënjë që u shtua blloku #90 (50a) dhe filluan të aplikojnë 888145 transaksione. Në të njëjtën kohë, serveri #3 ka aplikuar tashmë transaksione nga blloqet #88 (d3b), #89(214)
12:11 - të gjitha pishinat janë bosh
13:41 — të gjitha nyjet e serverit #3 përmbajnë 3 milionë transaksione dhe shenja
14:35 — të gjitha nyjet e serverit #1 përmbajnë 3 milionë transaksione dhe shenja
19:24 — të gjitha nyjet e serverit #2 përmbajnë 3 milionë transaksione dhe shenja

Pengesat

Gjatë zhvillimit të Plasma Cash kemi hasur në problemet e mëposhtme, të cilat gradualisht i kemi zgjidhur dhe po i zgjidhim:

1. Konflikti në ndërveprimin e funksioneve të ndryshme të sistemit. Për shembull, funksioni i shtimit të transaksioneve në grup bllokoi punën e paraqitjes dhe verifikimit të blloqeve dhe anasjelltas, gjë që çoi në një rënie të shpejtësisë.

2. Nuk ishte menjëherë e qartë se si të dërgohej një numër i madh transaksionesh duke minimizuar kostot e transferimit të të dhënave.

3. Nuk ishte e qartë se si dhe ku të ruheshin të dhënat për të arritur rezultate të larta.

4. Nuk ishte e qartë se si të organizohej një rrjet midis nyjeve, pasi madhësia e një blloku me 1 milion transaksione merr rreth 100 MB.

5. Puna në modalitetin me një fije të vetme prish lidhjen midis nyjeve kur ndodhin llogaritjet e gjata (për shembull, ndërtimi i një peme Merkle dhe llogaritja e hash-it të saj).

Si u përballëm me gjithë këtë?

Versioni i parë i nyjës Plasma Cash ishte një lloj kombinati që mund të bënte gjithçka në të njëjtën kohë: të pranonte transaksione, të dorëzonte dhe vërtetonte blloqet dhe të siguronte një API për aksesimin e të dhënave. Meqenëse NodeJS është origjinale me një fillesë, funksioni i rëndë i llogaritjes së pemës Merkle bllokoi funksionin e transaksionit të shtuar. Ne pamë dy opsione për zgjidhjen e këtij problemi:

1. Nisni disa procese NodeJS, secila prej të cilave kryen funksione specifike.

2. Përdorni worker_threads dhe zhvendosni ekzekutimin e një pjese të kodit në thread.

Si rezultat, ne përdorëm të dy opsionet në të njëjtën kohë: logjikisht ndamë një nyje në 3 pjesë që mund të funksionojnë veçmas, por në të njëjtën kohë në mënyrë sinkrone

1. Nyja e dorëzimit, e cila pranon transaksionet në grup dhe krijon blloqe.

2. Një nyje vërtetuese që kontrollon vlefshmërinë e nyjeve.

3. Nyja API - siguron një API për aksesimin e të dhënave.

Në këtë rast, mund të lidheni me secilën nyje përmes një fole unix duke përdorur cli.

Ne i zhvendosëm operacionet e rënda, të tilla si llogaritja e pemës Merkle, në një fije të veçantë.

Kështu, ne kemi arritur funksionimin normal të të gjitha funksioneve Plasma Cash në të njëjtën kohë dhe pa dështime.

Pasi sistemi u funksionalizua, filluam testimin e shpejtësisë dhe, për fat të keq, morëm rezultate të pakënaqshme: 5 transaksione në sekondë dhe deri në 000 transaksione për bllok. Më duhej të kuptoja se çfarë ishte zbatuar gabimisht.

Si fillim, ne filluam testimin e mekanizmit të komunikimit me Plasma Cash për të zbuluar aftësinë maksimale të sistemit. Ne kemi shkruar më herët se nyja Plasma Cash ofron një ndërfaqe unix socket. Fillimisht ishte e bazuar në tekst. objektet json u dërguan duke përdorur `JSON.parse()` dhe `JSON.stringify()`.

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

Ne matëm shpejtësinë e transferimit të objekteve të tilla dhe gjetëm ~ 130k në sekondë. Ne u përpoqëm të zëvendësonim funksionet standarde për të punuar me json, por performanca nuk u përmirësua. Motori V8 duhet të jetë i optimizuar mirë për këto operacione.

Ne kemi punuar me transaksione, argumente dhe blloqe përmes klasave. Kur krijohen klasa të tilla, performanca ra me 2 herë, gjë që tregon se OOP nuk është i përshtatshëm për ne. Më duhej të rishkruaja gjithçka në një qasje thjesht funksionale.

Regjistrimi në bazën e të dhënave

Fillimisht, Redis u zgjodh për ruajtjen e të dhënave si një nga zgjidhjet më produktive që plotëson kërkesat tona: ruajtja e vlerave kryesore, puna me tabelat hash, grupe. Ne lançuam redis-benchmark dhe morëm ~80 mijë operacione në sekondë në 1 modalitet tubacioni.

Për performancë të lartë, ne akorduam Redis më mirë:

  • Është krijuar një lidhje me fole unix.
  • Ne çaktivizuam ruajtjen e gjendjes në disk (për besueshmëri, mund të konfiguroni një kopje dhe ta ruani në disk në një Redis të veçantë).

Në Redis, një grup është një tabelë hash sepse ne duhet të jemi në gjendje të rikuperojmë të gjitha transaksionet në një pyetje dhe t'i fshijmë transaksionet një nga një. Ne u përpoqëm të përdornim një listë të rregullt, por është më e ngadaltë kur shkarkojmë të gjithë listën.

Kur përdorni NodeJS standard, bibliotekat Redis arritën një performancë prej 18 mijë transaksionesh në sekondë. Shpejtësia ra 9 herë.

Meqenëse standardi na tregoi se mundësitë ishin qartësisht 5 herë më të mëdha, filluam të optimizonim. Ne e ndryshuam bibliotekën në ioredis dhe morëm performancën prej 25 mijë për sekondë. Ne shtuam transaksionet një nga një duke përdorur komandën `hset`. Pra, ne po krijonim shumë pyetje në Redis. Ideja lindi për të kombinuar transaksionet në grupe dhe për t'i dërguar ato me një komandë `hmset`. Rezultati është 32 mijë për sekondë.

Për disa arsye, të cilat do t'i përshkruajmë më poshtë, ne punojmë me të dhëna duke përdorur "Buffer" dhe, siç rezulton, nëse i konvertoni ato në tekst ("buffer.toString('hex')") përpara se të shkruani, mund të merrni shtesë performancës. Kështu, shpejtësia u rrit në 35 mijë për sekondë. Për momentin, ne vendosëm të pezullojmë optimizimin e mëtejshëm.

Na u desh të kalonim në një protokoll binar sepse:

1. Sistemi shpesh llogarit hash-et, nënshkrimet, etj., dhe për këtë i duhen të dhëna në `Buffer.

2. Kur dërgohen ndërmjet shërbimeve, të dhënat binare peshojnë më pak se teksti. Për shembull, kur dërgoni një bllok me 1 milion transaksione, të dhënat në tekst mund të zënë më shumë se 300 megabajt.

3. Transformimi i vazhdueshëm i të dhënave ndikon në performancën.

Prandaj, ne morëm si bazë protokollin tonë binar për ruajtjen dhe transmetimin e të dhënave, të zhvilluar në bazë të bibliotekës së mrekullueshme "binare-të dhëna".

Si rezultat, ne morëm strukturat e mëposhtme të të dhënave:

-Transaksion

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

- Shenjë

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

- Blloko

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

Me komandat e zakonshme `BD.encode(block, Protocol).slice();` dhe `BD.decode(buffer, Protocol)` ne i konvertojmë të dhënat në "Buffer" për t'i ruajtur në Redis ose për t'i përcjellë në një nyje tjetër dhe për të rikthyer të dhënat prapa.

Ne gjithashtu kemi 2 protokolle binare për transferimin e të dhënave ndërmjet shërbimeve:

— Protokolli për ndërveprimin me nyjen e plazmës nëpërmjet prizës unix

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

ku:

  • 'lloj' — veprimi që do të kryhet, për shembull, 1 — dërgoTransaction, 2 — getTransaction;
  • 'ngarkesë' — të dhënat që duhen kaluar në funksionin e duhur;
  • `Id i mesazhit` — ID e mesazhit në mënyrë që përgjigja të mund të identifikohet.

— Protokolli për ndërveprimin ndërmjet nyjeve

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

ku:

  • 'kodi' — kodi i mesazhit, për shembull 6 — PREPARE_NEW_BLOCK, 7 — BLOCK_VALID, 8 — BLOCK_COMMIT;
  • `versionProtocol` — versioni i protokollit, pasi nyjet me versione të ndryshme mund të ngrihen në rrjet dhe mund të funksionojnë ndryshe;
  • `seq` — identifikuesi i mesazhit;
  • "countChunk". и "Numri i pjesës". e nevojshme për ndarjen e mesazheve të mëdha;
  • "gjatësia". и 'ngarkesë' gjatësia dhe vetë të dhënat.

Meqenëse i kemi shtypur paraprakisht të dhënat, sistemi përfundimtar është shumë më i shpejtë se biblioteka `rlp` e Ethereum. Fatkeqësisht, ende nuk kemi mundur ta refuzojmë, pasi është e nevojshme të finalizohet kontrata smart, të cilën planifikojmë ta bëjmë në të ardhmen.

Nëse do të arrinim të arrinim shpejtësinë 35 000 transaksionet në sekondë, ne gjithashtu duhet t'i përpunojmë ato në kohën optimale. Meqenëse koha e përafërt e formimit të bllokut zgjat 30 sekonda, duhet të përfshijmë në bllok 1 000 000 transaksione, që do të thotë të dërgosh më shumë 100 MB të dhëna.

Fillimisht, ne përdorëm bibliotekën `ethereumjs-devp2p` për të komunikuar midis nyjeve, por ajo nuk mund të trajtonte kaq shumë të dhëna. Si rezultat, ne përdorëm bibliotekën `ws` dhe konfiguruam dërgimin e të dhënave binare nëpërmjet websocket. Natyrisht, ne kemi hasur edhe probleme gjatë dërgimit të paketave të mëdha të të dhënave, por i kemi ndarë në copa dhe tani këto probleme janë zhdukur.

Gjithashtu duke formuar një pemë Merkle dhe duke llogaritur hash 1 000 000 transaksionet kërkon rreth 10 sekonda e llogaritjes së vazhdueshme. Gjatë kësaj kohe, lidhja me të gjitha nyjet arrin të prishet. U vendos që kjo llogaritje të zhvendoset në një fije të veçantë.

Konkluzione:

Në fakt, gjetjet tona nuk janë të reja, por për disa arsye shumë ekspertë i harrojnë ato gjatë zhvillimit.

  • Përdorimi i programimit funksional në vend të programimit të orientuar nga objekti përmirëson produktivitetin.
  • Monoliti është më i keq se një arkitekturë shërbimi për një sistem produktiv NodeJS.
  • Përdorimi i 'punëtor_threads' për llogaritje të rënda përmirëson reagimin e sistemit, veçanërisht kur kemi të bëjmë me operacione i/o.
  • foleja unix është më e qëndrueshme dhe më e shpejtë se kërkesat http.
  • Nëse keni nevojë të transferoni shpejt të dhëna të mëdha përmes rrjetit, është më mirë të përdorni fole në internet dhe të dërgoni të dhëna binare, të ndara në copa, të cilat mund të përcillen nëse nuk arrijnë, dhe më pas të kombinohen në një mesazh.

Ju ftojmë ta vizitoni GitHub projekti: https://github.com/opporty-com/Plasma-Cash/tree/new-version

Artikulli u shkrua nga Aleksandër Nashivan, zhvillues i vjetër Clever Solution Inc.

Burimi: www.habr.com

Shto një koment