Architettura delle applicazioni decentralizzate: back-end, sicurezza e modelli di progettazione

Le applicazioni decentralizzate, o ÐApps, richiedono uno speciale design del sistema per ottenere sicurezza e affidabilità elevate. In questo articolo tratterò diversi principi fondamentali su come progettare e implementare correttamente back-end e contratti intelligenti per applicazioni decentralizzate, prendendo Ethereum come esempio principale, sebbene gran parte di esso si applicherebbe a EOS, Tron e altre piattaforme di dati decentralizzate.

Punti salienti dell'articolo :

  • Come archiviare le chiavi private sul back-end senza problemi di sicurezza
  • Come progettare correttamente contratti intelligenti e cosa "decentralizzare"
  • Esempi di architettura di applicazioni decentralizzate e semi-centralizzate
  • Come gestire cose di basso livello come il carico di rete e gli errori

Sarà grande, facciamolo!

Programmi decentralizzati e Blockchain

Nonostante il fatto che blockchain stia affrontando molte difficoltà di adozione e regolamentazione oggi, è un tipo di tecnologia che è qui per restare, che si tratti di blockchain, hashgraph, tempo o qualsiasi altra tecnologia di registro distribuito ancora in arrivo, indipendentemente dall'algoritmo.

Il valore principale che la blockchain e altre tecnologie simili apportano può essere generalizzato come segue: consentono alle persone di scrivere ed eseguire programmi che, praticamente, non possono essere modificati dopo la creazione né manomessi durante l'esecuzione. In altre parole, questi programmi funzionano sempre come previsto e nessuna singola parte può influenzare il loro comportamento.

Questa definizione è valida per molte criptovalute che esistono oggi se le consideriamo come programmi che definiscono come le monete possono essere trasferite avanti e indietro. Questo spiega anche perché le criptovalute e molti tipi di token hanno un valore reale: non possono essere generati dal nulla, dai loro "programmi sottostanti" definiti.

Le piattaforme Ethereum / EOS / Tron /…, a differenza di Bitcoin, implementano un livello di programma più complesso, che a sua volta implementa l'ambiente di esecuzione consentendo a chiunque di scrivere i propri programmi decentralizzati sulla piattaforma. Questi programmi definiti dall'utente vengono eseguiti sempre come previsto, senza eccezioni, e la loro sicurezza è garantita dalla piattaforma.

Applicazioni decentralizzate

Questi programmi sicuri e immutabili eseguiti su una rete decentralizzata in combinazione con le tradizionali tecnologie front-end e back-end sono ciò che oggi chiamiamo applicazioni decentralizzate (ÐApps). Attraverso alcuni di essi possono essere semi-centralizzati, una parte importante delle attività nell'applicazione veramente decentralizzata dovrebbe avvenire fuori dal controllo di un partito centrale.

Per immaginare ciò che oggi chiamiamo applicazioni decentralizzate, prendi qualsiasi risorsa web centralizzata esistente come _YouTube_ o _Instagram_ come esempio e immagina che invece di un account centralizzato protetto da password tu abbia la tua " identità crittografica " legata alla risorsa web / mobile.

Questo è ciò che ti offre il software Wallet. La chiave privata di questa identità (un segreto, il cui possesso è possibile agire per conto di questa identità) è memorizzata sul tuo dispositivo locale e non va mai online, rendendo nessuno in grado di controllare questa identità tranne te. Con questa identità, è possibile eseguire diverse azioni sia centralizzato (risorsa web controllato da un'autorità centrale) e decentrata (che è una rete diversa da quella www tradizionale, il cui obiettivo è quello di eliminare l'autorità centrale) le reti , utilizzando il sito web come punto di accesso e / o come interfaccia utente grafica. Il punto centrale di questa "identità crittografica" è che le tue azioni sono protette crittograficamente e nessuno è in grado di cambiare ciò che hai firmato né la tua firma.

Oggi, le capacità di calcolo e archiviazione delle reti decentralizzate tolleranti ai guasti come Ethereum, EOS o Tron sono limitate. Se fossero scalabili, potremmo utilizzare reti decentralizzate per archiviare l'intera applicazione decentralizzata, compresa la sua interfaccia utente grafica, i dati e la logica aziendale. In questo caso, chiameremmo queste applicazioni veramente decentralizzate / distribuite.

Tuttavia, poiché oggi queste reti non sono scalabili, combiniamo diversi approcci per ottenere il massimo livello di decentralizzazione per le nostre applicazioni. Il back-end "tradizionale" come lo conosciamo non sta andando da nessuna parte. Per esempio:

  • Usiamo il back-end per ospitare il front-end per un'applicazione decentralizzata.
  • Usiamo il back-end per integrazioni con altre tecnologie e servizi esistenti. Le applicazioni reali di livello mondiale non possono vivere in un ambiente isolato.
  • Usiamo il back-end per archiviare ed elaborare qualsiasi cosa abbastanza grande per una rete decentralizzata (blockchain in particolare). In pratica, l'intera applicazione e la sua logica di business sono archiviate da qualche parte nel mondo, escludendo solo la parte blockchain. Per non parlare del fatto che IPFS e livelli di archiviazione simili non possono garantire l'accessibilità dei file, quindi non possiamo fare affidamento su di essi senza ospitare i file da soli. In altre parole, c'è sempre bisogno di un server in esecuzione dedicato.

Non c'è modo di creare un'applicazione sicura e parzialmente decentralizzata senza utilizzare un solido back-end a partire da oggi, e il punto centrale di questo articolo è spiegare come farlo bene.

(De) centralizzazione e token

Accade così che quasi tutte le applicazioni decentralizzate oggi siano costruite intorno ai cosiddetti token: criptovalute personalizzate (o semplicemente clonate) che guidano una particolare applicazione decentralizzata. I token sono semplicemente una valuta o risorse programmabili, questo è tutto.

Di solito, un token è un "contratto intelligente" (un programma personalizzato) scritto sopra una piattaforma decentralizzata come Ethereum. Possedendo alcuni token sei fondamentalmente in grado di ottenere diversi servizi su una risorsa web o un'app mobile e scambiare questo token con qualcos'altro. Il punto chiave qui è che il token vive da solo e non è controllato da un'autorità centrale.

Ci sono molti esempi di applicazioni costruite attorno ai token: da numerosi giochi collezionabili come CryptoKitties (token ERC721) ad app più orientate ai servizi come LOOM Network, o persino browser come Brave e piattaforme di gioco come DreamTeam (token compatibili con ERC20).

Gli sviluppatori stessi determinano e decidono quanto controllo avranno (o meno) sulle loro applicazioni. Possono costruire la logica di business dell'intera applicazione su contratti intelligenti (come ha fatto CryptoKitties), oppure non possono fare uso di contratti intelligenti, centralizzando tutto sui loro server. Tuttavia, l'approccio migliore è da qualche parte nel mezzo.

Back-end per reti decentralizzate

Da un punto di vista tecnico, deve esserci un ponte che collega token e altri contratti intelligenti con l'applicazione web / mobile.

Nelle odierne applicazioni completamente decentralizzate, in cui i clienti interagiscono direttamente con gli smart contract, questo bridge è ristretto alle capacità dell'API RPC JSON di API pubbliche o pool di nodi come Infura, che a loro volta sono costretti a esistere a causa del fatto che non tutti i dispositivi possono eseguire e supportare il proprio nodo di rete individuale. Tuttavia, questa API fornisce un unico insieme di funzioni di base e molto ristretto, che consente a malapena di eseguire query semplici né di aggregare dati in modo efficiente. Per questo motivo, alla fine, entra in gioco il back-end personalizzato, rendendo l'applicazione semi-centralizzata.

L'intera interazione con la rete decentralizzata può essere ristretta a uno o due punti, a seconda delle esigenze dell'applicazione:

  1. Ascolto degli eventi di rete (come i trasferimenti di token)/ leggere lo stato della rete .
  2. Transazioni di pubblicazione (invocando funzioni di contratto intelligente che cambiano lo stato come il trasferimento di token).

L'implementazione di entrambi questi punti è piuttosto complicata, soprattutto se vogliamo creare una soluzione di back-end sicura e affidabile. Ecco i punti principali che analizzeremo di seguito:

  • Prima di tutto, in Ethereum, il recupero degli eventi non è pronto per la produzione fuori dagli schemi. A causa di molteplici ragioni: i nodi di rete possono fallire durante il recupero di un gran numero di eventi, gli eventi possono scomparire o cambiare a causa di fork di rete, ecc. Dobbiamo costruire un livello di astrazione per sincronizzare gli eventi dalla rete e garantire la loro consegna affidabile.
  • Lo stesso per la pubblicazione delle transazioni, dobbiamo astrarre le cose di basso livello di Ethereum come i contatori nonce e le stime del gas, così come la ripubblicazione delle transazioni, fornendo un'interfaccia affidabile e stabile. Inoltre, la pubblicazione delle transazioni implica l'utilizzo di chiavi private, che richiede una sicurezza avanzata di back-end.
  • Sicurezza. Lo prenderemo sul serio e ammetteremo che è impossibile garantire che le chiavi private non vengano mai compromesse su un back-end. Fortunatamente, esiste un approccio alla progettazione di un'applicazione decentralizzata senza nemmeno la necessità di account back-end altamente protetti.

Nella nostra pratica, tutto ciò ci ha fatto creare una solida soluzione di back-end per Ethereum che chiamiamo Ethereum Gateway . Astrae altri microservizi dal divertimento di Ethereum e fornisce un'API affidabile per lavorarci.

In qualità di startup in rapida crescita, non possiamo rivelare la soluzione completa (solo ancora) per ovvi motivi, ma condividerò tutto ciò che devi sapere per far funzionare la tua applicazione decentralizzata in modo impeccabile. Tuttavia, se hai domande o richieste specifiche, non esitare a contattarmi. Anche i commenti a questo articolo sono molto apprezzati!

Architettura delle applicazioni decentralizzate

Questa parte dell'articolo dipende fortemente dalle esigenze di una particolare applicazione decentralizzata, ma proveremo a risolvere alcuni schemi di interazione di base su cui sono costruite queste applicazioni (ÐPlatform = Piattaforma decentralizzata = Ethereum / EOS / Tron / Qualunque cosa):

Client ⬌ ÐPlatform : applicazioni completamente decentralizzate .

Il client (browser o applicazione mobile) dialoga con la piattaforma decentralizzata direttamente con l'aiuto del software “wallet” di Ethereum come Metamask, Trust o portafogli hardware come Trezor o Ledger. Esempi di DApp costruite in questo modo sono CryptoKitties, Loom's Delegated Call, gli stessi crypto wallet (Metamask, Trust, Tron Wallet, altri), scambi di crittografia decentralizzati come Etherdelta e così via.

ÐPiattaformaClientBack End⬌Piattaforma : applicazioni centralizzate o semi-centralizzate .

L'interazione del client con la piattaforma decentralizzata e il server ha poco in comune. Il buon esempio di questo è qualsiasi scambio crittografico ( centralizzato ) oggi, come BitFinex o Poloniex: le valute che scambi sugli scambi sono semplicemente registrate nel database tradizionale. Puoi "ricaricare" il saldo del tuo database inviando risorse a un indirizzo specifico (ÐPlatform ⬌ Client) e quindi ritirare le risorse dopo alcune azioni nell'app (Back End ⬌ ÐPlatform), tuttavia, tutto ciò che fai in termini di "ÐApp" stesso (Client ⬌ Back End) non implica la tua interazione diretta con la ÐPlatform.

Un altro esempio è Etherscan.io, che utilizza un approccio semi-centralizzato : puoi eseguire tutte le azioni decentralizzate utili lì, ma l'applicazione stessa non ha senso senza il loro back-end completo (Etherscan sincronizza continuamente le transazioni, analizza i dati e li archivia, in ultima analisi, fornendo un'API / UI completa).

Qualcosa in mezzo: applicazioni fisse, centralizzate o semi-centralizzate .

Gli approcci di cui sopra combinati. Ad esempio, possiamo avere un'applicazione che fornisce vari servizi in cambio di crittografia, permettendoti di accedere e firmare informazioni con la tua identità crittografica.

Si spera che il modello di interazione delle applicazioni completamente decentralizzate (Client ⬌ ÐPlatform) non sollevi dubbi. Facendo affidamento su servizi così straordinari come Infura o Trongrid si può semplicemente creare un'applicazione che non richiede affatto un server. Quasi tutte le librerie lato client come Ethers.js per Ethereum o Tron-Web per Tron possono connettersi a questi servizi pubblici e comunicare con la rete. Tuttavia, per query e attività più complesse, potrebbe essere necessario allocare comunque il proprio server.

Il resto dei modelli di interazione che coinvolgono il back-end rendono le cose più interessanti e complesse. Per mettere tutto questo in un'immagine, immaginiamo un caso in cui il nostro back-end reagisce a qualche evento nella rete. Ad esempio, l'utente pubblica una transazione di indennità che ci autorizza ad addebitarli. Per effettuare un addebito, dobbiamo pubblicare la transazione di addebito in risposta all'evento di indennità emessa:

Dal punto di vista del back end ecco cosa succede:

  1. Ascoltiamo un particolare evento di rete interrogando continuamente la rete.
  2. Una volta ricevuto un evento, eseguiamo una logica di business e quindi decidiamo di pubblicare una transazione in risposta.
  3. Prima di pubblicare la transazione, vogliamo assicurarci che verrà probabilmente estratta (in Ethereum, la stima del gas della transazione riuscita significa che non ci sono errori rispetto allo stato corrente della rete ). Tuttavia, non possiamo garantire che la transazione venga estratta correttamente .
  4. Usando una chiave privata, firmiamo e pubblichiamo la transazione. In Ethereum dobbiamo anche determinare il prezzo del gas e il limite del gas della transazione.
  5. Dopo aver pubblicato la transazione, interroghiamo continuamente la rete per il suo stato.
  6. Se impiega troppo tempo e non possiamo ottenere lo stato della transazione, dobbiamo ripubblicarlo o attivare uno "scenario di fallimento". Le transazioni possono essere perse per vari motivi: congestione della rete, peer in calo, aumento del carico di rete, ecc. In Ethereum, puoi anche considerare di firmare nuovamente una transazione con un prezzo del gas (effettivo) diverso.
  7. Dopo aver finalmente estratto la nostra transazione, possiamo eseguire più logica di business se necessario. Ad esempio, possiamo notificare ad altri servizi di back end il fatto che la transazione è stata completata. Inoltre, considera l'attesa di un paio di conferme prima di prendere le decisioni finali sulla transazione: la rete è distribuita e quindi il risultato può cambiare in pochi secondi.

Come puoi vedere, stanno succedendo molte cose! Tuttavia, la tua applicazione potrebbe non richiedere alcuni di questi passaggi, a seconda di ciò che stai cercando di ottenere. Tuttavia, la creazione di un back-end robusto e stabile richiede una soluzione per tutti i problemi sopra menzionati. Analizziamolo.

Back-end delle applicazioni decentralizzate

Qui voglio evidenziare alcuni dei punti che pongono la maggior parte delle domande, vale a dire:

  • Ascolto di eventi di rete e lettura di dati dalla rete
  • Pubblicare le transazioni e come farlo in sicurezza

Ascolto di eventi di rete

In Ethereum, così come in altre reti decentralizzate, un concetto di eventi di contratto intelligente (o log di eventi, o semplicemente log) consente alle applicazioni off-chain di essere consapevoli di ciò che sta accadendo nella blockchain. Questi eventi possono essere creati dagli sviluppatori di contratti intelligenti in qualsiasi punto del codice del contratto intelligente.

Ad esempio, all'interno del noto standard di token ERC20, ogni trasferimento di token deve registrare l'evento di trasferimento, consentendo così alle applicazioni off-chain di sapere che è avvenuto un trasferimento di token. “Ascoltando” questi eventi possiamo eseguire qualsiasi (ri) azione. Ad esempio, alcuni crypto-wallet mobili ti inviano una notifica push / email quando i token vengono trasferiti al tuo indirizzo.

In effetti, non esiste una soluzione affidabile per ascoltare gli eventi di rete fuori dagli schemi. Diverse librerie consentono di tracciare / ascoltare eventi, tuttavia, ci sono molti casi in cui qualcosa può andare storto, provocando eventi persi o non elaborati. Per evitare di perdere eventi, dobbiamo creare un back-end personalizzato, che manterrà il processo di sincronizzazione degli eventi.

A seconda delle tue esigenze, l'implementazione può variare. Ma metterti in una foto qui è una delle opzioni su come puoi costruire la consegna di eventi Ethereum affidabile in termini di architettura di microservizi:

Questi componenti funzionano nel modo seguente:

  1. Il servizio back-end di sincronizzazione degli eventi interroga costantemente la rete, cercando di recuperare nuovi eventi. Quando sono disponibili alcuni nuovi eventi, invia questi eventi al bus dei messaggi. In caso di invio riuscito dell'evento al bus dei messaggi, come per la blockchain, possiamo salvare il blocco dell'ultimo evento per richiedere nuovi eventi da questo blocco la prossima volta. Tieni presente che il recupero di troppi eventi contemporaneamente può comportare sempre richieste non riuscite, quindi devi limitare il numero di eventi / blocchi richiesti dalla rete.
  2. Il bus dei messaggi (ad esempio, Rabbit MQ) instrada l'evento a ogni coda impostata individualmente per ogni servizio di back-end. Prima della pubblicazione degli eventi, il servizio back-end di sincronizzazione degli eventi specifica la chiave di instradamento (ad esempio, un indirizzo del contratto intelligente + un argomento dell'evento), mentre i consumatori (altri servizi di back-end) creano code che vengono sottoscritte solo per eventi particolari.

Di conseguenza, ogni servizio di back-end riceve solo gli eventi di cui ha bisogno. Inoltre, il bus dei messaggi garantisce la consegna di tutti gli eventi una volta pubblicati su di esso.

Ovviamente, puoi usare qualcos'altro al posto del bus dei messaggi: callback HTTP, socket, ecc. In questo caso, dovrai capire come garantire tu stesso la consegna dei callback: gestire i tentativi di richiamata esponenziali / personalizzati, implementare il monitoraggio personalizzato e presto.

Transazioni di pubblicazione

Ci sono un paio di passaggi che dobbiamo eseguire per pubblicare una transazione sulla rete decentralizzata:

  1. Preparare la transazione. Insieme ai dati della transazione, questo passaggio implica la richiesta dello stato della rete per scoprire se questa transazione è valida e verrà estratta (stima del gas in Ethereum) e il numero sequenziale della transazione (nonce in Ethereum). Alcune librerie tentano di farlo sotto il cofano, tuttavia, questi passaggi sono importanti.
  2. Firma della transazione. Questo passaggio implica l'utilizzo della chiave privata. Molto probabilmente, qui vorrai incorporare la soluzione di assembly della chiave privata personalizzata (ad esempio).
  3. Pubblicazione e ripubblicazione della transazione. Uno dei punti chiave qui è che la tua transazione pubblicata ha sempre la possibilità di perdersi o essere eliminata dalla rete decentralizzata. Ad esempio, in Ethereum, la transazione pubblicata può essere interrotta se il prezzo del gas della rete aumenta improvvisamente. In questo caso, devi ripubblicare la transazione. Inoltre, potresti voler ripubblicare la transazione con altri parametri (almeno con un prezzo del gas più alto) per poterla estrarre il prima possibile. Pertanto, la ripubblicazione della transazione può implicare una nuova firma, se la transazione sostitutiva non è stata pre-firmata in precedenza (con parametri diversi).

Utilizzando gli approcci di cui sopra puoi finire per costruire qualcosa di simile a ciò che viene presentato nel diagramma di sequenza qui sotto. In questo particolare diagramma di sequenza, dimostro (in generale!) Come funziona la fatturazione ricorrente blockchain (c'è di più in un articolo collegato):

  1. L'utente esegue una funzione in uno smart contract, che alla fine consente al back-end di eseguire una transazione di addebito riuscita.
  2. Un servizio di back-end responsabile di una particolare attività ascolta l'evento di indennità di addebito e pubblica una transazione di addebito.
  3. Una volta che la transazione di addebito è stata estratta, questo servizio di back-end responsabile di una particolare attività riceve un evento dalla rete Ethereum ed esegue una logica (inclusa l'impostazione della data di addebito successiva).

Sicurezza back-end e contratti intelligenti

La pubblicazione delle transazioni implica sempre l'utilizzo di una chiave privata . Forse ti starai chiedendo se è possibile mantenere le chiavi private al sicuro. Ebbene sì e no. Esistono numerose strategie complesse e diversi tipi di software che consentono di archiviare le chiavi private sul back-end in modo abbastanza sicuro. Alcune soluzioni di archiviazione della chiave privata utilizzano database distribuiti geograficamente, mentre altre suggeriscono persino l'uso di hardware speciale. Tuttavia, in ogni caso, il punto più vulnerabile di un'applicazione semi-centralizzata è dove la chiave privata viene assemblata e utilizzata per firmare una transazione (o, in caso di hardware speciale, un punto di attivazione di una procedura di firma della transazione). Quindi, in teoria, non esiste una soluzione affidabile al 100% che consenta una protezione a prova di proiettile dalla compromissione delle chiavi private archiviate.

Ora pensa in questo modo. In molti casi, non è nemmeno necessario proteggere le chiavi private sul back-end così spesso. Invece, puoi progettare contratti intelligenti e l'intera applicazione in modo tale che una perdita di chiave privata non influenzi il loro comportamento abituale . Con questo approccio, non importa come gli account autorizzati interagiscono con lo smart contract. Stanno solo "attivando" uno smart contract per svolgere il suo lavoro abituale e lo smart contract stesso esegue la convalida richiesta. Lo chiamo il "modello dei conti operativi".

In questo modo, in caso di emergenza:

  • L'unica cosa che l'attaccante può rubare è una piccola quantità di Ether (a partire da Ethereum) depositata negli account operativi per la pubblicazione delle transazioni
  • L'aggressore non sarà in grado di danneggiare la logica del contratto intelligente né chiunque sia coinvolto nel processo
  • Gli account operativi compromessi possono essere rapidamente sostituiti con altri, tuttavia, ciò richiede la sostituzione manuale (generazione di nuovi account e nuova autorizzazione degli account in tutti gli smart contract) o lo sviluppo di una soluzione aggiuntiva che farà tutta la magia con una singola transazione da un super -account master sicuro (hardware o multi-sig).

Ad esempio, nella nostra soluzione di fatturazione ricorrente per Ethereum, indipendentemente da ciò che accade su un back-end, il contratto intelligente di fatturazione ricorrente è progettato in modo tale che abbiamo un intero mese di tempo per sostituire gli account compromessi se qualcuno di essi è compromesso .

Tuttavia, se desideri rendere il più sicuro possibile l'archiviazione della tua chiave privata back-end, puoi provare a utilizzare Vault con un ottimo plug-in per Ethereum che archivia e gestisce gli account Ethereum (inoltre, tieni d'occhio i nostri moduli open-source: noi stanno per rilasciare presto qualcosa di simile). Non approfondirò i dettagli qui, anche se puoi visitare i progetti collegati e imparare da lì tu stesso.

Questo non è nemmeno tutto quello che ho da dire. Tuttavia, questo articolo si è rivelato molto più lungo di quanto mi aspettassi, quindi devo smetterla. Iscriviti al mio Medium / altre reti se sei interessato a software, criptovalute, consigli di viaggio o vuoi semplicemente seguire qualcosa di interessante. Spero di aver fornito un'informazione di grande valore e che lo troverai utile. Sentiti libero di commentare e diffondere questo articolo!