Afișare inteligentă a contractului: Hyperledger Fabric vs MultiChain vs Ethereum vs Corda

Nodul sursă: 1585333

Există mai multe modalități de a pune cod pe un blockchain

În majoritatea discuțiilor despre blockchains, nu durează mult până să apară noțiunea de „contracte inteligente”. În imaginația populară, contractele inteligente automatizează execuția interacțiunilor între părți, fără a necesita un intermediar de încredere. Exprimând relațiile juridice în cod, mai degrabă decât în ​​cuvinte, ele promit să permită tranzacțiilor să aibă loc direct și fără eroare, fie deliberată sau nu.

Din punct de vedere tehnic, un contract inteligent este ceva mai specific: un cod de computer care trăiește pe un blockchain și definește regulile pentru tranzacțiile acelui lanț. Această descriere sună destul de simplă, dar în spatele ei se află o mare variație în modul în care aceste reguli sunt exprimate, executate și validate. Când alegeți o platformă blockchain pentru o nouă aplicație, întrebarea „Această platformă acceptă contracte inteligente?” nu este cel potrivit să întreb. În schimb, trebuie să ne întrebăm: „Ce tip de contracte inteligente acceptă această platformă?”

În acest articol, scopul meu este să examinez unele dintre diferențele majore dintre abordările smart contract și compromisurile pe care le reprezintă. Voi face acest lucru uitându-mă la patru platforme populare de blockchain pentru întreprinderi care acceptă o anumită formă de cod personalizat în lanț. În primul rând, IBM Hyperledger Fabric, care își numește contractele „cod de lanț”. În al doilea rând, platforma noastră MultiChain, care introduce filtre inteligente în versiunea 2.0. Al treilea, Ethereum (și este permis Cvorum și Vizuină spin-off), care a popularizat denumirea de „contract inteligent”. Și, în sfârșit, R3 Corda, care face referire la „contracte” în tranzacțiile sale. În ciuda terminologiei diferite, în cele din urmă toate acestea se referă la același lucru - cod specific aplicației care definește regulile unui lanț.

Înainte de a merge mai departe, ar trebui să avertizez cititorul că o mare parte din conținutul următor este de natură tehnică și presupune o anumită familiaritate cu conceptele generale de programare și baze de date. În bine sau în rău, acest lucru nu poate fi evitat – fără a intra în detalii, este imposibil să luați o decizie informată cu privire la utilizarea unui blockchain pentru un anumit proiect și (dacă da) tipul corect de blockchain de utilizat.

Noțiuni de bază despre blockchain

Să începem cu un context. Imaginați-vă o aplicație care este partajată de mai multe organizații, care se bazează pe o bază de date subiacentă. Într-o arhitectură centralizată tradițională, această bază de date este găzduită și administrată de o singură parte în care toți participanții au încredere, chiar dacă nu au încredere unul în celălalt. Tranzacțiile care modifică baza de date sunt inițiate numai de aplicațiile din sistemele acestei părți centrale, adesea ca răspuns la mesajele primite de la participanți. Baza de date face pur și simplu ceea ce i se spune, deoarece aplicația este implicit de încredere pentru a-i trimite doar tranzacții care au sens.

Blockchain-urile oferă o modalitate alternativă de gestionare a unei baze de date partajate, fără un intermediar de încredere. Într-un blockchain, fiecare participant rulează un „nod” care deține o copie a bazei de date și procesează în mod independent tranzacțiile care o modifică. Participanții sunt identificați folosind chei publice sau „adrese”, fiecare dintre ele având o cheie privată corespunzătoare, cunoscută doar de proprietarul identității. În timp ce tranzacțiile pot fi create de orice nod, ele sunt „semnate digital” de cheia privată a inițiatorului lor pentru a dovedi originea lor.

Nodurile se conectează între ele într-un mod peer-to-peer, propagă rapid tranzacțiile și „blocurile” în care sunt marcate de timp și confirmate în rețea. Blockchain-ul în sine este literalmente un lanț al acestor blocuri, care formează un jurnal ordonat al fiecărei tranzacții istorice. Un „algoritm de consens” este utilizat pentru a se asigura că toate nodurile ajung la un acord cu privire la conținutul blockchain-ului, fără a necesita un control centralizat. (Rețineți că o parte din această descriere nu se aplică Corda, în care fiecare nod are doar o copie parțială a bazei de date și nu există un blockchain global. Vom vorbi mai multe despre asta mai târziu.)

În principiu, orice aplicație de bază de date partajată poate fi arhitecturată folosind un blockchain în nucleul său. Dar acest lucru creează o serie de provocări tehnice care nu există într-un scenariu centralizat:

  • Reguli de tranzacție. Dacă orice participant poate schimba direct baza de date, cum ne asigurăm că respectă regulile aplicației? Ce oprește un utilizator să corupă conținutul bazei de date într-un mod care se folosește?
  • Determinismul. Odată definite aceste reguli, ele vor fi aplicate de mai multe ori de către mai multe noduri atunci când procesează tranzacțiile pentru propria copie a bazei de date. Cum ne asigurăm că fiecare nod obține exact același rezultat?
  • Prevenirea conflictelor. Fără o coordonare centrală, cum ne descurcăm cu două tranzacții care respectă fiecare regulile aplicației, dar care totuși sunt în conflict între ele? Conflictele pot proveni dintr-o încercare deliberată de a juca sistemul sau pot fi rezultatul inocent al ghinionului și al timpului.

Deci, unde intervin contractele inteligente, filtrele inteligente și codurile de lanț? Scopul lor principal este să lucreze cu infrastructura de bază a unui blockchain pentru a rezolva aceste provocări. Contractele inteligente sunt echivalentul descentralizat al codului aplicației – în loc să ruleze într-un singur loc central, rulează pe mai multe noduri din blockchain, creând sau validând tranzacțiile care modifică conținutul acelei baze de date.

Să începem cu regulile de tranzacție, prima dintre aceste provocări, și să vedem cum sunt exprimate în Fabric, MultiChain, Ethereum și, respectiv, Corda.

Reguli de tranzacție

Regulile de tranzacție îndeplinesc o funcție specifică în bazele de date bazate pe blockchain - restricționând transformări care poate fi efectuat pe starea acelei baze de date. Acest lucru este necesar deoarece tranzacțiile unui blockchain pot fi inițiate de oricare dintre participanții săi, iar acești participanți nu au suficientă încredere unul în altul pentru a le permite să modifice baza de date după bunul plac.

Să vedem două exemple de ce sunt necesare reguli de tranzacție. În primul rând, imaginați-vă un blockchain conceput pentru a agrega și marca documentele PDF care sunt publicate de participanții săi. În acest caz, nimeni nu ar trebui să aibă dreptul de a elimina sau modifica documentele, deoarece acest lucru ar submina întregul scop al sistemului – persistența documentelor. În al doilea rând, luați în considerare un blockchain care reprezintă un registru financiar comun, care ține evidența soldurilor utilizatorilor săi. Nu putem permite unui participant să-și umfle în mod arbitrar propriul sold sau să ia banii altora.

Intrări și ieșiri

Platformele noastre blockchain se bazează pe două abordări largi pentru exprimarea regulilor de tranzacție. Primul, pe care îl numesc „model de intrare-ieșire”, este folosit în MultiChain și Corda. Aici, tranzacțiile listează în mod explicit rândurile sau „stările” bazei de date pe care le șterg și le creează, formând un set de „intrari” și, respectiv, „ieșiri”. Modificarea unui rând este exprimată ca operația echivalentă de ștergere a acelui rând și crearea unuia nou în locul său.

Deoarece rândurile bazei de date sunt șterse numai în intrări și create numai în ieșiri, fiecare intrare trebuie să „cheltuiască” rezultatul unei tranzacții anterioare. Starea curentă a bazei de date este definită ca setul de „ieșiri ale tranzacțiilor necheltuite” sau „UTXO”, adică rezultate din tranzacțiile anterioare care nu au fost încă utilizate. Tranzacțiile pot conține, de asemenea, informații suplimentare, numite „metadate”, „comenzi” sau „atașamente”, care nu devin parte din baza de date, dar ajută la definirea sensului sau scopului lor.

Având în vedere aceste trei seturi de intrări, ieșiri și metadate, validitatea unei tranzacții în MultiChain sau Corda este definită de un cod care poate efectua calcule arbitrare pe acele seturi. Acest cod poate valida tranzacția sau poate returna o eroare cu o explicație corespunzătoare. Vă puteți gândi la modelul de intrare-ieșire ca la un „inspector” automat care deține o listă de verificare care asigură că tranzacțiile respectă fiecare regulă. Dacă tranzacția nu reușește oricare dintre aceste verificări, aceasta va fi automat respinsă de toate nodurile din rețea.

Trebuie remarcat faptul că, în ciuda partajării modelului de intrare-ieșire, MultiChain și Corda îl implementează foarte diferit. În MultiChain, ieșirile pot conține active și/sau date în format JSON, text sau binar. Regulile sunt definite în „filtre de tranzacții” sau „filtre de flux”, care pot fi setate pentru a verifica toate tranzacțiile sau numai cele care implică anumite active sau grupări de date. În schimb, o „stare” de ieșire Corda este reprezentată de un obiect în limbajul de programare Java sau Kotlin, cu câmpuri de date definite. Regulile lui Corda sunt definite în „contracte” care sunt atașate unor state specifice, iar contractul unui stat se aplică numai tranzacțiilor care conțin acea stare în intrările sau ieșirile sale. Aceasta se referă la Corda model de vizibilitate neobișnuit, în care tranzacțiile pot fi văzute doar de contrapărțile lor sau de cei ale căror tranzacții ulterioare le afectează.

Contracte și mesaje

A doua abordare, pe care o numesc „modelul contract-mesaj”, este folosită în Hyperledger Fabric și Ethereum. Aici, mai multe „contracte inteligente” sau „coduri de lanț” pot fi create pe blockchain și fiecare are propria sa bază de date și cod asociat. Baza de date a unui contract poate fi modificată doar prin codul său, mai degrabă decât direct prin tranzacții blockchain. Acest model de design este similar cu „încapsularea” codului și datelor în programarea orientată pe obiecte.

Cu acest model, o tranzacție blockchain începe ca un mesaj trimis unui contract, cu niște parametri sau date opționale. Codul contractului este executat ca reacție la mesaj și parametri și este liber să citească și să scrie propria bază de date ca parte a acelei reacții. Contractele pot trimite mesaje și către alte contracte, dar nu pot accesa reciproc bazele de date direct. În limbajul bazelor de date relaționale, contractele acționează ca executată „proceduri stocate”, unde tot accesul la baza de date se face printr-un cod predefinit.

Atât Fabric, cât și Quorum, o variantă a Ethereum, complică această imagine permițând unei rețele să definească mai multe „canale” sau „stări private”. Scopul este de a atenua problema confidențialității blockchain prin crearea de medii separate, fiecare dintre acestea fiind vizibilă doar pentru un anumit subgrup de participanți. Deși acest lucru sună promițător în teorie, în realitate contractele și datele din fiecare canal sau stat privat sunt izolate de cele din celelalte. Drept urmare, în ceea ce privește contractele inteligente, aceste medii sunt echivalente cu blockchain-uri separate.

Exemple de reguli

Să vedem cum să implementăm regulile de tranzacție pentru un registru financiar cu un singur activ cu aceste două modele. Fiecare rând din baza de date a registrului nostru are două coloane, care conțin adresa proprietarului și cantitatea bunului deținut. În modelul input-output, tranzacțiile trebuie să îndeplinească două condiții:

  1. Cantitatea totală de active din ieșirile unei tranzacții trebuie să se potrivească cu totalul din intrările sale. Acest lucru împiedică utilizatorii să creeze sau să ștergă bani în mod arbitrar.
  2. Fiecare tranzacție trebuie să fie semnată de proprietarul fiecărei intrări. Acest lucru împiedică utilizatorii să-și cheltuiască banii reciproc fără permisiune.

Luate împreună, aceste două condiții sunt tot ceea ce este necesar pentru a crea un sistem financiar simplu, dar viabil.

În modelul contract-mesaj, contractul bunului acceptă un mesaj de „trimitere plată”, care ia trei parametri: adresa expeditorului, adresa destinatarului și cantitatea care trebuie trimisă. Ca răspuns, contractul execută următorii patru pași:

  1. Verificați dacă tranzacția a fost semnată de expeditor.
  2. Verificați dacă expeditorul are fonduri suficiente.
  3. Deduceți cantitatea solicitată din rândul expeditorului.
  4. Adăugați acea cantitate pe rândul destinatarului.

Dacă oricare dintre verificările din primii doi pași eșuează, contractul se va anula și nu se va efectua nicio plată.

Deci, atât modelele de intrare-ieșire, cât și de contract-mesaj sunt modalități eficiente de a defini regulile de tranzacție și de a menține în siguranță o bază de date partajată. Într-adevăr, la nivel teoretic, fiecare dintre aceste modele poate fi folosit pentru a-l simula pe celălalt. În practică însă, modelul cel mai potrivit va depinde de aplicația construită. Fiecare tranzacție afectează puține sau mai multe informații? Trebuie să putem garanta independența tranzacțiilor? Fiecare parte de date are un proprietar clar sau există o stare globală de partajat?

Este dincolo de domeniul nostru de a explora modul în care răspunsurile ar trebui să influențeze alegerea dintre aceste două modele. Dar, ca ghid general, atunci când se dezvoltă o nouă aplicație blockchain, merită să încerci să-și exprime regulile de tranzacție în ambele forme și să vezi care se potrivește mai natural. Diferența se va exprima în termeni de: (a) ușurință de programare, (b) cerințe de stocare și debit și (c) viteza de detectare a conflictelor. Vom vorbi mai multe despre această ultimă problemă mai târziu.

Reguli încorporate

Când vine vorba de regulile de tranzacție, există un fel în care MultiChain diferă în mod specific de Fabric, Ethereum și Corda. Spre deosebire de aceste alte platforme, MultiChain are mai multe abstracții încorporate care oferă câteva blocuri de bază pentru aplicații bazate pe blockchain, fără necesită dezvoltatorii să-și scrie propriul cod. Aceste abstracții acoperă trei domenii de care sunt necesare în mod obișnuit: (a) permisiuni dinamice, (b) active transferabile și (c) stocarea datelor.

De exemplu, MultiChain gestionează permisiunile pentru conectarea la rețea, trimiterea și primirea tranzacțiilor, crearea de active sau fluxuri sau controlul permisiunilor altor utilizatori. Mai multe active fungibile pot fi emise, transferate, retrase sau schimbate în siguranță și atomic. Orice număr de „fluxuri” pot fi create într-un lanț, pentru publicarea, indexarea și preluarea datelor în lanț sau în afara lanțului în formate JSON, text sau binar. Toate regulile de tranzacție pentru aceste abstracții sunt disponibile imediat.

Când dezvoltați o aplicație pe MultiChain, este posibil să ignorați această funcționalitate încorporată și să exprimați regulile de tranzacție folosind numai filtre inteligente. Cu toate acestea, filtrele inteligente sunt proiectate să funcționeze împreună cu abstracțiile sale încorporate, permițând comportamentul lor implicit să fie limitat în moduri personalizate. De exemplu, permisiunea pentru anumite activități ar putea fi controlată de anumiți administratori, mai degrabă decât comportamentul implicit în care va face orice administrator. Transferul anumitor active poate fi limitat de timp sau poate necesita aprobare suplimentară peste o anumită sumă. Datele dintr-un anumit flux pot fi validate pentru a se asigura că constă numai din structuri JSON cu câmpuri și valori obligatorii.

În toate aceste cazuri, filtrele inteligente creează cerințe suplimentare pentru ca tranzacțiile să fie validate, dar nu scoate regulile simple care sunt încorporate. Acest lucru poate ajuta la abordarea uneia dintre provocările cheie în aplicațiile blockchain: faptul că o eroare în unele coduri în lanț poate duce la consecințe dezastruoase. Am văzut nenumărate exemple ale acestei probleme în blockchain-ul public Ethereum, cel mai faimos în Decesul DAO si Erori de paritate multisemnătură. Sondaje mai ample au găsit un număr mare de vulnerabilități comune în contractele inteligente Ethereum care permit atacatorilor să fure sau să înghețe fondurile altor persoane.

Desigur, filtrele inteligente MultiChain pot conține și erori, dar consecințele lor sunt mai limitate. De exemplu, regulile de active încorporate împiedică un utilizator să cheltuiască banii altuia sau să-și facă din greșeală să dispară banii, indiferent de ce altă logică conține un filtru inteligent. Dacă se găsește un bug într-un filtru inteligent, acesta poate fi dezactivat și înlocuit cu o versiune corectată, în timp ce integritatea de bază a registrului este protejată. Din punct de vedere filozofic, MultiChain este mai aproape de arhitecturile tradiționale de baze de date, unde platforma de baze de date oferă o serie de abstracții încorporate, cum ar fi coloane, tabele, indici și constrângeri. Funcțiile mai puternice, cum ar fi declanșatoarele și procedurile stocate, pot fi codificate opțional de către dezvoltatorii de aplicații, în cazurile în care sunt cu adevărat necesare.

Reguli de tranzacție Țesături multicatenari Ethereum Corda
Model Contract-mesaj Intrare ieșire Contract-mesaj Intrare ieșire
Încorporate Nici unul Permisiuni +
active + fluxuri
Nici unul Nici unul

Determinismul

Să trecem la următoarea parte a confruntării noastre. Indiferent de abordarea pe care o alegem, regulile de tranzacție personalizate ale unei aplicații blockchain sunt exprimate ca cod de computer scris de dezvoltatorii de aplicații. Și, spre deosebire de aplicațiile centralizate, acest cod va fi executat de mai multe ori și în mai multe locuri pentru fiecare tranzacție. Acest lucru se datorează faptului că mai multe noduri blockchain aparținând diferiților participanți trebuie să verifice și/sau să execute fiecare tranzacție pentru ei înșiși.

Această execuție de cod repetată și redundantă introduce o nouă cerință care se găsește rar în aplicațiile centralizate: determinismul. În contextul calculului, determinismul înseamnă că o bucată de cod va da întotdeauna același răspuns pentru aceiași parametri, indiferent unde și când este rulată. Acest lucru este absolut crucial pentru codul care interacționează cu un blockchain, deoarece, fără determinism, consensul dintre nodurile de pe acel lanț se poate distruge catastrofal.

Să vedem cum arată acest lucru în practică, mai întâi în modelul de intrare-ieșire. Dacă două noduri au o opinie diferită cu privire la validitatea unei tranzacții, atunci unul va accepta un bloc care conține acea tranzacție, iar celălalt nu. Deoarece fiecare bloc se leagă în mod explicit la un bloc anterior, acest lucru va crea o „furcătură” permanentă în rețea, unul sau mai multe noduri care nu acceptă opinia majorității despre conținutul întregului blockchain din acel moment. Nodurile din minoritate vor fi tăiate din starea de evoluție a bazei de date și nu vor mai putea folosi aplicația în mod eficient.

Acum să vedem ce se întâmplă dacă consensul se destramă în modelul contract-mesaj. Dacă două noduri au o opinie diferită despre modul în care un contract ar trebui să răspundă la un anumit mesaj, acest lucru poate duce la o diferență în conținutul bazelor de date. Acest lucru, la rândul său, poate afecta răspunsul contractului la mesajele viitoare, inclusiv mesajele pe care le trimite către alte contracte. Rezultatul final este o divergență tot mai mare între vizualizarea diferitelor noduri asupra stării bazei de date. (Câmpul „rădăcină de stat” din blocurile Ethereum asigură că orice diferență în răspunsurile contractelor duce imediat la o bifurcație complet catastrofală a blockchain-ului, mai degrabă decât riscul să rămână ascuns pentru o perioadă de timp.)

Surse de non-determinism

Deci non-determinismul în codul blockchain este în mod clar o problemă. Dar dacă elementele de bază ale calculului, cum ar fi aritmetica, sunt deterministe, de ce trebuie să ne îngrijorăm? Ei bine, se pare, destul de multe lucruri:

  • Cel mai evident, generatoare de numere aleatorii, deoarece prin definiție acestea sunt concepute pentru a produce un rezultat diferit de fiecare dată.
  • Verificarea orei curente, deoarece nodurile nu vor procesa tranzacțiile exact în același timp și, în orice caz, ceasurile lor pot fi desincronizate. (Este încă posibil să se implementeze reguli dependente de timp făcând referire la marcajele de timp din cadrul blockchain-ului însuși.)
  • Interogarea resurselor externe, cum ar fi Internetul, fișierele de disc sau alte programe care rulează pe un computer. Nu se poate garanta că aceste resurse vor da întotdeauna același răspuns și pot deveni indisponibile.
  • Rularea mai multor bucăți de cod în „fire” paralele, deoarece aceasta duce la o „condiție de cursă” în care ordinea în care se termină aceste procese nu poate fi prezisă.
  • Efectuarea oricăror calcule în virgulă mobilă care pot da răspunsuri chiar și minuscule diferite pe diferite arhitecturi de procesoare ale computerului.

Cele patru platforme blockchain ale noastre folosesc mai multe abordări diferite pentru a evita aceste capcane.

Execuție deterministă

Să începem cu Ethereum, deoarece abordarea sa este cea mai „pură”. Contractele Ethereum sunt exprimate într-un format special numit „Ethereum bytecode”, care este executat de Ethereum Virtual Machine (“EVM”). Programatorii nu scriu bytecode direct, ci mai degrabă îl generează sau îl „compilează” dintr-un limbaj de programare asemănător JavaScript numit Solidity. (Alte limbi erau disponibile, dar de atunci au fost depreciate.) Determinismul este garantat de faptul că Solidity și Ethereum bytecode nu pot codifica operațiuni nedeterministe – este atât de simplu.

Filtrele MultiChain și contractele Corda aleg o abordare diferită, adaptând limbajele de programare existente și mediile de rulare. MultiChain folosește JavaScript care rulează în Google V8 motor, care formează și nucleul browserului Chrome și al platformei Node.js, dar cu sursele de non-determinism dezactivate. În mod similar, Corda folosește Java sau Kotlin, ambele sunt compilate în „Java bytecode” care se execută într-o mașină virtuală Java („JVM”). Deocamdată, Corda utilizează JVM-ul nedeterminist standard al Oracle, dar se lucrează la integrarea unui versiune deterministă. Între timp, dezvoltatorii de contracte Corda trebuie să aibă grijă să nu permită non-determinismul în codul lor.

Cum se compară purismul Ethereum cu abordarea evolutivă adoptată de MultiChain și Corda? Principalul avantaj pentru Ethereum este minimizarea riscului - o mașină virtuală construită pentru scop este mai puțin probabil să conțină o sursă inadvertentă de non-determinism. În timp ce orice astfel de neglijare ar putea fi remediată printr-o actualizare de software, ar fi perturbator pentru orice lanț care a avut ghinionul să o întâlnească. Problema lui Ethereum este însă că Solidity și EVM constituie un ecosistem mic și în curs de dezvoltare în contextul mai larg al limbajelor de programare și al mediilor de rulare. Prin comparație, JavaScript și Java sunt primele două limbi pe Github, rulează pe miliarde de dispozitive digitale și au durate care au fost optimizate de-a lungul deceniilor. Probabil că acesta este motivul pentru care blockchain-ul public Ethereum ia în considerare o tranziție la eWASM, o bifurcătură deterministă a standardului emergent WebAssembly.

Determinism prin aprobare

Când vine vorba de determinism, Hyperledger Fabric adoptă o abordare complet diferită. În Fabric, atunci când un nod „client” dorește să trimită un mesaj către un cod de lanț, mai întâi trimite acel mesaj către niște noduri „endorser”. Fiecare dintre aceste noduri execută codul de lanț în mod independent, formându-și o părere despre mesajul efect în baza de date a acelui cod de lanț. Aceste opinii sunt trimise înapoi clientului împreună cu o semnătură digitală care constituie un „aviz formal”. Dacă clientul primește suficiente aprobări cu privire la rezultatul dorit, acesta creează o tranzacție care conține acele aprobări și o difuzează pentru a fi inclusă în lanț.

Pentru a garanta determinismul, fiecare bucată de cod de lanț are o „politică de aprobare” care definește exact ce nivel de aprobare este necesar pentru a-și face tranzacțiile valabile. De exemplu, politica unui cod de lanț ar putea prevedea că sunt necesare aprobări de la cel puțin jumătate din nodurile blockchain-ului. Un alt ar putea necesita aprobarea uneia dintre cele trei părți de încredere. Oricum, fiecare nod poate verifica independent dacă au fost primite aprobările necesare.

Pentru a clarifica diferența, determinismul în majoritatea platformelor blockchain se bazează pe întrebarea: „Care este rezultatul rulării acestui cod pe aceste date?” – și trebuie să fim absolut siguri că fiecare nod va răspunde la această întrebare în mod identic. În schimb, determinismul în Fabric se bazează pe o întrebare diferită: „Suficienți susținători sunt de acord cu rezultatul rulării acestui cod pe aceste date?” Răspunsul la acesta este o chestiune destul de simplă de numărare și nu există loc pentru non-determinism să se strecoare.

Determinismul prin aprobare al lui Fabric are o serie de consecințe interesante. În primul rând, codul în lanț poate fi scris în multe limbaje de programare diferite, deoarece acestea nu trebuie adaptate pentru determinism (Go, Java și JavaScript sunt în prezent acceptate). În al doilea rând, codul de lanț poate fi ascuns de unii dintre participanții unui blockchain, deoarece trebuie executat doar de clienți și susținători (baza de date în sine este vizibilă la nivel global). În cele din urmă și mai ales, Fabric chaincode poate face lucruri care sunt interzise în alte medii blockchain, cum ar fi verificarea vremii folosind un API web online. În cel mai rău caz, în care fiecare susținător primește un răspuns diferit de la acest API, clientul nu va obține suficiente aprobări pentru un anumit rezultat și nu va avea loc nicio tranzacție. (Trebuie remarcat faptul că membrii echipei Fabric încă recomanda folosind logica deterministă în interiorul codului de lanț, pentru a evita surprizele.)

Ce preț plătește Fabric pentru această flexibilitate? Dacă scopul unui blockchain este de a elimina intermediarii dintr-o aplicație partajată bazată pe baze de date, atunci dependența Fabricii de susținători face un pas mare de la acest obiectiv. Pentru participanții în lanț, nu mai este suficient să urmeze regulile codului de lanț - au nevoie și de anumite alte noduri pentru a fi de acord că au făcut acest lucru. Și mai rău, un subset rău intenționat de susținători ar putea aproba modificări ale bazei de date care nu urmează deloc codul de lanț. Acest lucru oferă susținătorilor mult mai multă putere decât validatorii din blockchain-urile obișnuite, care pot cenzura tranzacțiile, dar nu pot încălca regulile blockchain-ului. Dezvoltatorii de aplicații Blockchain trebuie să decidă dacă acest compromis are sens în cazul lor particular.

Determinismul Țesături multicatenari Ethereum Corda
Model Promovări Timp de rulare adaptat VM construit special Timp de rulare adaptat
Limbă Go + Java + JavaScript JavaScript trăinicie Java + Kotlin
Vizibilitatea codului Contrapartide +
susținători
Blockchain Blockchain Contrapartide +
dependente
Conturi activate Nu Da Da Nu (deocamdată)

Prevenirea conflictelor

Până acum, am discutat despre modul în care diferitele platforme blockchain exprimă regulile de tranzacție în cod și cum asigură determinist că fiecare nod aplică acele reguli în mod identic. Acum este timpul să vorbim despre un al treilea aspect al confruntării noastre: Cum tratează fiecare platformă cu posibilitatea ca două tranzacții, care sunt valabile în sine, să intre în conflict una cu cealaltă? În cel mai simplu exemplu, imaginați-vă că Alice are 10 USD într-un registru financiar și difuzează două tranzacții – una trimițând 8 USD lui Bob, iar cealaltă trimițând 7 USD lui Charlie. În mod clar, doar una dintre aceste tranzacții poate fi permisă să reușească.

Două modele

Putem începe prin a grupa abordarea MultiChain și Corda asupra acestei probleme împreună. După cum s-a descris mai devreme, ambele folosesc un model de intrare-ieșire pentru reprezentarea tranzacțiilor și regulile acestora, în care fiecare intrare de tranzacție cheltuiește o ieșire anterioară a tranzacției. Acest lucru duce la un principiu simplu pentru prevenirea conflictelor: fiecare rezultat poate fi cheltuit o singură dată. Filtrele MultiChain și contractele Corda se pot baza pe platformele lor respective pentru a aplica această restricție în mod absolut. Deoarece suma de 10 USD a lui Alice este reprezentată de o tranzacție anterioară, această regulă de cheltuire unică o oprește automat să-i trimită atât lui Bob, cât și lui Charlie.

În ciuda acestei asemănări, este important să subliniem o diferență cheie în modul în care MultiChain și Corda previn conflictele. În MultiChain, fiecare nod vede fiecare tranzacție și astfel poate verifica în mod independent că fiecare ieșire este cheltuită o singură dată. Orice tranzacție care efectuează o cheltuială dublă față de o tranzacție confirmată anterior va fi respinsă instantaneu și automat. În schimb, în ​​Corda nu există un blockchain global, așa că „notarii” sunt obligați să prevină aceste cheltuieli duble. Fiecare stare de ieșire Corda este atribuită unui notar, care trebuie să semneze orice tranzacție care cheltuiește acea ieșire, confirmând că nu a fost cheltuită înainte. Participanții unui blockchain trebuie să aibă încredere în notarii pentru a respecta această regulă în mod onest, iar notarii rău intenționați pot provoca ravagii după bunul plac. Ca și în cazul aprobărilor în Fabric, acest „cheltuială unică ca serviciu” designul are avantaje în ceea ce privește confidențialitatea dar reintroduce intermediari, mergând împotriva firului blockchain. (Este important să clarificăm faptul că notarii Corda pot fi conduși de grupuri de participanți folosind un algoritm de consens, astfel încât integritatea registrului poate fi încă protejată împotriva actorilor răi individuali).

Să trecem la Ethereum. Pentru a ne aminti, Ethereum folosește contracte și mesaje mai degrabă decât intrări și ieșiri. Ca urmare, conflictele de tranzacții, cum ar fi cele două plăți ale lui Alice, nu sunt imediat vizibile pentru motorul blockchain. În schimb, ele sunt detectate și blocate de către contract care procesează tranzacțiile, după ce comanda lor este confirmată pe lanț. Atunci când procesează fiecare dintre plățile lui Alice, contractul verifică dacă soldul ei este suficient. Dacă tranzacția care plătește 8 USD lui Bob este prima, aceasta va fi procesată ca de obicei, lăsând-o pe Alice cu 2 USD în cont. Drept urmare, atunci când contractul procesează a doua tranzacție plătind 7 dolari lui Charlie, vede că Alice îi lipsesc fondurile necesare și tranzacția se întrerupe.

Ieșiri vs contracte

Până acum am văzut două tehnici diferite pentru prevenirea tranzacțiilor conflictuale – rezultate cu o singură cheltuială în MultiChain și Corda și verificarea bazată pe contract în Ethereum. Deci care este mai bun?

Pentru a ajuta la răspunsul la această întrebare, să luăm în considerare un exemplu de cont „1 din 2 cu semnături multiple” care deține 100 USD în numele lui Gavin și Helen și le permite fiecaruia dintre ei să cheltuiască acești bani în mod independent. Gavin îi cere cererii să plătească 80 de dolari lui Donna, iar câteva secunde mai târziu, Helen vrea să-i trimită 40 de dolari lui Edward. Deoarece există fonduri insuficiente pentru ambele plăți, aceste tranzacții ar intra inevitabil în conflict. În cazul în care ambele tranzacții sunt difuzate, rezultatul va fi determinat de cel care ajunge primul în lanț. Rețineți că, spre deosebire de exemplul lui Alice, acest conflict este accidental, din moment ce nimeni nu încearcă să încalce regulile aplicației – pur și simplu au avut un timp nefericit.

Luând în considerare probabilitatea ca acest conflict să apară, întrebarea cheie este următoarea: după ce Gavin își trimite tranzacția, cât timp va dura nodul lui Helen să știe că plata ei ar putea eșua? Cu cât această perioadă este mai scurtă, cu atât este mai probabil ca Helen să fie oprită să încerce acea plată, salvându-i pe ea și cererea ei de o surpriză ulterioară.

Cu modelul de intrare-ieșire, orice conflict între tranzacții este direct vizibil pentru platforma blockchain, deoarece cele două tranzacții vor încerca în mod explicit să cheltuiască aceeași ieșire anterioară. În MultiChain, acest lucru se întâmplă de îndată ce tranzacția lui Gavin s-a propagat la nodul lui Helen, de obicei într-o secundă sau mai puțin. În Corda, notarul ieșirii va refuza cererea de semnare a tranzacției lui Helen, deoarece aceasta a semnat-o deja pe cea a lui Gavin, astfel că Helen va ști imediat că plata ei va eșua. (Deși dacă notarul Corda este el însuși distribuit, ea poate fi nevoită să aștepte câteva secunde pentru un răspuns.) Oricum, nu este nevoie să așteptați ca o tranzacție să fie confirmată și comandată în blockchain.

Dar modelul lui Ethereum? În acest caz, nu există o modalitate imediată ca platforma blockchain să știe că va avea loc un conflict. În timp ce nodul lui Helen poate vedea tranzacția lui Gavin în rețea, nu poate ști cum va afecta aceasta tranzacția proprie a lui Helen, deoarece din perspectiva sa, acestea sunt doar două mesaje trimise către același contract. Poate zece secunde mai târziu, odată ce comanda finală a tranzacțiilor conflictuale este confirmată pe blockchain, nodul lui Helen va recalcula rezultatul real în loc de cel așteptat, iar aplicația ei își va actualiza afișarea în consecință. Între timp, atât Gavin, cât și Helen vor rămâne în întuneric.

Dar nu ar trebui să concluzionăm din aceasta că modelul de intrare-ieșire funcționează întotdeauna cel mai bine. Luați în considerare o variație a scenariului nostru exemplu, în care atât Gavin, cât și Helen solicită plăți mai mici de 40 USD din soldul inițial de 100 USD, exact în același timp. În modelul de intrare-ieșire, aceste tranzacții ar intra în conflict, deoarece ambii cheltuiesc același rând de bază de date care conține acei 100 USD și doar una dintre plăți ar reuși. Dar în Ethereum, ambele tranzacții ar fi procesate cu succes, indiferent de comanda lor finală, deoarece contul conține fonduri suficiente pentru ambele. În acest caz, Ethereum îndeplinește mai fidel intențiile lui Gavin și Helen.

Seturi de citire-scriere

În cele din urmă, să vorbim despre Fabric, a cărui abordare bazată pe aprobare este un hibrid al acestor două tehnici. După cum sa explicat mai devreme, atunci când un nod „client” Fabric dorește să trimită un mesaj unui contract, mai întâi le cere unor noduri de aprobare să execute acel mesaj în numele său. Nodurile de aprobare fac acest lucru într-un mod similar cu Ethereum - rulează contractul în baza lor de date locală - dar acest proces este observat mai degrabă decât aplicat imediat. Fiecare susținător înregistrează setul de rânduri care ar fi citite și scrise, notând, de asemenea, versiunea exactă a acelor rânduri la acel moment. Acest „set de citire-scriere” de rânduri versionate este menționat în mod explicit în aprobare și inclus în tranzacția pe care o difuzează clientul.

Conflictele dintre tranzacțiile Fabric sunt rezolvate odată ce comanda lor este finalizată în lanț. Fiecare nod procesează fiecare tranzacție în mod independent, verificând politicile de aprobare și aplicând modificările specificate în baza de date. Cu toate acestea, dacă o tranzacție citește sau scrie o versiune de rând a bazei de date care a fost deja modificată de o tranzacție anterioară, atunci a doua tranzacție este ignorată. Pentru a reveni la plățile conflictuale ale lui Alice către Bob și Charlie, ambele tranzacții vor citi și modifica aceeași versiune de rând, care conține cei 10 USD cu care Alice a început. Deci, a doua tranzacție va fi anulată în siguranță și automat.

Abordarea Fabric de rezolvare a conflictelor funcționează foarte bine, dar în ceea ce privește performanța și flexibilitatea combină cele mai rele dintre cele două modele anterioare. Deoarece aprobările convertesc tranzacțiile în seturi de citire-scriere specifice, plățile simultane, dar compatibile, de 40 USD ale lui Gavin și Helen ar duce la un conflict pe care Ethereum îl evită. Cu toate acestea, Fabric nu câștigă avantajul de viteză al modelului de intrare-ieșire, deoarece susținătorii execută contracte cu cea mai recentă versiune a bazei de date confirmată de blockchain, ignorând tranzacțiile neconfirmate. Deci, dacă Helen își inițiază plata la câteva secunde după Gavin, dar înainte ca Gavin să fie confirmat pe blockchain, Fabric va crea tranzacții conflictuale pe care un model pur de intrare-ieșire le evită.

Prevenirea conflictelor Țesături multicatenari Ethereum Corda
Model Seturi de citire-scriere Cheltuieli unice Verificări contractuale Cheltuieli unice
Verificare Independent Independent Independent Notari de încredere
Viteză ~10s (confirmare) ~1s (propagare) ~10s (confirmare) 0~5s (notar)

O alegere complexă

În această piesă, am trecut în revistă multe dintre diferitele moduri în care Corda, Ethereum, Fabric și MultiChain abordează provocările cheie ale „contractelor inteligente” sau codului de aplicație care este încorporat într-un blockchain. Și fiecare platformă are răspunsuri diferite la cele trei întrebări principale ale noastre: Cum sunt reprezentate regulile de tranzacție? Cum se execută codul în mod determinist? Și cum prevenim conflictele?

Deci, cine este câștigătorul confruntării noastre cu contracte inteligente? Ar trebui să fie evident până acum că nu există un răspuns simplu. Fiecare platformă reprezintă un compromis complex între flexibilitate, simplitate, performanță, dezintermediere, siguranță și confidențialitate. Deci, alegerea platformei pentru o anumită aplicație trebuie să înceapă cu o înțelegere detaliată a modelului de încredere al aplicației respective, a tipurilor de tranzacții pe care le implică și a tiparelor lor probabile de conflict. Dacă găsiți pe cineva care pregătește o anumită soluție de contract inteligent înainte de a cunoaște răspunsurile la aceste întrebări, vă sugerez să insistați politicos, dar ferm, să adopte o abordare „mai inteligentă”.

Vă rugăm să postați comentarii pe LinkedIn.

Timestamp-ul:

Mai mult de la multicatenari