{"id":38856,"date":"2019-10-31T22:26:22","date_gmt":"2019-10-31T19:26:22","guid":{"rendered":"https:\/\/prohoster.info\/blog\/publichnyj-test-reshenie-dlya-privatnosti-i-masshtabiruemosti-v-efiriume\/"},"modified":"2019-10-31T22:26:22","modified_gmt":"2019-10-31T19:26:22","slug":"publichnyj-test-reshenie-dlya-privatnosti-i-masshtabiruemosti-v-efiriume","status":"publish","type":"post","link":"https:\/\/prohoster.info\/nl\/blog\/administrirovanie\/publichnyj-test-reshenie-dlya-privatnosti-i-masshtabiruemosti-v-efiriume","title":{"rendered":"Publieke test: oplossing voor privacy en schaalbaarheid met Ethereum","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p><b>Blockchain<\/b> is een innovatieve technologie die belooft veel gebieden van het menselijk leven te verbeteren. Het brengt echte processen en producten naar de digitale ruimte, garandeert snelheid en betrouwbaarheid van financi\u00eble transacties, verlaagt hun kosten en maakt het mogelijk om moderne DAPP-applicaties te cre\u00ebren met behulp van slimme contracten in gedecentraliseerde netwerken.<\/p>\n<p>Gezien de vele voordelen en diverse toepassingsgebieden van blockchain, lijkt het vreemd dat deze veelbelovende technologie nog niet in alle sectoren is doorgedrongen. Het probleem is dat moderne gedecentraliseerde blockchains niet genoeg schaalbaarheid bieden. Ethereum verwerkt ongeveer 20 transacties per seconde, wat niet voldoende is om te voldoen aan de behoeften van moderne dynamische bedrijven. Tegelijkertijd aarzelen bedrijven die blockchain-technologie gebruiken om Ethereum te verlaten vanwege de hoge mate van bescherming tegen hacks en netwerkstoringen.<\/p>\n<p>Om decentralisatie, veiligheid en schaalbaarheid in blockchain te waarborgen en zo de Schaalbaarheidsdilemma op te lossen, heeft het ontwikkelingsteam <noindex><a rel=\"nofollow\" href=\"https:\/\/opporty.com\/\">Opporty<\/a><\/noindex> Plasma Cash gecre\u00eberd \u2014 een zijketen die bestaat uit een slim contract en een priv\u00e9netwerk op basis van Node.js, dat periodiek zijn status naar de hoofdketen (Ethereum) doorgeeft.<\/p>\n<p><img decoding=\"async\" alt=\"Publieke test: oplossing voor privacy en schaalbaarheid met Ethereum\" src=\"\/wp-content\/uploads\/2019\/10\/02cc45df3474179d0936c2a86fb7dee3.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<h2>De sleutelprocessen in Plasma Cash<\/h2>\n<p>\n<b>1. <\/b>De gebruiker roept de functie van het slimme contract `deposit` aan en geeft het bedrag in ETH op dat hij\/zij in de Plasma Cash-token wil storten. De functie van het slimme contract cre\u00ebert de token en genereert daar een gebeurtenis voor.<\/p>\n<p><b>2. <\/b>Plasma Cash-nodes die zijn ingeschreven op de gebeurtenissen van het slimme contract, ontvangen de gebeurtenis van de creatie van de storting en voegen de transactie voor de creatie van de token toe aan de pool.<\/p>\n<p><b>3. <\/b>Periodiek nemen speciale Plasma Cash-nodes alle transacties uit de pool (tot 1 miljoen) en vormen daar een blok van, berekenen de Merkle-boom en dus de hash. Dit blok wordt naar andere nodes verzonden voor verificatie. Nodes controleren of de Merkle-hash geldig is, of de transacties geldig zijn (bijvoorbeeld of de afzender van de token de eigenaar ervan is). Na verificatie van het blok roept de node de functie `submitBlock` van het slimme contract aan, die het nummer en de Merkle-hash van het blok in de hoofdketen opslaat. Het slimme contract genereert een gebeurtenis over het succesvolle toevoegen van het blok. Transacties worden uit de pool verwijderd. <\/p>\n<p><b>4. <\/b>Nodes that received the submit event of the block begin to apply the transactions that were added to the block.<\/p>\n<p><b>5. <\/b>At some point, the owner (or non-owner) of the token wants to withdraw it from Plasma Cash. To do this, they call the `startExit` function, passing in information about the last 2 transactions for the token that confirm they are indeed the owner of the token. The smart contract, using the Merkle hash, verifies the presence of the transactions in the blocks and sends the token for withdrawal, which will occur in two weeks.<\/p>\n<p><b>6. <\/b>If the token withdrawal operation occurred with violations (the token was spent after the withdrawal procedure began or the token was already not owned before withdrawal), the owner of the token can dispute the withdrawal within two weeks.<\/p>\n<p><img decoding=\"async\" alt=\"Publieke test: oplossing voor privacy en schaalbaarheid met Ethereum\" src=\"\/wp-content\/uploads\/2019\/10\/0626ca6b010eb847175dbfb0b6d7b357.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<\/p>\n<h2>Privacy is achieved in two ways.<\/h2>\n<p>\n<b>1. <\/b>The root chain knows nothing about the transactions that are formed and transmitted within the child chain. Public remains the information about who deposited and withdrew ETH to\/from Plasma Cash.<\/p>\n<p><b>2. <\/b>The child chain allows for anonymous transactions using zk-SNARKs.<\/p>\n<h2>Technologische stack<\/h2>\n<p><\/p>\n<ul>\n<li>NodeJS<\/li>\n<li>Redis<\/li>\n<li>Ethereum<\/li>\n<li>Solid<\/li>\n<\/ul>\n<p><\/p>\n<h2>Testen <\/h2>\n<p>\nIn developing Plasma Cash, we tested the system\u2019s performance and received the following results:<\/p>\n<ul>\n<li>up to 35,000 transactions per second are added to the pool;<\/li>\n<li>up to 1,000,000 transactions can be stored in a block.<\/li>\n<\/ul>\n<p>\nTests were conducted on the following 3 servers:<\/p>\n<p><i>1. Intel Core i7-6700 Quad-Core Skylake incl. NVMe SSD \u2014 512 GB, 64 GB DDR4 RAM<\/i><br \/>\n 3 validating Plasma Cash nodes were launched.<\/p>\n<p><i>2. AMD Ryzen 7 1700X Octa-Core 'Summit Ridge' (Zen), SATA SSD \u2014 500 GB, 64 GB DDR4 RAM<\/i><br \/>\n A Ropsten testnet ETH node was launched.<br \/>\n 3 validating Plasma Cash nodes were launched.<\/p>\n<p><i>3. Intel Core i9-9900K Octa-Core incl. NVMe SSD \u2014 1 TB, 64 GB DDR4 RAM<\/i><br \/>\n 1 submit Plasma Cash node was launched.<br \/>\n 3 validating Plasma Cash nodes were launched.<br \/>\n A test was run to add transactions to the Plasma Cash network.<\/p>\n<p><b>Kortom: <\/b>10 Plasma Cash nodes in a private network.<\/p>\n<h3>Test 1<\/h3>\n<p>\nThere is a limit of 1 million transactions per block. Therefore, 1 million transactions go into 2 blocks (since the system can capture some transactions and submit them while they are being sent).<\/p>\n<p><center><div class=\"youtube-placeholder\" data-id=\"pKwqyGkEgdQ\" onclick=\"loadVideo(this)\">\r\n        <img decoding=\"async\" src=\"https:\/\/img.youtube.com\/vi\/pKwqyGkEgdQ\/hqdefault.jpg\" alt=\"Video afspelen\" loading=\"lazy\" width=\"480\" height=\"360\" style=\"width:100%;height:auto;\">\r\n        <div class=\"play-button\"><\/div>\r\n    <\/div><\/center><br \/>\nInitial state: last block #7; 1 million transactions and tokens are stored in the database.<\/p>\n<p>00:00 \u2014 script for generating transactions started<br \/>\n01:37 \u2014 1 million transactions created and sending to node started<br \/>\n01:46 \u2014 the submit node took 240k transactions from the pool and forms block #8. We also see that 320k transactions are added to the pool in 10 seconds.<br \/>\n01:58 \u2014 block #8 signed and sent for validation.<br \/>\n02:03 \u2014 blok #8 gevalideerd en de functie `submitBlock` van het smart contract aangeroepen met de Merkle-hash en bloknummer.<br \/>\n02:10 \u2014 de demo-script is gestopt, dat 1 miljoen transacties in 32 seconden heeft verzonden.<br \/>\n02:33 \u2014 knooppunten beginnen informatie te ontvangen dat blok #8 aan de hoofdketen is toegevoegd en starten met het uitvoeren van 240k transacties.<br \/>\n02:40 \u2014 240k transacties zijn uit de pool verwijderd, die al in blok #8 zitten.<br \/>\n02:56 \u2014 de submit-knoop heeft de resterende 760k transacties uit de pool genomen en begonnen met het berekenen van de Merkle-hash en het ondertekenen van blok #9.<br \/>\n03:20 \u2014 alle knooppunten bevatten 1 miljoen 240k transacties en tokens.<br \/>\n03:35 \u2014 blok #9 is ondertekend en wordt ter validatie naar andere knooppunten gestuurd. <br \/>\n03:41 \u2014 er is een netwerkfout opgetreden.<br \/>\n04:40 \u2014 de wachttijd voor de validatie van blok #9 is vanwege time-out be\u00ebindigd.<br \/>\n04:54 \u2014 de submit-knoop heeft de resterende 760k transacties uit de pool genomen en begonnen met het berekenen van de Merkle-hash en het ondertekenen van blok #9.<br \/>\n05:32 \u2014 blok #9 is ondertekend en wordt ter validatie naar andere knooppunten gestuurd.<br \/>\n05:53 \u2014 blok #9 is gevalideerd en verzonden naar de hoofdketen.<br \/>\n06:17 \u2014 knooppunten beginnen informatie te ontvangen dat blok #9 aan de hoofdketen is toegevoegd en starten met het uitvoeren van 760k transacties.<br \/>\n06:47 \u2014 de pool is opgeschoond van transacties die in blok #9 zitten.<br \/>\n09:06 \u2014 alle knooppunten bevatten 2 miljoen transacties en tokens.<\/p>\n<h3>Test 2<\/h3>\n<p>\nEr geldt een limiet van 350k per blok. Dit resulteert in 3 blokken.<\/p>\n<p><center><div class=\"youtube-placeholder\" data-id=\"mpTfTPKYRIc\" onclick=\"loadVideo(this)\">\r\n        <img decoding=\"async\" src=\"https:\/\/img.youtube.com\/vi\/mpTfTPKYRIc\/hqdefault.jpg\" alt=\"Video afspelen\" loading=\"lazy\" width=\"480\" height=\"360\" style=\"width:100%;height:auto;\">\r\n        <div class=\"play-button\"><\/div>\r\n    <\/div><\/center><br \/>\nIniti\u00eble staat: laatste blok #9; er zijn 2 miljoen transacties en tokens in de database opgeslagen.<\/p>\n<p>00:00 \u2014 het script voor het genereren van transacties is al gestart.<br \/>\n00:44 \u2014 1 miljoen transacties zijn aangemaakt en de verzending naar de knoop is begonnen.<br \/>\n00:56 \u2014 de submit-knoop heeft 320k transacties uit de pool genomen en vormt blok #10. We zien ook dat er 320k transacties aan de pool worden toegevoegd in 10 seconden.<br \/>\n01:12 \u2014 blok #10 is ondertekend en wordt naar andere knooppunten verzonden voor validatie.<br \/>\n01:18 \u2014 de demo-script is gestopt, dat 1 miljoen transacties in 34 seconden heeft verzonden.<br \/>\n01:20 \u2014 blok #10 is gevalideerd en verzonden naar de hoofdketen. <br \/>\n01:51 \u2014 alle knooppunten hebben informatie ontvangen uit de hoofdketen dat blok #10 is toegevoegd, en beginnen 320k transacties toe te passen.<br \/>\n02:01 \u2014 de pool is opgeschoond van 320k transacties die in blok #10 zijn toegevoegd.<br \/>\n02:15 \u2014 de submit-knoop heeft 350k transacties uit de pool genomen en vormt blok #11.<br \/>\n02:34 \u2014 blok #11 is ondertekend en wordt naar andere knooppunten verzonden voor validatie.<br \/>\n02:51 \u2014 blok #11 is gevalideerd en verzonden naar de hoofdketen. <br \/>\n02:55 \u2014 de laatste knoop heeft de transacties uit blok #10 uitgevoerd.<br \/>\n10:59 \u2014 de transactie met de indienen van blok #9 duurde erg lang in de rootketen, maar deze is afgerond en alle knooppunten hebben hier informatie over ontvangen en begonnen met het verwerken van 350k transacties.<br \/>\n11:05 \u2014 de pool is opgeschoond met 320k transacties, die zijn toegevoegd aan blok #11.<br \/>\n12:10 \u2014 alle knooppunten bevatten 1 miljoen 670k transacties en tokens.<br \/>\n12:17 \u2014 de submit-knooppunt nam 330k transacties uit de pool en vormt blok #12.<br \/>\n12:32 \u2014 blok #12 is ondertekend en wordt naar andere knooppunten gestuurd voor validatie.<br \/>\n12:39 \u2014 blok #12 is gevalideerd en naar de rootketen gestuurd. <br \/>\n13:44 \u2014 alle knooppunten hebben informatie uit de rootketen ontvangen dat blok #12 is toegevoegd en beginnen met het toepassen van 330k transacties.<br \/>\n14:50 \u2014 alle knooppunten bevatten 2 miljoen transacties en tokens.<\/p>\n<h3>Test 3<\/h3>\n<p>\nOp de eerste en tweede servers is \u00e9\u00e9n validatieknooppunt vervangen door een submit-knooppunt. <\/p>\n<p><center><div class=\"youtube-placeholder\" data-id=\"w5QHab3heIc\" onclick=\"loadVideo(this)\">\r\n        <img decoding=\"async\" src=\"https:\/\/img.youtube.com\/vi\/w5QHab3heIc\/hqdefault.jpg\" alt=\"Video afspelen\" loading=\"lazy\" width=\"480\" height=\"360\" style=\"width:100%;height:auto;\">\r\n        <div class=\"play-button\"><\/div>\r\n    <\/div><\/center><br \/>\nIniti\u00eble staat: laatste blok #84; er zijn 0 transacties en tokens in de database opgeslagen.<\/p>\n<p>00:00 \u2014 3 scripts gestart die elk 1 miljoen transacties genereren en verzenden.<br \/>\n01:38 \u2014 1 miljoen transacties zijn aangemaakt en de verzending naar submit-knooppunt #3 is begonnen.<br \/>\n01:50 \u2014 submit-knooppunt #3 nam 330k transacties uit de pool en vormt blok #85 (f21). Ook zien we dat er 350k transacties aan de pool worden toegevoegd in 10 seconden.<br \/>\n01:53 \u2014 1 miljoen transacties zijn aangemaakt en de verzending naar submit-knooppunt #1 is begonnen.<br \/>\n01:50 \u2014 submit-knooppunt #3 nam 330k transacties uit de pool en vormt blok #85 (f21). Ook zien we dat er 350k transacties aan de pool worden toegevoegd in 10 seconden.<br \/>\n02:01 \u2014 submit-knooppunt #1 nam 250k transacties uit de pool en vormt blok #85 (65e).<br \/>\n02:06 \u2014 blok #85 (f21) is ondertekend en wordt naar andere knooppunten gestuurd voor validatie.<br \/>\n02:08 \u2014 de demo-script op server #3 is gestopt, die 1 miljoen transacties heeft verzonden in 30 seconden.<br \/>\n02:14 \u2014 blok #85 (f21) is gevalideerd en naar de rootketen gestuurd. <br \/>\n02:19 \u2014 blok #85 (65e) is ondertekend en wordt naar andere knooppunten gestuurd voor validatie.<br \/>\n02:22 \u2014 1 miljoen transacties zijn aangemaakt en de verzending naar submit-knooppunt #2 is begonnen.<br \/>\n02:27 \u2014 blok #85 (65e) is gevalideerd en naar de rootketen gestuurd. <br \/>\n02:29 \u2014 submit-knooppunt #2 nam 111855 transacties uit de pool en vormt blok #85 (256).<br \/>\n02:36 \u2014 blok #85 (256) is ondertekend en wordt naar andere knooppunten gestuurd voor validatie.<br \/>\n02:36 \u2014 de demo-script op server #1 is gestopt, die 1 miljoen transacties heeft verzonden in 42,5 seconden.<br \/>\n02:38 \u2014 blok #85 (256) is gevalideerd en naar de rootketen gestuurd.<br \/>\n03:08 \u2014 de demo-script op server #2 is gestopt, die 1 miljoen transacties heeft verzonden in 47 seconden. <br \/>\n03:38 \u2014 alle knooppunten hebben informatie uit de rootketen ontvangen dat blokken #85 (f21), #86 (65e), #87 (256) zijn toegevoegd en beginnen met het toepassen van 330k, 250k, 111855 transacties.<br \/>\n03:49 \u2014 de pool is opgeschoond met 330k, 250k, 111855 transacties die zijn toegevoegd aan blokken #85 (f21), #86(65e), #87(256)<br \/>\n03:59 \u2014 de submit node #1 heeft 888145 transacties uit de pool genomen en vormt blok #88 (214), de submit node #2 heeft 750k transacties uit de pool genomen en vormt blok #88 (50a), de submit node #3 heeft 670k transacties uit de pool genomen en vormt blok #88 (d3b)<br \/>\n04:44 \u2014 blok #88 (d3b) is ondertekend en wordt naar andere nodes gestuurd voor validatie<br \/>\n04:58 \u2014 blok #88 (214) is ondertekend en wordt naar andere nodes gestuurd voor validatie<br \/>\n05:11 \u2014 blok #88 (50a) is ondertekend en wordt naar andere nodes gestuurd voor validatie<br \/>\n05:11 \u2014 blok #85 (d3b) is gevalideerd en naar de wortelketen gestuurd <br \/>\n05:36 \u2014 blok #85 (214) is gevalideerd en naar de wortelketen gestuurd <br \/>\n05:43 \u2014 alle nodes hebben uit de wortelketen informatie ontvangen dat blokken #88 (d3b), #89(214) zijn toegevoegd en beginnen met het toepassen van 670k, 750k transacties<br \/>\n06:50 \u2014 door een verbindingsonderbreking is blok #85 (50a) niet gevalideerd<br \/>\n06:55 \u2014 de submit node #2 heeft 888145 transacties uit de pool genomen en vormt blok #90 (50a)<br \/>\n08:14 \u2014 blok #90 (50a) is ondertekend en wordt naar andere nodes gestuurd voor validatie<br \/>\n09:04 \u2014 blok #90 (50a) is gevalideerd en naar de wortelketen gestuurd <br \/>\n11:23 \u2014 alle nodes hebben uit de wortelketen informatie ontvangen dat blok #90 (50a) is toegevoegd, en beginnen met het toepassen van 888145 transacties. Inmiddels heeft server #3 al transacties uit blokken #88 (d3b), #89(214) toegepast<br \/>\n12:11 \u2014 alle pools zijn leeg<br \/>\n13:41 \u2014 alle nodes van server #3 bevatten 3 miljoen transacties en tokens<br \/>\n14:35 \u2014 alle nodes van server #1 bevatten 3 miljoen transacties en tokens<br \/>\n19:24 \u2014 alle nodes van server #2 bevatten 3 miljoen transacties en tokens <\/p>\n<h2>Obstakels<\/h2>\n<p>\nTijdens de ontwikkeling van Plasma Cash stuitten we op de volgende problemen, die we geleidelijk hebben opgelost en nog steeds oplossen:<\/p>\n<p><b>1.<\/b> Conflict tussen verschillende functies van het systeem. Bijvoorbeeld, de functie om transacties aan de pool toe te voegen blokkeerde de werking van de submit en validatie van blokken, en vice versa, wat leidde tot een vertraging in de snelheid.<\/p>\n<p><b>2. <\/b>Het was niet meteen duidelijk hoe een enorme hoeveelheid transacties te verzenden en tegelijkertijd de datakosten te minimaliseren.<\/p>\n<p><b>3. <\/b>Het was niet duidelijk hoe en waar gegevens op te slaan om hoge resultaten te bereiken.<\/p>\n<p><b>4. <\/b>Het was niet duidelijk hoe het netwerk tussen nodes te organiseren, aangezien de grootte van een blok met 1 miljoen transacties ongeveer 100 MB bedraagt.<\/p>\n<p><b>5.<\/b> Werken in een single-threaded modus verstoort de verbinding tussen nodes wanneer er lange berekeningen plaatsvinden (bijvoorbeeld, het bouwen van een Merkle-boom en het berekenen van de hash).<\/p>\n<h2>Hoe hebben we dit allemaal aangepakt?<\/h2>\n<p>\nDe eerste versie van de Plasma Cash-knooppunt was een soort combinatie die alles tegelijk kon doen: transacties ontvangen, blokken indienen en valideren, en een API bieden voor gegevens toegang. Aangezien NodeJS oorspronkelijk enkelvoudig (single-threaded) is, blokkeerde de zware functie voor het berekenen van de Merkle-boom de functie voor het toevoegen van transacties. We zagen twee mogelijke oplossingen voor dit probleem:<\/p>\n<p><b>1. <\/b>Meerdere NodeJS-processen starten, waarbij elk specifieke functies uitvoert.<\/p>\n<p><b>2. <\/b>Gebruik maken van worker_threads en een deel van de code naar threads verplaatsen.<\/p>\n<p>Uiteindelijk hebben we beide opties tegelijkertijd gebruikt: we hebben \u00e9\u00e9n knooppunt logisch verdeeld in 3 delen die apart kunnen werken maar tegelijkertijd synchroon blijven.<\/p>\n<p><b>1.<\/b> Een submissieknooppunt dat transacties in de pool accepteert en verantwoordelijk is voor het cre\u00ebren van blokken.<\/p>\n<p><b>2.<\/b> Een validatieknooppunt dat de geldigheid van knooppunten controleert.<\/p>\n<p><b>3. <\/b>API-knooppunt \u2014 biedt een API voor gegevens toegang.<\/p>\n<p>Elke knooppunt kan via een unix-socket worden aangesloten via de cli.<\/p>\n<p>Zware bewerkingen, zoals het berekenen van de Merkle-boom, hebben we naar een aparte thread verplaatst.<\/p>\n<p>Op deze manier hebben we ervoor gezorgd dat alle functies van Plasma Cash tegelijkertijd en zonder storingen normaal functioneren.<\/p>\n<p>Zodra het systeem functioneel was, begonnen we met het testen van de snelheid en kregen helaas ontevredenstellende resultaten: 5.000 transacties per seconde en tot 50.000 transacties per blok. We moesten achterhalen wat er verkeerd was ge\u00efmplementeerd.<\/p>\n<p>Eerst testten we het communicatie-mechanisme met Plasma Cash om de piekcapaciteit van het systeem te achterhalen. Eerder hebben we vermeld dat het Plasma Cash-knooppunt een unix-socketinterface biedt. Aanvankelijk was het tekstgebaseerd. json-objecten werden verzonden met `JSON.parse()` en `JSON.stringify()`. <\/p>\n<pre><code class=\"plaintext\">{\"action\": \"sendTransaction\",\"payload\":{ \"prevHash\": \"0x8a88cc4217745fd0b4eb161f6923235da10593be66b841d47da86b9cd95d93e0\",\"prevBlock\": 41,\"tokenId\": \"57570139642005649136210751546585740989890521125187435281313126554130572876445\",\"newOwner\": \"0x200eabe5b26e547446ae5821622892291632d4f4\",\"type\": \"pay\",\"data\": \"\",\"signature\": \"0xd1107d0c6df15e01e168e631a386363c72206cb75b233f8f3cf883134854967e1cd9b3306cc5c0ce58f0a7397ae9b2487501b56695fe3a3c90ec0f61c7ea4a721c\"}}\n<\/code><\/pre>\n<p>\nWe hebben de snelheid van de verzending van zulke objecten gemeten en kregen ~ 130k per seconde. We hebben geprobeerd de standaard functies voor json-werking te vervangen, maar de prestaties verbeterden niet. De V8-motor moet goed geoptimaliseerd zijn voor deze operaties.<\/p>\n<p>Werken met transacties, tokens en blokken gebeurden bij ons via klassen. Bij het aanmaken van dergelijke klassen daalde de prestaties met 50%, wat aangeeft dat OOP niet geschikt voor ons is. We moesten alles herschrijven naar een puur functionele aanpak.<\/p>\n<h2>Schrijven naar de database<\/h2>\n<p>\nAanvankelijk werd Redis gekozen voor gegevensopslag als een van de meest performante oplossingen die aan onze eisen voldoet: key-value opslag, werken met hash-tabellen, verzamelingen. We hebben redis-benchmark uitgevoerd en kregen ~80k operaties per seconde in mode van 1 pipelining.<\/p>\n<p>Voor hoge prestaties hebben we Redis finetuned: <\/p>\n<ul>\n<li>We hebben een unix socket verbinding ingesteld.<\/li>\n<li>We hebben de opslag van de staat op schijf uitgeschakeld (voor betrouwbaarheid kan er een replica worden ingesteld die de opslag op schijf uitvoert).<\/li>\n<\/ul>\n<p>\nIn Redis is een pool een hash-tabel, omdat we de mogelijkheid nodig hebben om alle transacties met \u00e9\u00e9n verzoek te krijgen en transacties \u00e9\u00e9n voor \u00e9\u00e9n te verwijderen. We hebben geprobeerd een gewone lijst te gebruiken, maar die werkt trager bij het uitladen van de volledige lijst. <\/p>\n<p>Bij het gebruik van de standaard NodeJS Redis bibliotheek behaalden we 18k transacties per seconde. De snelheid daalde met 9 keer. <\/p>\n<p>Aangezien de benchmark ons duidelijk mogelijkheden van 5 keer meer toonde, begonnen we te optimaliseren. We schakelden over naar de ioredis bibliotheek en behaalden nu al 25k per seconde. We voegden transacties \u00e9\u00e9n voor \u00e9\u00e9n toe met de `hset` opdracht. Op die manier genereerden we veel verzoeken naar Redis. Het idee ontstond om transacties in batches samen te voegen en ze met \u00e9\u00e9n opdracht `hmset` te verzenden. Resultaat \u2014 32k per seconde. <\/p>\n<p>Om verschillende redenen, die we hieronder zullen beschrijven, werken we met gegevens met behulp van `Buffer` en, zoals bleek, als we het omzetten naar tekst (`buffer.toString('hex')`) voordat we schrijven, kunnen we extra prestaties behalen. Op deze manier slaagden we erin de snelheid te verhogen tot 35k per seconde. Op dit moment hebben we besloten om verdere optimalisatie te pauzeren.<\/p>\n<p>We moesten overschakelen naar een binaire protocol omdat:<\/p>\n<p><b>1. <\/b>Het systeem berekent vaak hashes, handtekeningen, enzovoorts, en daarvoor zijn gegevens in `Buffer` nodig.<\/p>\n<p><b>2.<\/b> Bij verzending tussen services wegen binaire gegevens minder dan tekst. Bijvoorbeeld, bij het verzenden van een blok met 1 miljoen transacties kunnen de gegevens in tekst meer dan 300 megabyte in beslag nemen.<\/p>\n<p><b>3.<\/b> Voortdurende conversie van gegevens heeft invloed op de prestaties.<\/p>\n<p>Daarom hebben we ons eigen binaire gegevensopslag- en -overdrachtsprotocol gebaseerd op de geweldige bibliotheek `binary-data` genomen.<\/p>\n<p>Het resultaat is dat we de volgende datastructuren hebben gekregen:<\/p>\n<h3> \u2014 Transactie<\/h3>\n<p><\/p>\n<pre><code class=\"plaintext\">  ```json\n  {\n    prevHash: BD.types.buffer(20),\n    prevBlock: BD.types.uint24le,\n    tokenId: BD.types.string(null),\n    type: BD.types.uint8,\n    newOwner: BD.types.buffer(20),\n    dataLength: BD.types.uint24le,\n    data: BD.types.buffer(({current}) =&gt; current.dataLength),\n    signature: BD.types.buffer(65),\n    hash: BD.types.buffer(32),\n    blockNumber: BD.types.uint24le,\n    timestamp: BD.types.uint48le,\n  }\n  ```\n<\/code><\/pre>\n<p><\/p>\n<h3> \u2014 Token<\/h3>\n<p><\/p>\n<pre><code class=\"plaintext\">  ```json\n  {\n    id: BD.types.string(null),\n    owner: BD.types.buffer(20),\n    block: BD.types.uint24le,\n    amount: BD.types.string(null),\n  }\n  ```\n<\/code><\/pre>\n<p><\/p>\n<h3> \u2014 Blok<\/h3>\n<p><\/p>\n<pre><code class=\"plaintext\">  ```json\n  {\n    number: BD.types.uint24le,\n    merkleRootHash: BD.types.buffer(32),\n    signature: BD.types.buffer(65),\n    countTx: BD.types.uint24le,\n    transactions: BD.types.array(Transaction.Protocol, ({current}) =&gt; current.countTx),\n    timestamp: BD.types.uint48le,\n  }\n  ```\n<\/code><\/pre>\n<p>\nMet de gewone commando's `BD.encode(block, Protocol).slice();` en ` BD.decode(buffer, Protocol)` zetten we de gegevens om naar `Buffer` voor opslag in Redis of verzending naar een andere node en halen we de gegevens weer terug.<\/p>\n<p>We hebben ook 2 binaire protocollen voor gegevensoverdracht tussen diensten:<\/p>\n<p><i> \u2014 Protocol voor interactie met Plasma Node via unix socket<\/i><\/p>\n<pre><code class=\"plaintext\">  ```json\n  {\n    type: BD.types.uint8,\n    messageId: BD.types.uint24le,\n    error: BD.types.uint8,\n    length: BD.types.uint24le,\n    payload: BD.types.buffer(({node}) =&gt; node.length)\n  }\n  ```\n<\/code><\/pre>\n<p>\n waarbij:<\/p>\n<ul>\n<li> <b>`type`<\/b> \u2014 de actie die moet worden uitgevoerd, bijvoorbeeld, 1 \u2014 sendTransaction, 2 \u2014 getTransaction;<\/li>\n<li> <b>`payload`<\/b> \u2014 de gegevens die naar de overeenkomstige functie moeten worden verzonden;<\/li>\n<li> <b>`messageId`<\/b> \u2014 het id van het bericht, zodat het antwoord kan worden ge\u00efdentificeerd. <\/li>\n<\/ul>\n<p>\n<i> \u2014 Protocol voor interactie tussen nodes<\/i><\/p>\n<pre><code class=\"plaintext\">  ```json\n  {\n    code: BD.types.uint8,\n    versionProtocol: BD.types.uint24le,\n    seq: BD.types.uint8,\n    countChunk: BD.types.uint24le,\n    chunkNumber: BD.types.uint24le,\n    length: BD.types.uint24le,\n    payload: BD.types.buffer(({node}) =&gt; node.length)\n  }\n  ```\n<\/code><\/pre>\n<p>\n waarbij:<\/p>\n<ul>\n<li> <b>`code`<\/b> \u2014 de code van het bericht, bijvoorbeeld 6 \u2014 PREPARE_NEW_BLOCK, 7 \u2014 BLOCK_VALID, 8 \u2014 BLOCK_COMMIT;<\/li>\n<li> <b>`versionProtocol`<\/b> \u2014 de versie van het protocol, omdat er nodes in het netwerk kunnen zijn met verschillende versies die anders kunnen werken;<\/li>\n<li> <b>`seq`<\/b> \u2014 de identificatie van het bericht;<\/li>\n<li> <b>`countChunk`<\/b> en <b>`chunkNumber`<\/b> nodig voor het splitsen van grote berichten;<\/li>\n<li> <b>`length`<\/b> en <b>`payload`<\/b> de lengte en de gegevens zelf.<\/li>\n<\/ul>\n<p>\nOmdat we de gegevens van tevoren hebben getypeerd, werkt het eind systeem veel sneller dan de `rlp` bibliotheek van Ethereum. Helaas is het ons nog niet gelukt om ervan af te stappen, omdat we het smart contract moeten aanpassen, wat we van plan zijn te doen in de toekomst.<\/p>\n<p>Als we erin geslaagd zijn om snelheid te bereiken <b>35 000<\/b> transacties per seconde, moeten we ze ook binnen een optimale tijd verwerken. Aangezien de geschatte tijd voor het vormen van een blok 30 seconden bedraagt, moeten we opnemen in het blok <b>1 000 000<\/b> transacties, wat betekent dat meer dan <b>100<\/b> mb aan gegevens wordt verzonden. <\/p>\n<p>In het begin gebruikten we de `ethereumjs-devp2p` bibliotheek voor de communicatie tussen nodes, maar deze kon niet omgaan met zo'n hoeveelheid gegevens. Daarom maakten we gebruik van de `ws` bibliotheek en configureerden we de verzending van binaire gegevens via WebSocket. Natuurlijk stuiten we ook op problemen bij het verzenden van grote pakketten gegevens, maar we hebben ze in chunks opgedeeld en nu zijn die problemen er niet meer.<\/p>\n<p>Ook het vormen van de Merkle-boom en het berekenen van de hash <b>1 000 000<\/b> transacties vereist ongeveer<b> 10<\/b> seconden aan continue berekening. In die tijd kan de verbinding met alle nodes verbroken raken. Het werd besloten om deze berekening naar een aparte thread te verplaatsen.<\/p>\n<h2>Conclusies:<\/h2>\n<p>\nIn feite zijn onze conclusies niet nieuw, maar om de een of andere reden vergeten veel specialisten deze tijdens de ontwikkeling. <\/p>\n<ul>\n<li>Het gebruik van Functionele Programmeren in plaats van Objectgeori\u00ebnteerd Programmeren verhoogt de prestaties.<\/li>\n<li>Een monolith is slechter dan een service-architectuur voor een productieve NodeJS-systeem.<\/li>\n<li>Het gebruik van `worker_threads` voor zware berekeningen verbetert de responsiviteit van het systeem, vooral bij het werken met I\/O-operaties.<\/li>\n<li>unix-socket is stabieler en sneller dan http-verzoeken.<\/li>\n<li>Als je snel grote gegevens over het netwerk moet verzenden, is het beter om WebSockets te gebruiken en binaire gegevens te verzenden, opgesplitst in chunks, die opnieuw kunnen worden verzonden als ze niet aankomen, om ze vervolgens weer tot \u00e9\u00e9n bericht te combineren.<\/li>\n<\/ul>\n<p>\nWe nodigen je uit om <b>GitHub<\/b> van het project: <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/opporty-com\/Plasma-Cash\/tree\/new-version\">https:\/\/github.com\/opporty-com\/Plasma-Cash\/tree\/new-version<\/a><\/noindex><\/p>\n<p>Dit artikel is mede geschreven door <i>Alexander Nashivan<\/i>, senior ontwikkelaar bij <noindex><a rel=\"nofollow\" href=\"https:\/\/clever-solution.com\/\">Clever Solution Inc<\/a><\/noindex>.<br \/>\n<br \/>Bron: <a content=\"nofollow\" rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/post\/471096\/\">habr.com<\/a><\/p>","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>\u0411\u043b\u043e\u043a\u0447\u0435\u0439\u043d \u2014 \u0438\u043d\u043d\u043e\u0432\u0430\u0446\u0438\u043e\u043d\u043d\u0430\u044f \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u044f, \u043e\u0431\u0435\u0449\u0430\u044e\u0449\u0430\u044f \u0443\u043b\u0443\u0447\u0448\u0438\u0442\u044c \u043c\u043d\u043e\u0433\u0438\u0435 \u0441\u0444\u0435\u0440\u044b \u0447\u0435\u043b\u043e\u0432\u0435\u0447\u0435\u0441\u043a\u043e\u0439 \u0436\u0438\u0437\u043d\u0438. \u041e\u043d\u0430 \u043f\u0435\u0440\u0435\u043d\u043e\u0441\u0438\u0442 \u0440\u0435\u0430\u043b\u044c\u043d\u044b\u0435 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u044b \u0438 \u043f\u0440\u043e\u0434\u0443\u043a\u0442\u044b \u0432 \u0446\u0438\u0444\u0440\u043e\u0432\u043e\u0435 \u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432\u043e, \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0432\u0430\u0435\u0442 \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u044c \u0438 \u043d\u0430\u0434\u0435\u0436\u043d\u043e\u0441\u0442\u044c \u0444\u0438\u043d\u0430\u043d\u0441\u043e\u0432\u044b\u0445 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0439, \u0441\u043d\u0438\u0436\u0430\u0435\u0442 \u0438\u0445 \u0441\u0442\u043e\u0438\u043c\u043e\u0441\u0442\u044c, \u0430 \u0442\u0430\u043a\u0436\u0435 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c \u0441\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 DAPP \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u0438\u043d\u0442\u0435\u043b\u043b\u0435\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u044b\u0445 \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u043e\u0432 \u0432 \u0434\u0435\u0446\u0435\u043d\u0442\u0440\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u0441\u0435\u0442\u044f\u0445. \u0423\u0447\u0438\u0442\u044b\u0432\u0430\u044f \u043c\u043d\u043e\u0433\u043e\u0447\u0438\u0441\u043b\u0435\u043d\u043d\u044b\u0435 \u043f\u0440\u0435\u0438\u043c\u0443\u0449\u0435\u0441\u0442\u0432\u0430 \u0438 \u0440\u0430\u0437\u043d\u043e\u043e\u0431\u0440\u0430\u0437\u043d\u044b\u0435 \u0441\u0444\u0435\u0440\u044b \u043f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0431\u043b\u043e\u043a\u0447\u0435\u0439\u043d, \u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u044c\u0441\u044f \u0441\u0442\u0440\u0430\u043d\u043d\u044b\u043c, \u0447\u0442\u043e \u044d\u0442\u0430 [&hellip;]<\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"author":1,"featured_media":29146,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[688],"tags":[],"class_list":["post-38856","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-administrirovanie"],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 5.0.3 - aioseo.com -->\n\t<meta name=\"description\" content=\"\u0411\u043b\u043e\u043a\u0447\u0435\u0439\u043d \u2014 \u0438\u043d\u043d\u043e\u0432\u0430\u0446\u0438\u043e\u043d\u043d\u0430\u044f \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u044f, \u043e\u0431\u0435\u0449\u0430\u044e\u0449\u0430\u044f \u0443\u043b\u0443\u0447\u0448\u0438\u0442\u044c \u043c\u043d\u043e\u0433\u0438\u0435 \u0441\u0444\u0435\u0440\u044b \u0447\u0435\u043b\u043e\u0432\u0435\u0447\u0435\u0441\u043a\u043e\u0439 \u0436\u0438\u0437\u043d\u0438.\" \/>\n\t<meta name=\"robots\" content=\"max-image-preview:large\" \/>\n\t<meta name=\"author\" content=\"Yuri Gagarin\"\/>\n\t<link rel=\"canonical\" href=\"https:\/\/prohoster.info\/nl\/blog\/administrirovanie\/publichnyj-test-reshenie-dlya-privatnosti-i-masshtabiruemosti-v-efiriume\" \/>\n\t\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.3\" \/>\n\t\t<meta property=\"og:locale\" content=\"nl_NL\" \/>\n\t\t<meta property=\"og:site_name\" content=\"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b\" \/>\n\t\t<meta property=\"og:type\" content=\"article\" \/>\n\t\t<meta property=\"og:title\" content=\"\ud83e\udd47\u041f\u0443\u0431\u043b\u0438\u0447\u043d\u044b\u0439 \u0442\u0435\u0441\u0442: \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u0434\u043b\u044f \u043f\u0440\u0438\u0432\u0430\u0442\u043d\u043e\u0441\u0442\u0438 \u0438 \u043c\u0430\u0441\u0448\u0442\u0430\u0431\u0438\u0440\u0443\u0435\u043c\u043e\u0441\u0442\u0438 \u0432 \u042d\u0444\u0438\u0440\u0438\u0443\u043c\u0435 | ProHoster\" \/>\n\t\t<meta property=\"og:description\" content=\"\u0411\u043b\u043e\u043a\u0447\u0435\u0439\u043d \u2014 \u0438\u043d\u043d\u043e\u0432\u0430\u0446\u0438\u043e\u043d\u043d\u0430\u044f \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u044f, \u043e\u0431\u0435\u0449\u0430\u044e\u0449\u0430\u044f \u0443\u043b\u0443\u0447\u0448\u0438\u0442\u044c \u043c\u043d\u043e\u0433\u0438\u0435 \u0441\u0444\u0435\u0440\u044b \u0447\u0435\u043b\u043e\u0432\u0435\u0447\u0435\u0441\u043a\u043e\u0439 \u0436\u0438\u0437\u043d\u0438.\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/nl\/blog\/administrirovanie\/publichnyj-test-reshenie-dlya-privatnosti-i-masshtabiruemosti-v-efiriume\" \/>\n\t\t<meta property=\"og:image\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:secure_url\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:width\" content=\"350\" \/>\n\t\t<meta property=\"og:image:height\" content=\"350\" \/>\n\t\t<meta property=\"article:published_time\" content=\"2019-10-31T19:26:22+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2019-10-31T19:26:22+00:00\" \/>\n\t\t<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<meta property=\"article:author\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<!-- All in One SEO -->\n\n","aioseo_head_json":{"title":"\ud83e\udd47Openbare test: oplossing voor privacy en schaalbaarheid in Ethereum | ProHoster","description":"Blockchain is een innovatieve technologie die veel gebieden van het menselijk leven kan verbeteren.","canonical_url":"https:\/\/prohoster.info\/nl\/blog\/administrirovanie\/publichnyj-test-reshenie-dlya-privatnosti-i-masshtabiruemosti-v-efiriume","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"nl_NL","og:site_name":"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b","og:type":"article","og:title":"\ud83e\udd47\u041f\u0443\u0431\u043b\u0438\u0447\u043d\u044b\u0439 \u0442\u0435\u0441\u0442: \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u0434\u043b\u044f \u043f\u0440\u0438\u0432\u0430\u0442\u043d\u043e\u0441\u0442\u0438 \u0438 \u043c\u0430\u0441\u0448\u0442\u0430\u0431\u0438\u0440\u0443\u0435\u043c\u043e\u0441\u0442\u0438 \u0432 \u042d\u0444\u0438\u0440\u0438\u0443\u043c\u0435 | ProHoster","og:description":"\u0411\u043b\u043e\u043a\u0447\u0435\u0439\u043d \u2014 \u0438\u043d\u043d\u043e\u0432\u0430\u0446\u0438\u043e\u043d\u043d\u0430\u044f \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u044f, \u043e\u0431\u0435\u0449\u0430\u044e\u0449\u0430\u044f \u0443\u043b\u0443\u0447\u0448\u0438\u0442\u044c \u043c\u043d\u043e\u0433\u0438\u0435 \u0441\u0444\u0435\u0440\u044b \u0447\u0435\u043b\u043e\u0432\u0435\u0447\u0435\u0441\u043a\u043e\u0439 \u0436\u0438\u0437\u043d\u0438.","og:url":"https:\/\/prohoster.info\/nl\/blog\/administrirovanie\/publichnyj-test-reshenie-dlya-privatnosti-i-masshtabiruemosti-v-efiriume","og:image":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:secure_url":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:width":350,"og:image:height":350,"article:published_time":"2019-10-31T19:26:22+00:00","article:modified_time":"2019-10-31T19:26:22+00:00","article:publisher":"https:\/\/www.facebook.com\/prohoster","article:author":"https:\/\/www.facebook.com\/prohoster"},"aioseo_meta_data":{"post_id":"38856","title":null,"description":null,"keywords":null,"keyphrases":null,"primary_term":null,"canonical_url":null,"og_title":null,"og_description":null,"og_object_type":"default","og_image_type":"default","og_image_url":null,"og_image_width":null,"og_image_height":null,"og_image_custom_url":null,"og_image_custom_fields":null,"og_video":null,"og_custom_url":null,"og_article_section":null,"og_article_tags":null,"twitter_use_og":false,"twitter_card":"default","twitter_image_type":"default","twitter_image_url":null,"twitter_image_custom_url":null,"twitter_image_custom_fields":null,"twitter_title":null,"twitter_description":null,"schema":{"blockGraphs":[],"customGraphs":[],"default":{"data":{"Article":[],"Course":[],"Dataset":[],"FAQPage":[],"Movie":[],"Person":[],"Product":[],"ProductReview":[],"Car":[],"Recipe":[],"Service":[],"SoftwareApplication":[],"WebPage":[]},"graphName":"","isEnabled":true},"graphs":[]},"schema_type":null,"schema_type_options":null,"pillar_content":false,"robots_default":true,"robots_noindex":false,"robots_noarchive":false,"robots_nosnippet":false,"robots_nofollow":false,"robots_noimageindex":false,"robots_noodp":false,"robots_notranslate":false,"robots_max_snippet":null,"robots_max_videopreview":null,"robots_max_imagepreview":"large","priority":null,"frequency":null,"local_seo":null,"seo_analyzer_scan_date":"2026-01-23 23:42:19","breadcrumb_settings":null,"limit_modified_date":false,"reviewed_by":null,"ai":null,"created":"2021-02-28 12:15:36","updated":"2026-01-23 23:42:19","focus_keyword":null,"additional_keywords":null,"truseo_locale":null},"gt_translate_keys":[{"key":"link","format":"url"}],"_links":{"self":[{"href":"https:\/\/prohoster.info\/nl\/wp-json\/wp\/v2\/posts\/38856","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/nl\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/nl\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/nl\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/nl\/wp-json\/wp\/v2\/comments?post=38856"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/nl\/wp-json\/wp\/v2\/posts\/38856\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/nl\/wp-json\/wp\/v2\/media\/29146"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/nl\/wp-json\/wp\/v2\/media?parent=38856"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/nl\/wp-json\/wp\/v2\/categories?post=38856"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/nl\/wp-json\/wp\/v2\/tags?post=38856"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}