Showdown smart contract: Hyperledger Fabric vs MultiChain vs Ethereum vs Corda

Nodo di origine: 1585333

C'è più di un modo per inserire il codice su una blockchain

Nella maggior parte delle discussioni sulle blockchain, non ci vuole molto prima che venga fuori la nozione di "contratti intelligenti". Nell'immaginario popolare, i contratti intelligenti automatizzano l'esecuzione delle interazioni tra le parti, senza richiedere un intermediario fidato. Esprimendo i rapporti giuridici in codice anziché in parole, promettono di consentire alle transazioni di svolgersi direttamente e senza errori, intenzionali o meno.

Da un punto di vista tecnico, uno smart contract è qualcosa di più specifico: codice informatico che vive su una blockchain e definisce le regole per le transazioni di quella catena. Questa descrizione sembra abbastanza semplice, ma dietro di essa si cela una grande variazione nel modo in cui queste regole vengono espresse, eseguite e convalidate. Quando si sceglie una piattaforma blockchain per una nuova applicazione, la domanda "Questa piattaforma supporta contratti intelligenti?" non è quello giusto da chiedere. Invece, dobbiamo chiederci: "Che tipo di contratti intelligenti supporta questa piattaforma?"

In questo articolo, il mio obiettivo è esaminare alcune delle principali differenze tra gli approcci del contratto intelligente e i compromessi che rappresentano. Lo farò esaminando quattro popolari piattaforme blockchain aziendali che supportano una qualche forma di codice on-chain personalizzato. Primo, quello di IBM Tessuto Hyperledger, che chiama i suoi contratti "chaincode". In secondo luogo, la nostra piattaforma MultiChain, che introduce filtri intelligenti nella versione 2.0. Terzo, Ethereum (ed è autorizzato Quorum ed Tana spin-off), che ha reso popolare il nome di "contratto intelligente". E infine, Corda R3, che fa riferimento a "contratti" nelle sue transazioni. Nonostante tutta la diversa terminologia, alla fine tutti si riferiscono alla stessa cosa: codice specifico dell'applicazione che definisce le regole di una catena.

Prima di andare oltre, dovrei avvertire il lettore che gran parte del seguente contenuto è di natura tecnica e presuppone una certa familiarità con la programmazione generale e i concetti di database. Nel bene o nel male, questo non può essere evitato: senza entrare nei dettagli è impossibile prendere una decisione informata sull'opportunità di utilizzare una blockchain per un particolare progetto e (in tal caso) il giusto tipo di blockchain da utilizzare.

Nozioni di base sulla blockchain

Cominciamo con un po 'di contesto. Immagina un'applicazione condivisa da più organizzazioni, basata su un database sottostante. In un'architettura centralizzata tradizionale, questo database è ospitato e amministrato da una singola parte di cui tutti i partecipanti si fidano, anche se non si fidano l'uno dell'altro. Le transazioni che modificano il database vengono avviate solo dalle applicazioni sui sistemi di questa parte centrale, spesso in risposta ai messaggi ricevuti dai partecipanti. Il database fa semplicemente ciò che viene detto perché l'applicazione è implicitamente attendibile per inviarle solo transazioni che hanno senso.

Le blockchain forniscono un modo alternativo per gestire un database condiviso, senza un intermediario fidato. In una blockchain, ogni partecipante gestisce un "nodo" che contiene una copia del database ed elabora in modo indipendente le transazioni che lo modificano. I partecipanti vengono identificati utilizzando chiavi pubbliche o "indirizzi", ciascuno dei quali ha una chiave privata corrispondente nota solo al proprietario dell'identità. Sebbene le transazioni possano essere create da qualsiasi nodo, vengono "firmate digitalmente" dalla chiave privata del loro iniziatore per provare la loro origine.

I nodi si connettono tra loro in modo peer-to-peer, propagando rapidamente le transazioni ei "blocchi" in cui sono contrassegnati e confermati attraverso la rete. La stessa blockchain è letteralmente una catena di questi blocchi, che forma un registro ordinato di ogni transazione storica. Un "algoritmo di consenso" viene utilizzato per garantire che tutti i nodi raggiungano un accordo sul contenuto della blockchain, senza richiedere un controllo centralizzato. (Nota che parte di questa descrizione non si applica a Corda, in cui ogni nodo ha solo una copia parziale del database e non esiste una blockchain globale. Ne parleremo più avanti.)

In linea di principio, qualsiasi applicazione di database condivisa può essere progettata utilizzando una blockchain al suo interno. Ma così facendo si creano una serie di sfide tecniche che non esistono in uno scenario centralizzato:

  • Regole di transazione. Se un partecipante può modificare direttamente il database, come ci assicuriamo che segua le regole dell'applicazione? Cosa impedisce a un utente di corrompere i contenuti del database in modo autonomo?
  • Determinismo. Una volta definite, queste regole verranno applicate più volte da più nodi durante l'elaborazione delle transazioni per la propria copia del database. Come ci assicuriamo che ogni nodo ottenga esattamente lo stesso risultato?
  • Prevenzione dei conflitti. Senza un coordinamento centrale, come gestiamo due transazioni che seguono ciascuna le regole dell'applicazione, ma sono comunque in conflitto tra loro? I conflitti possono derivare da un tentativo deliberato di ingannare il sistema o essere il risultato innocente di sfortuna e tempismo.

Allora, da dove vengono gli smart contract, i filtri intelligenti e il chaincode? Il loro scopo principale è lavorare con l'infrastruttura sottostante di una blockchain per risolvere queste sfide. I contratti intelligenti sono l'equivalente decentralizzato del codice dell'applicazione: invece di essere eseguiti in un unico luogo centrale, vengono eseguiti su più nodi nella blockchain, creando o convalidando le transazioni che modificano il contenuto di quel database.

Cominciamo con le regole di transazione, la prima di queste sfide, e vediamo come si esprimono rispettivamente in Fabric, MultiChain, Ethereum e Corda.

Regole di transazione

Le regole di transazione svolgono una funzione specifica nei database basati su blockchain, limitando l'estensione trasformazioni che può essere eseguito sullo stato di quel database. Ciò è necessario perché le transazioni di una blockchain possono essere avviate da uno qualsiasi dei suoi partecipanti e questi partecipanti non si fidano sufficientemente l'uno dell'altro per consentire loro di modificare il database a volontà.

Vediamo due esempi del motivo per cui sono necessarie le regole di transazione. Innanzitutto, immagina una blockchain progettata per aggregare e contrassegnare i documenti PDF che vengono pubblicati dai suoi partecipanti. In questo caso, nessuno dovrebbe avere il diritto di rimuovere o modificare i documenti, poiché così facendo si minerebbe l'intero scopo del sistema: la persistenza dei documenti. In secondo luogo, considera una blockchain che rappresenta un libro mastro finanziario condiviso, che tiene traccia dei saldi dei suoi utenti. Non possiamo permettere a un partecipante di gonfiare arbitrariamente il proprio saldo o di portare via i soldi degli altri.

Ingressi e uscite

Le nostre piattaforme blockchain si basano su due ampi approcci per esprimere le regole delle transazioni. Il primo, che chiamo "modello input-output", è utilizzato in MultiChain e Corda. Qui, le transazioni elencano esplicitamente le righe del database o gli "stati" che eliminano e creano, formando rispettivamente un insieme di "input" e "output". La modifica di una riga è espressa come l'operazione equivalente di eliminare quella riga e crearne una nuova al suo posto.

Poiché le righe del database vengono eliminate solo negli input e create solo negli output, ogni input deve "spendere" l'output di una transazione precedente. Lo stato corrente del database è definito come l'insieme di "output di transazione non spesi" o "UTXO", ovvero output di transazioni precedenti che non sono ancora state utilizzate. Le transazioni possono anche contenere informazioni aggiuntive, chiamate “metadati”, “comandi” o “allegati”, che non diventano parte del database ma aiutano a definirne il significato o lo scopo.

Dati questi tre set di input, output e metadati, la validità di una transazione in MultiChain o Corda è definita da un codice che può eseguire calcoli arbitrari su tali set. Questo codice può convalidare la transazione oppure restituire un errore con una spiegazione corrispondente. Puoi pensare al modello input-output come un "ispettore" automatizzato che tiene una lista di controllo che garantisce che le transazioni seguano ogni regola. Se la transazione non supera uno di questi controlli, verrà automaticamente rifiutata da tutti i nodi della rete.

Va notato che, nonostante condividano il modello input-output, MultiChain e Corda lo implementano in modo molto diverso. In MultiChain, gli output possono contenere asset e / o dati in formato JSON, testo o binario. Le regole sono definite in "filtri di transazione" o "filtri di flusso", che possono essere impostati per controllare tutte le transazioni o solo quelle che coinvolgono particolari risorse o raggruppamenti di dati. Al contrario, uno “stato” di output Corda è rappresentato da un oggetto nel linguaggio di programmazione Java o Kotlin, con campi dati definiti. Le regole di Corda sono definite in "contratti" che sono allegati a stati specifici, e il contratto di uno stato è applicato solo alle transazioni che contengono quello stato nei suoi input o output. Questo si riferisce a Corda's modello di visibilità insolito, in cui le transazioni possono essere viste solo dalle loro controparti o da coloro le cui operazioni successive influenzano.

Contratti e messaggi

Il secondo approccio, che chiamo il "modello di messaggio-contratto", viene utilizzato in Hyperledger Fabric ed Ethereum. Qui, è possibile creare più "contratti intelligenti" o "chaincode" sulla blockchain e ciascuno ha il proprio database e il codice associato. Il database di un contratto può essere modificato solo dal suo codice, piuttosto che direttamente dalle transazioni blockchain. Questo modello di progettazione è simile all '"incapsulamento" di codice e dati nella programmazione orientata agli oggetti.

Con questo modello, una transazione blockchain inizia come un messaggio inviato a un contratto, con alcuni parametri o dati opzionali. Il codice del contratto viene eseguito in reazione al messaggio e ai parametri ed è libero di leggere e scrivere il proprio database come parte di tale reazione. I contratti possono anche inviare messaggi ad altri contratti, ma non possono accedere direttamente ai database degli altri. Nel linguaggio dei database relazionali, i contratti agiscono come forzata "Stored procedure", dove tutti gli accessi al database avvengono tramite un codice predefinito.

Sia Fabric che Quorum, una variazione di Ethereum, complicano questo quadro consentendo a una rete di definire più "canali" o "stati privati". L'obiettivo è mitigare il problema della riservatezza della blockchain creando ambienti separati, ognuno dei quali è visibile solo a un particolare sottogruppo di partecipanti. Anche se in teoria questo sembra promettente, in realtà i contratti ei dati in ogni canale o stato privato sono isolati da quelli negli altri. Di conseguenza, in termini di contratti intelligenti, questi ambienti sono equivalenti a blockchain separati.

Regole di esempio

Vediamo come implementare le regole di transazione per un libro mastro finanziario mono-asset con questi due modelli. Ogni riga nel database del nostro libro mastro ha due colonne, contenenti l'indirizzo del proprietario e la quantità del bene posseduto. Nel modello input-output, le transazioni devono soddisfare due condizioni:

  1. La quantità totale di attività negli output di una transazione deve corrispondere al totale nei suoi input. Ciò impedisce agli utenti di creare o eliminare denaro in modo arbitrario.
  2. Ogni transazione deve essere firmata dal proprietario di ciascuno dei suoi input. Ciò impedisce agli utenti di spendere i soldi gli uni degli altri senza autorizzazione.

Nel loro insieme, queste due condizioni sono tutto ciò che è necessario per creare un sistema finanziario semplice ma sostenibile.

Nel modello contratto-messaggio, il contratto dell'asset supporta un messaggio di "invio pagamento", che accetta tre parametri: indirizzo del mittente, indirizzo del destinatario e quantità da inviare. In risposta, il contratto esegue i seguenti quattro passaggi:

  1. Verifica che la transazione sia stata firmata dal mittente.
  2. Verifica che il mittente disponga di fondi sufficienti.
  3. Sottrarre la quantità richiesta dalla riga del mittente.
  4. Aggiungi quella quantità alla riga del destinatario.

Se uno dei controlli nei primi due passaggi fallisce, il contratto verrà interrotto e non verrà effettuato alcun pagamento.

Pertanto, entrambi i modelli di input-output e di contratto-messaggio sono modi efficaci per definire le regole di transazione e mantenere sicuro un database condiviso. Infatti, a livello teorico, ciascuno di questi modelli può essere utilizzato per simulare l'altro. In pratica, tuttavia, il modello più appropriato dipenderà dall'applicazione che si sta costruendo. Ogni transazione interessa poche o molte informazioni? Dobbiamo essere in grado di garantire l'indipendenza delle transazioni? Ogni pezzo di dati ha un chiaro proprietario o c'è uno stato globale da condividere?

Esplorare come le risposte dovrebbero influenzare una scelta tra questi due modelli va oltre il nostro scopo. Ma come linea guida generale, quando si sviluppa una nuova applicazione blockchain, vale la pena provare a esprimere le sue regole di transazione in entrambe le forme e vedere quale si adatta in modo più naturale. La differenza si esprimerà in termini di: (a) facilità di programmazione, (b) requisiti di archiviazione e velocità effettiva e (c) velocità di rilevamento dei conflitti. Parleremo più avanti di questo ultimo numero.

Regole incorporate

Quando si tratta di regole di transazione, c'è un modo in cui MultiChain differisce specificamente da Fabric, Ethereum e Corda. A differenza di queste altre piattaforme, MultiChain ha diverse astrazioni integrate che forniscono alcuni elementi costitutivi di base per le applicazioni basate su blockchain, senza richiedendo sviluppatori a scrivere il proprio codice. Queste astrazioni coprono tre aree comunemente necessarie: (a) autorizzazioni dinamiche, (b) risorse trasferibili e (c) archiviazione dei dati.

Ad esempio, MultiChain gestisce le autorizzazioni per la connessione alla rete, l'invio e la ricezione di transazioni, la creazione di risorse o flussi o il controllo delle autorizzazioni di altri utenti. Più beni fungibili possono essere emessi, trasferiti, ritirati o scambiati in modo sicuro e atomico. È possibile creare un numero qualsiasi di "flussi" su una catena, per la pubblicazione, l'indicizzazione e il recupero di dati in catena o fuori catena in formato JSON, testo o binario. Tutte le regole di transazione per queste astrazioni sono disponibili out-of-the-box.

Quando si sviluppa un'applicazione su MultiChain, è possibile ignorare questa funzionalità integrata ed esprimere le regole di transazione utilizzando solo filtri intelligenti. Tuttavia, i filtri intelligenti sono progettati per funzionare insieme alle sue astrazioni incorporate, abilitando il loro comportamento predefinito limitato in modi personalizzati. Ad esempio, l'autorizzazione per determinate attività potrebbe essere controllata da amministratori specifici, anziché il comportamento predefinito in cui lo farà qualsiasi amministratore. Il trasferimento di determinate attività può essere limitato nel tempo o richiedere un'ulteriore approvazione al di sopra di un determinato importo. I dati in un determinato flusso possono essere convalidati per garantire che sia costituito solo da strutture JSON con campi e valori obbligatori.

In tutti questi casi, i filtri intelligenti creano requisiti aggiuntivi per la convalida delle transazioni, ma non lo fanno rimuovere le semplici regole che sono incorporate. Questo può aiutare ad affrontare una delle sfide chiave nelle applicazioni blockchain: il fatto che un bug in alcuni codici on-chain può portare a conseguenze disastrose. Abbiamo visto infiniti esempi di questo problema nella blockchain pubblica di Ethereum, la più famosa nel Fine della DAO e la Bug multisignatura di parità. Indagini più ampie hanno trovato un gran numero di vulnerabilità comuni negli smart contract di Ethereum che consentono agli aggressori di rubare o congelare i fondi di altre persone.

Ovviamente, anche i filtri intelligenti MultiChain possono contenere bug, ma le loro conseguenze sono di portata più limitata. Ad esempio, le regole per le risorse integrate impediscono a un utente di spendere il denaro di un altro o di far sparire accidentalmente il proprio denaro, indipendentemente dall'altra logica contenuta in un filtro intelligente. Se un bug viene trovato in un filtro intelligente, può essere disattivato e sostituito con una versione corretta, mentre l'integrità di base del libro mastro è protetta. Filosoficamente, MultiChain è più vicino alle architetture di database tradizionali, in cui la piattaforma di database fornisce una serie di astrazioni integrate, come colonne, tabelle, indici e vincoli. Funzionalità più potenti come trigger e stored procedure possono essere facoltativamente codificate dagli sviluppatori di applicazioni, nei casi in cui sono effettivamente necessarie.

Regole di transazione Tessuto più giri Ethereum Corda
Modello Contratto-messaggio Input Output Contratto-messaggio Input Output
Built-in Nessuna Autorizzazioni +
risorse + flussi
Nessuna Nessuna

Determinismo

Passiamo alla parte successiva della nostra resa dei conti. Indipendentemente dall'approccio che scegliamo, le regole di transazione personalizzate di un'applicazione blockchain sono espresse come codice di computer scritto dagli sviluppatori dell'applicazione. E a differenza delle applicazioni centralizzate, questo codice verrà eseguito più di una volta e in più di una posizione per ciascuna transazione. Questo perché più nodi blockchain appartenenti a diversi partecipanti devono verificare e / o eseguire quella transazione per se stessi.

Questa esecuzione ripetuta e ridondante del codice introduce un nuovo requisito che si riscontra raramente nelle applicazioni centralizzate: il determinismo. Nel contesto del calcolo, determinismo significa che un pezzo di codice darà sempre la stessa risposta per gli stessi parametri, indipendentemente da dove e quando viene eseguito. Questo è assolutamente cruciale per il codice che interagisce con una blockchain perché, senza determinismo, il consenso tra i nodi di quella catena può crollare catastroficamente.

Vediamo come appare in pratica, prima nel modello input-output. Se due nodi hanno un'opinione diversa sulla validità di una transazione, uno accetterà un blocco contenente quella transazione e l'altro no. Poiché ogni blocco si collega esplicitamente a un blocco precedente, questo creerà un "fork" permanente nella rete, con uno o più nodi che da quel momento in poi non accettano l'opinione della maggioranza sull'intera blockchain. I nodi in minoranza verranno esclusi dallo stato in evoluzione del database e non saranno più in grado di utilizzare efficacemente l'applicazione.

Vediamo ora cosa succede se il consenso viene meno nel modello del messaggio di contratto. Se due nodi hanno un'opinione diversa su come un contratto dovrebbe rispondere a un particolare messaggio, ciò può portare a una differenza nei contenuti dei loro database. Ciò a sua volta può influire sulla risposta del contratto ai messaggi futuri, inclusi i messaggi che invia ad altri contratti. Il risultato finale è una crescente divergenza tra la visualizzazione dello stato del database da parte dei diversi nodi. (Il campo "root di stato" nei blocchi Ethereum garantisce che qualsiasi differenza nelle risposte dei contratti porti immediatamente a un fork blockchain completamente catastrofico, piuttosto che rischiare di rimanere nascosti per un periodo di tempo.)

Fonti di non determinismo

Quindi il non determinismo nel codice blockchain è chiaramente un problema. Ma se gli elementi costitutivi di base del calcolo, come l'aritmetica, sono deterministici, di cosa dobbiamo preoccuparci? Bene, si scopre, un bel po 'di cose:

  • Ovviamente, generatori di numeri casuali, poiché per definizione questi sono progettati per produrre ogni volta un risultato diverso.
  • Controllo dell'ora corrente, poiché i nodi non elaboreranno le transazioni esattamente nello stesso momento e in ogni caso i loro orologi potrebbero non essere sincronizzati. (È ancora possibile implementare regole dipendenti dal tempo facendo riferimento ai timestamp all'interno della blockchain stessa.)
  • Interrogare risorse esterne come Internet, file su disco o altri programmi in esecuzione su un computer. Non è possibile garantire che queste risorse forniscano sempre la stessa risposta e potrebbero non essere disponibili.
  • Esecuzione di più parti di codice in "thread" paralleli, poiché ciò porta a una "condizione di competizione" in cui non è possibile prevedere l'ordine in cui questi processi terminano.
  • Esecuzione di calcoli in virgola mobile che possono fornire risposte anche minuziosamente diverse su diverse architetture di processori del computer.

Le nostre quattro piattaforme blockchain utilizzano diversi approcci per evitare queste insidie.

Esecuzione deterministica

Partiamo da Ethereum, visto che il suo approccio è il più “puro”. I contratti Ethereum sono espressi in un formato speciale chiamato "Ethereum bytecode", che viene eseguito dalla Ethereum Virtual Machine ("EVM"). I programmatori non scrivono il bytecode direttamente, ma piuttosto lo generano o lo "compilano" da un linguaggio di programmazione simile a JavaScript chiamato Solidity. (Altre lingue erano disponibili ma da allora sono state deprecate.) Il determinismo è garantito dal fatto che Solidity ed Ethereum bytecode non possono codificare alcuna operazione non deterministica - è così semplice.

I filtri MultiChain ei contratti Corda scelgono un approccio diverso, adattando i linguaggi di programmazione esistenti e gli ambienti di runtime. MultiChain utilizza JavaScript in esecuzione in Google V8 motore, che costituisce anche il cuore del browser Chrome e della piattaforma Node.js, ma con le fonti di non determinismo disabilitate. Allo stesso modo, Corda utilizza Java o Kotlin, entrambi compilati in "Java bytecode" che viene eseguito all'interno di una Java Virtual Machine ("JVM"). Per ora, Corda utilizza la JVM non deterministica standard di Oracle, ma sono in corso lavori per integrare un file versione deterministica. Nel frattempo, gli sviluppatori di contratti Corda devono fare attenzione a non consentire il non determinismo nel loro codice.

Come si confronta il purismo di Ethereum con l'approccio evolutivo adottato da MultiChain e Corda? Il vantaggio principale di Ethereum è la minimizzazione del rischio: è meno probabile che una macchina virtuale costruita per uno scopo contenga una fonte involontaria di non determinismo. Sebbene una simile svista possa essere risolta da un aggiornamento software, sarebbe dannosa per qualsiasi catena che sia stata così sfortunata da incontrarla. Il problema di Ethereum, tuttavia, è che Solidity e EVM costituiscono un piccolo e nascente ecosistema nel contesto più ampio dei linguaggi di programmazione e degli ambienti di runtime. In confronto, JavaScript e Java sono i file le prime due lingue su GitHub, funzionano su miliardi di dispositivi digitali e hanno tempi di esecuzione ottimizzati nel corso di decenni. Presumibilmente questo è il motivo per cui la blockchain pubblica di Ethereum sta considerando una transizione a eWASM, un fork deterministico dello standard emergente WebAssembly.

Determinismo per approvazione

Quando si tratta di determinismo, Hyperledger Fabric adotta un approccio completamente diverso. In Fabric, quando un nodo "client" vuole inviare un messaggio a un chaincode, invia prima quel messaggio ad alcuni nodi "endorser". Ognuno di questi nodi esegue il chaincode in modo indipendente, formando un'opinione sul messaggio effetto nel database di quel chaincode. Queste opinioni vengono rispedite al cliente insieme a una firma digitale che costituisce un "avallo" formale. Se il cliente riceve un numero sufficiente di approvazioni del risultato previsto, crea una transazione contenente tali approvazioni e la trasmette per l'inclusione nella catena.

Al fine di garantire il determinismo, ogni pezzo di chaincode ha una "politica di approvazione" che definisce esattamente quale livello di approvazione è richiesto per rendere valide le sue transazioni. Ad esempio, la politica di un chaincode potrebbe affermare che sono richieste approvazioni da almeno metà dei nodi della blockchain. Un altro potrebbe richiedere l'approvazione di una delle tre parti fidate. In ogni caso, ogni nodo può controllare in modo indipendente se sono state ricevute le necessarie approvazioni.

Per chiarire la differenza, il determinismo nella maggior parte delle piattaforme blockchain si basa sulla domanda: "Qual è il risultato dell'esecuzione di questo codice su questi dati?" - e dobbiamo essere assolutamente sicuri che ogni nodo risponderà a questa domanda in modo identico. Al contrario, il determinismo in Fabric si basa su una domanda diversa: "Un numero sufficiente di sostenitori concorda sul risultato dell'esecuzione di questo codice su questi dati?" Rispondere a questa domanda è piuttosto semplice da contare e non c'è spazio per il non determinismo che si insinua.

Il determinismo per approvazione di Fabric ha una serie di conseguenze interessanti. Innanzitutto, il chaincode può essere scritto in molti linguaggi di programmazione diversi, poiché questi non devono essere adattati per il determinismo (Go, Java e JavaScript sono attualmente supportati). In secondo luogo, il chaincode può essere nascosto ad alcuni dei partecipanti a una blockchain, poiché deve essere eseguito solo da client e endorser (il database stesso è visibile a livello globale). Infine, e soprattutto, il chaincode di Fabric può fare cose che sono vietate in altri ambienti blockchain, come controllare il tempo utilizzando un'API web online. Nel peggiore dei casi, in cui ogni endorser ottiene una risposta diversa da questa API, il client non riuscirà a ottenere abbastanza approvazioni per un determinato risultato e non avrà luogo alcuna transazione. (Va notato che i membri del team di Fabric ancora raccomandare utilizzando la logica deterministica all'interno del chaincode, per evitare sorprese.)

Quale prezzo paga Fabric per questa flessibilità? Se lo scopo di una blockchain è rimuovere gli intermediari da un'applicazione condivisa basata su database, la dipendenza di Fabric dagli endorser fa un grande passo avanti da tale obiettivo. Per i partecipanti alla catena, non è più sufficiente seguire le regole del chaincode: hanno anche bisogno di alcuni altri nodi per concordare di averlo fatto. Ancora peggio, un sottoinsieme dannoso di endorser potrebbe approvare modifiche al database che non seguono affatto il chaincode. Ciò conferisce agli endorser molto più potere rispetto ai validatori nelle normali blockchain, che possono censurare le transazioni ma non possono violare le regole della blockchain. Gli sviluppatori di applicazioni blockchain devono decidere se questo compromesso ha senso nel loro caso particolare.

Determinismo Tessuto più giri Ethereum Corda
Modello Riconoscimenti Runtime adattato VM appositamente progettata Runtime adattato
Le Lingue Vai + Java + JavaScript JavaScript Solidity Java + Kotlin
Visibilità del codice Controparti +
testimonial
Blockchain Blockchain Controparti +
a carico
Imposto Non No (per ora)

Prevenzione dei conflitti

Finora, abbiamo discusso di come le diverse piattaforme blockchain esprimono le regole di transazione nel codice e di come assicurano deterministicamente che ogni nodo applichi queste regole in modo identico. Ora è il momento di parlare di un terzo aspetto della nostra resa dei conti: in che modo ciascuna piattaforma affronta la possibilità che due transazioni, valide di per sé, entrino in conflitto tra loro? Nell'esempio più semplice, immagina che Alice abbia $ 10 in un registro finanziario e trasmetta due transazioni: una che invia $ 8 a Bob e l'altra che invia $ 7 a Charlie. Chiaramente, solo una di queste transazioni può avere successo.

Due modelli

Possiamo iniziare raggruppando insieme l'approccio di MultiChain e Corda a questo problema. Come descritto in precedenza, entrambi utilizzano un modello input-output per rappresentare le transazioni e le loro regole, in cui ogni input di transazione spende un output di transazione precedente. Questo porta a un semplice principio per prevenire i conflitti: ogni output può essere speso solo una volta. I filtri MultiChain e i contratti Corda possono fare affidamento sulle rispettive piattaforme per applicare assolutamente questa restrizione. Poiché i $ 10 di Alice sono rappresentati da un output di transazione precedente, questa regola di spesa singola interrompe automaticamente il suo invio a Bob e Charlie.

Nonostante questa somiglianza, è importante sottolineare una differenza fondamentale nel modo in cui MultiChain e Corda prevengono i conflitti. In MultiChain, ogni nodo vede ogni transazione e quindi può verificare indipendentemente che ogni output venga speso solo una volta. Qualsiasi transazione che esegua una doppia spesa rispetto a una transazione confermata in precedenza verrà immediatamente e automaticamente rifiutata. Al contrario, in Corda non esiste una blockchain globale, quindi i "notai" sono tenuti a prevenire queste doppie spese. Ogni stato di uscita Corda è assegnato a un notaio, che deve firmare ogni transazione spendendo quell'output, confermando che non è stato speso prima. I partecipanti a una blockchain devono fidarsi dei notai per seguire questa regola onestamente, ei notai malintenzionati possono causare il caos a volontà. Come per le approvazioni in Fabric, questo "spesa unica come servizio”Il design presenta vantaggi in termini di riservatezza ma reintroduce intermediari, andando contro la grana blockchain. (È importante chiarire che i notai Corda possono essere gestiti da gruppi di partecipanti utilizzando un algoritmo di consenso, quindi l'integrità del libro mastro può ancora essere protetta contro i singoli cattivi attori).

Passiamo a Ethereum. Per ricordare, Ethereum utilizza contratti e messaggi piuttosto che input e output. Di conseguenza, i conflitti di transazione come i due pagamenti di Alice non sono immediatamente visibili al motore blockchain. Invece, vengono rilevati e bloccati da contratto che elabora le transazioni, dopo che il loro ordine è stato confermato sulla catena. Durante l'elaborazione di ciascuno dei pagamenti di Alice, il contratto verifica se il suo saldo è sufficiente. Se la transazione che paga $ 8 a Bob arriva per prima, verrà elaborata come al solito, lasciando Alice con $ 2 nel suo account. Di conseguenza, quando il contratto elabora la seconda transazione pagando $ 7 a Charlie, vede che Alice non ha i fondi necessari e la transazione si interrompe.

Output vs contratti

Finora abbiamo visto due diverse tecniche per prevenire transazioni in conflitto: output a spesa singola in MultiChain e Corda e verifica basata su contratto in Ethereum. Allora qual è il migliore?

Per aiutare a rispondere a questa domanda, si consideri un esempio di account "1 su 2 firme multiple" che detiene $ 100 per conto di Gavin ed Helen e consente a entrambi di spendere quei soldi in modo indipendente. Gavin ordina alla sua domanda di pagare $ 80 a Donna e, pochi secondi dopo, Helen vuole inviare $ 40 a Edward. Poiché non ci sono fondi sufficienti per entrambi i pagamenti, queste transazioni sarebbero inevitabilmente in conflitto. Nel caso in cui entrambe le transazioni vengano trasmesse, il risultato sarà determinato da chi entra per primo nella catena. Nota che a differenza dell'esempio di Alice, questo conflitto è accidentale, poiché nessuno sta cercando di infrangere le regole dell'applicazione, semplicemente hanno avuto un tempismo sfortunato.

Considerando la probabilità che questo conflitto si verifichi, la domanda chiave è questa: dopo che Gavin ha inviato la sua transazione, quanto tempo impiegherà il nodo di Helen per sapere che il suo pagamento potrebbe non riuscire? Più breve è questo periodo, più è probabile che Helen venga impedito di tentare il pagamento, salvando lei e la sua domanda da una successiva sorpresa.

Con il modello input-output, qualsiasi conflitto tra le transazioni è direttamente visibile alla piattaforma blockchain, poiché le due transazioni tenteranno esplicitamente di spendere lo stesso output precedente. In MultiChain, ciò accade non appena la transazione di Gavin si è propagata al nodo di Helen, di solito in un secondo o meno. A Corda, il notaio dell'output rifiuterà la richiesta di firmare la transazione di Helen, poiché ha già firmato quella di Gavin, quindi Helen saprà immediatamente che il suo pagamento non andrà a buon fine. (Anche se se il notaio Corda viene distribuito, potrebbe dover attendere alcuni secondi per una risposta.) In ogni caso, non è necessario attendere che una transazione venga confermata e ordinata nella blockchain.

E il modello di Ethereum? In questo caso, non esiste un modo immediato per la piattaforma blockchain di sapere che si verificherà un conflitto. Sebbene il nodo di Helen possa vedere la transazione di Gavin sulla rete, non può sapere come ciò influenzerà la transazione di Helen, poiché dal suo punto di vista questi sono semplicemente due messaggi inviati allo stesso contratto. Forse dieci secondi dopo, una volta confermato l'ordine finale delle transazioni in conflitto sulla blockchain, il nodo di Helen ricalcolerà il risultato effettivo anziché quello previsto e la sua applicazione aggiornerà la sua visualizzazione di conseguenza. Nel frattempo, sia Gavin che Helen saranno lasciati all'oscuro.

Ma non dovremmo concludere da questo che il modello input-output funziona sempre meglio. Considera una variazione del nostro scenario di esempio, in cui sia Gavin che Helen richiedono pagamenti inferiori di $ 40 dal saldo originale di $ 100, esattamente nello stesso momento. Nel modello input-output queste transazioni sarebbero in conflitto, poiché entrambe spendono la stessa riga di database contenente quei $ 100 e solo uno dei pagamenti andrebbe a buon fine. Ma in Ethereum, entrambe le transazioni verrebbero elaborate con successo, indipendentemente dal loro ordine finale, poiché l'account contiene fondi sufficienti per entrambe. In questo caso, Ethereum soddisfa più fedelmente le intenzioni di Gavin ed Helen.

Set di lettura-scrittura

Infine, parliamo di Fabric, il cui approccio basato sull'endorsement è un ibrido di queste due tecniche. Come spiegato in precedenza, quando un nodo "client" di Fabric desidera inviare un messaggio a un contratto, chiede prima ad alcuni nodi di approvazione di eseguire quel messaggio per suo conto. I nodi di approvazione lo fanno in modo simile a Ethereum - eseguendo il contratto sul loro database locale - ma questo processo viene osservato piuttosto che applicato immediatamente. Ogni endorser registra l'insieme di righe che verrebbero lette e scritte, annotando anche la versione esatta di quelle righe in quel momento. Questo "set di lettura-scrittura" di righe con versione è esplicitamente indicato nell'avallo e incluso nella transazione trasmessa dal client.

I conflitti tra le transazioni Fabric vengono risolti una volta che il loro ordine è stato finalizzato nella catena. Ogni nodo elabora ogni transazione in modo indipendente, controllando le politiche di approvazione e applicando le modifiche al database specificate. Tuttavia, se una transazione legge o scrive una versione della riga del database che è già stata modificata da una transazione precedente, la seconda transazione viene ignorata. Per tornare ai pagamenti in conflitto di Alice a Bob e Charlie, entrambe queste transazioni leggeranno e modificheranno la stessa versione di riga, contenente i $ 10 con cui Alice ha iniziato. Quindi la seconda transazione verrà interrotta automaticamente e in modo sicuro.

L'approccio di Fabric alla risoluzione dei conflitti funziona bene, ma in termini di prestazioni e flessibilità combina il peggio dei due modelli precedenti. Poiché le approvazioni convertono le transazioni in specifici set di lettura-scrittura, i pagamenti simultanei ma compatibili di $ 40 di Gavin e Helen porterebbero a un conflitto che Ethereum evita. Tuttavia, Fabric non ottiene il vantaggio di velocità del modello input-output, dal momento che gli endorser eseguono contratti sulla versione più recente del database confermata dalla blockchain, ignorando le transazioni non confermate. Quindi, se Helen avvia il pagamento pochi secondi dopo Gavin, ma prima che Gavin sia confermato sulla blockchain, Fabric creerà transazioni in conflitto che un modello di input-output puro evita.

Prevenzione dei conflitti Tessuto più giri Ethereum Corda
Modello Set di lettura-scrittura Spesa singola Controlli contrattuali Spesa singola
Convalida Competenza Competenza Competenza Notai fidati
Velocità ~ 10s (conferma) ~ 1s (propagazione) ~ 10s (conferma) 0 ~ 5s (notaio)

Una scelta complessa

In questo articolo, abbiamo esaminato molti dei diversi modi in cui Corda, Ethereum, Fabric e MultiChain affrontano le sfide chiave dei "contratti intelligenti" o del codice dell'applicazione incorporato in una blockchain. E ogni piattaforma ha risposte diverse alle nostre tre domande principali: come sono rappresentate le regole di transazione? Come viene eseguito il codice in modo deterministico? E come si prevengono i conflitti?

Allora chi è il vincitore della nostra resa dei conti del contratto intelligente? Dovrebbe essere ovvio ormai che non esiste una risposta semplice. Ogni piattaforma rappresenta un complesso compromesso multidirezionale tra flessibilità, semplicità, prestazioni, disintermediazione, sicurezza e riservatezza. Pertanto, la scelta della piattaforma per una particolare applicazione deve iniziare con una comprensione dettagliata del modello di affidabilità dell'applicazione, dei tipi di transazioni che comporta e dei loro probabili modelli di conflitto. Se trovi qualcuno che spinge una specifica soluzione di contratto intelligente prima di conoscere le risposte a queste domande, suggerisco cortesemente ma fermamente di insistere affinché adotti un approccio "più intelligente".

Si prega di inviare eventuali commenti LinkedIn.

Timestamp:

Di più da più giri