Skip to main content

Topic outline

  • Overview

                Acest curs este o introducere de suprafața în ce înseamnă Ethereum, ce sunt Smart Contracts, la ce folosesc și cum putem scrie (dezvolta) un smart contract.

                În a doua parte a cursului o sa dau exemple de smart contracts cu explicații iar pe final o sa vorbesc puțin despre cel mai important aspect legate de smart contracts si anume:
    SECURITATEA.


                     La finalul cursul o sa vorbesc putin despre viitorul platformei Ehterum, despre cateva materiale de studiu pentru cine vrea sa aprofundeze tehnologiile blockchain si smart contracts, si cateva intrebari si raspunsuri legate de smart contracts.





  • Platforma Ethereum

              “The world computer” – rețea descentralizată de noduri care pot executa secvențe de cod și salva rezultatele intr-o baza de date (blockchain).

    Ethereum oferă posibilitatea dezvoltării de aplicații descentralizate, oferă disponibilitate 100% (24/7) transparenta, securitate, poate fi auditat codul de orice entitate și este neutru din punct de vedere politic, guvernamental sau emotional.


    Componentele Ethereum:


               O rețea de noduri (softuri care rulează pe computer fizice sau virtuale in cloud), nodurile sunt interconectate și au scopul de a transmite (propaga) tranzacții în rețea. Anumite noduri au “dreptul” (își câștigă dreptul găsind soluții brute force la niste probleme matematice) de a scrie informație în baza de date (blockchain). Găsirea soluțiilor se face printr-un algoritm de consens numit “proof of work”. Acest algoritm totodată rasplateste pe cei care găsesc soluțiile cu ether tokens.

              

              Tranzactii - sunt de 2 tipuri, un tip muta (transfera) ether tokens dintr-un cont în altul și alt tip de tranzacție sunt reprezentate de lansari(deploy)/executii de smart contracts.

              

               EVM (Ethereum Virtual Machine) - o masina virtuala care are rolul de a executa deterministic pe baza unor reguli definite de protocolul Ethereum secvențe de cod numite smart contracts.


             Blockchain (baza de date) -
     un lanț de blocuri securizate folosind criptografia în care se salvează tranzacțiile.


     
    Cum s-a nascut ?


              2009 Satoshi Nakamoto creeaza crypto-moneda Bitcoin.


              2013 Vitalik Buterin (programator, făcea parte în comunitatea de Bitcoin) încearca sa aduca noi capabilități crypto-monedei Bitocin, dar comunitatea nu este de acord sustinand ca sunt prea ample modificările aduse monedei Bitcoin și nu a fost gandita pentru așa ceva și nu acesta e scopul ei (viziunea lui Satoshi Nakamoto).


              2013 decembrie Vitalik Buterin lansează primul whitepaper în care explica ideea din spatele rețelei Ethereum, un blockchain care sa poate executa secvențe de cod folosind o mașina Turing completa.


              2014 Vitalik Buterin și Gavin Wood rafinează ideea de la sfarsitul anului 2013 și încep dezvoltarea primului client Ethereum.


              2015 iulie 30 primul bloc Ethereum a fost minat și practic în acel moment a început rețeaua Ethereum.


    Definitii


              Unitati de moneda (ether tokens)
                          -          Cea mai mica unitate se numește “wei” si 1 eth = 1 * 10^18 wei, peste tot în blockchain                                        orice valoare este salvată în wei așadar un cont care detine 1 eth defapt detine                                                      1000000000000000000 wei
                          -          1,000 wei = 1 kilo wei (babbage)
                          -          1,000,000 wei = 1 megawei (lovelace)
                          -          1,000,000,000 wei = 1 giga wei or nanoether (Shannon)
                          -          1,000,000,000,000 wei = 1 micro ether (Szabo)
                          -          1,000,000,000,000,000 wei = 1 miliether (finney)
     
              GAS – in Ethereum ether token au scop de “combustibil” pentru rețea. De fiecare data cand trimiti tokens de la un EOA catre alt EOA sau catre un contract sau cand executi smart contract trebuie sa plătești pentru execuția tranzactiei. 

              Plata se face chiar dacă execuția s-a efectuat cu succes sau nu. Costul tranzacției este Gas limit * Gas Price. GAS limit reprezinta totalul de “litiri” pe care ești dispus sa îl consumi pentru a efectua tranzacția. 

              GAS Price reprezinta pretul pe care esti dispus să-l plătești pentru “un litru” de gas. Am folosit litru pentru a face o analogie cu gazul folosit de o masina, în esență un litru este o unitate de ethereum GAS. 

              În funcție de prețul pe care ești dispus să-l plătești pentru o unitate de gas tranzacția este mai mult sau mai puțin de interes pentru noduri și va ajunge mai repede sau mai greu în blockchain.





    • Conturi si Portofele

      Conturi (Ethereum Accounts)


                EOA (Externally Owned Account). Conturile create cu wallet-urile de mai sus sunt EOA, ele au o cheie publica (adresa publica Ethereum este generata deterministic din cheia publica) și o cheie privată generata din cuvinte.


                 Contract Accounts au asociat un smart contract si nu au o cheie privată, nu sunt deținute de o persoana și sunt controlate de codul din smart contract. Sunt create de un EOA dar deciziile ulterioare sunt luate de executia codului.


                  Atat EOA cat si Contract Accounts au adrese, pot primi si trimite ether tokens. 

                  Pentru a scrie smart contracts se poate folosi orice limbaj de programare dacă exista un framework pentru el care sa transforme codul scris în limbajul respectiv in EVM bytecode (cod interpretabil de masina virtuala Ethereum). 

                   Ethereum foundation a construit un limbaj asemanator javascript dar care este type-safe pentru a scrie smart contracts numit Solidity. In acest curs o sa prezint acest limbaj. Deși nu sunt schimbări radicale de limbaj tot ce urmează o sa fie compilabil în Solidity versiunea 0.8+.



      Portofele (wallets)


                Meta Mask – extensie de browser (orice browser bazat pe chromium)


                Jaxx liberty – un wallet care poate fi instalat atat pe desktop cât și pe mobil si merge pe orice platforma.


                Coinomi – la fel ca jaxx, deține mult mai multe monede decât jaxx și poți avea access și la rețele de test pentru anumite monede.



      Wallets vs Accounts


                Desi in multe materiale, articole și alte scrieri în presa sau internet aceste doua notiuni se confunda sau sunt folosite una in loc de cealalta este o diferenta colosala intre ele.


                Account – este o adresa Ethereum. Cheia private este generata folosind un algoritm de random (256 biti alesi aleator), acelei chei private i se cauta cheia publica corespondenta (exista o singura cheie publica corespondenta cheii private). 

                      O data determinate cheia publica se genereaza adresa Ethereum din ea. Astfel as putea concluziona că “account” este o adresa ethereum care este utilizabila doar de entitatea care deține cheia private asociată.


                Wallet – este un soft (disponibil atat pe pc cat si pe mobile sau web) care face un management al mai multor account-uri, al perechilor de chei publice și private. 

                      În general se folosesc HD Wallets acestea pornesc de la un o samanta (seed sau entropy) o secventa de 128…256 biti alesi aleator și genereaza un set de chei private și apoi publice folosind un algoritm deterministic HD insemnand Hierarchical Deterministic.


      Instalare Coinomi


                  Portofelul Coinomi are o istorie luna fiind printe pionierii domeniului, are o securitate decenta, este usor de folosit, din pacate nu are posibilitatea folosirii unei retele de test Ethereum si nu o sa il folosesc in acest curs pentru a exemplifica tranzactii. Exista varianta desktop, mobile si web.


                  Pentru a instala acest wallet navigati catre adresa https://www.coinomi.com/downloads/




                       Dupa instalare portofelul poate porni in 2 variante. 

                       Daca avem din trecut un portofel deja creeat putem sa il folosim pe acela, aplicatia pornind de la un "seed" (24 cuvinte in limba engleza) va genera toate adresele din protofel si utilizatorul is poate vedea balanta si efectua tranzactii. 

                       Daca nu avem un portofel putem crea unul acum. Pentru a crea un portofel aplicatia ne va genera 24 cuvinte aleatorii in limba engleza pe care ne cere sa le salvam undeva si ele vor fi folosite ulterior pentru a generea adrese Ethereum (sau alte monede disponibile in Coinomi).






                 Foarte important este sa salvati undeva aceste cuvinte, cel mai sigur pe un mediu extern PC-ului, o hartie cel mai bine. Daca ati pierdut aceste cuvinte si ulterior din varii motive nu mai puteti porni aplicatia nu exista nicio posiblitate reala de mai avea acces la fondurile din wallet.

                   In continuare aplicatia va cere sa introduceti cuvintele pentru a se asigura ca le aveti salvate si optional va cere si parola cu care sa protejati aplicatia.





                  In continuare aplicatia va cere pentru ce monede sa genereze adrese (sunt foarte multe monede disponibilie in aplicatia Coinomi), poate nu toate monedele sunt de inters pentru utilizator. Odata terminat acest proces aplicatia se deschide si poate fi folosita.






      Instalare portofel MetaMask

               Portofelul MetaMask este unul dedicat Ethereum si poate fi instalat ca o extensie de Chrome (sau orice browser compatibil). MetaMask este mai mult decat un wallet obisnuit dar mai multe pe tema aceasta mai tarziu in curs.

               Pentru a instala MetaMask trebuie sa navigati la https://metamask.io/. 


               


                 Dupa instalare MetaMask va cere o parola cu care sa protejati portofelul si apoi va genera un set de cuvinte in limba engleza pe care va cere sa le pastrati pentru a putea reface portofelul in caz ca ceva se strica si nu mai aveti acces la el. Este foarte important sa salvati undeva sigur aceaste cuvinte, pierderea acestor cuvinte face imposibila vreodata refacerea portofelului.


         




                Dupa ce ati terminat procesul de instalare portofelul este creat si puteti avea acces la el. Spre deosebire de Coinomi MetaMask are posibilitatea de a conecta portofelul la mai multe retele Ethereum, atat cea "main" (reteaua principala Ethereum singura in care Ether tokens au valoare) cat si la retelele de test Ropsten, Kovan, Rinkeby, Goreli dar si la o retea de test care ruleaza pe un server propriu sau chiar pe PC-ul propriu. Un exemplu de astfel de retea este Ganache, utilitar care implementeaza intocmai masina virtuala Ethereum si face parte din suita Truffle.


      Retelele de test Ethereum


      Ropsten

      • Algoritmul de consens este Proof of Work
      • Clienții care suporta aceasta rețea sunt: Geth, Besu
      • Este rețeaua care reproduce cel mai bine rețeaua main a Ethereum, și este cea mai buna pentru a testa un smart contract.


      Kovan
      • Algoritmul de conses este Proof of Authority
      • Clienții care suporta aceasta rețea sunt: OpenEthereum, Nethermind



      Rinkeby
      • Algoritmul de conses este Proof of Authority
      • Clienții care suporta aceasta rețea sunt: Geth, Besu, OpenEthereum, Nethermind



      Goreli
      • Algoritmul de conses este Proof of Authority
      • Clienții care suporta aceasta rețea sunt: Geth, Besu, OpenEthereum, Nethermind






      • Tranzactii in Ethereum


        Ethereum clients (aproximativ 6500 online luna iulie 2021):


                   
         Clienții Ethereum oferă un API și un set de comenzi RPC (Remote procedure call) care primesc și răspund folosind obiecte JSON. Interfata RPC este expusă prin protocolul HTTP și rulează în mod implicit pe portul 8545, tot în mod implicit acceptand conexiuni doar de pe localhost.


                   Geth clientul -
        cel mai folosit scris în GOLang de Ethereum foundation (87%)
                   OpenEthereum - al doilea cel mai intalnit clienți scris în Rust (8%)
                   Erigon - mare parte scirs in GOLang  (3%)
                   Nethermind scris in C# (1%)
                   Turbo-geth scris in C++ (0.5%)
                   Besu - scris in Java (0.2%)



        Tranzactii


                  
        Tranzacțiile în Ethereum sunt semnate folosind cheia privată si ulterior sunt verificate semnaturile folosind cheia publica astfel cheile private nu sunt parte din blockchain și nu sunt expuse niciodată. Ele sunt ținute secret de fiecare utilizator și nu este nevoie de ele în funcționarea rețelei. 


                   Singurul moment cand este nevoie de cheia privată este la momentul semnării tranzactiei. Acest lucru este valabil pentru  toate criptomonedele care folosesc chei publice/private.


                   Pentru a crea o semnătura în Ethereum se folosesc detaliile tranzactiei ca mesaj. Tranzacția este trimisă către retea impreuna cu semnatura si reteaua folosind cheia publica poate verifica este legitima mutarea de ether tokens sau executia de smart contract.
         


        Structura tranzactiei


                      Nonce –
        o secventa numerica generate de EOA pentru a genera o ordine a tranzacțiilor de exemplu nu este o validă o tranzacție cu nonce 2 dacă nu au existat în prealabil tranzacțiile cu nonce 0 și 1. In acest fel se previn incercari de frauda; dacă se genereaza 2 tranzacții identice ele trebuie sa aiba nouce diferit și astfel una va fi validată și scris în blockchain a doua ne mai fiind validă.


                      Gas price
        prețul gazului în wei pe care cel care creeaza tranzacția este dispus să-l plătească


                      Gast limit
        gazul maxim pe care cel ce creeaza tranzacția este dispus să îl consume


                      Recipient
        adresa de destinatie ethereum


                      Value
        valoare de ether tokens pe care vrei sa o trimiti


                      Data
        o secventa variabila de date binare


                       v,r,s
        3 componente specifice algoritmul ECDSA ale celui care creeaza tranzacția
         


        Tranzacții speciale:


                   Creare de smart contracts -
        tranzacții care au ca destinatie adresa 0x0, aceasta adresa nu corespunde unui EOA și nu poate fi sursa a unei tranzacții pe viitor este destinata doar creării de un smart contract nou. Tranzactia contine doar “data payload” si este secventa binara de bytecode a contractului compilat, poate conține și o cantitate de Ether tokens in campul “value”, respectivii tokens fiind detinuti de smart contract.


                    Ardere (burn) ether tokens -
        tranzacție cu destinatie adresa specială și este folosită pentru a distruge ether tokens (adresa:0x000000000000000000000000000000000000dEaD)

                     Execuție de smart contracts - este similară cu tranzacția care creeaza un smart contract în campul “from” care este adresa celui care executa un smart contract, campul “to” contine adresa contractului, campul “value” poate contine o valoare dacă vrem sa trimitem ether tokens către smart contract altfel este 0, campul “data” contine selectorul functiei ce va fi executată și eventualele argumente ale ei encodate intr-un sir de bytes. Campurile “gas limit” si “gas price” au acelasi rol ca în orice timp de tranzactie.
         





        • Smart Contracts


          Smart Contracts – ce sunt?


                       C
          onceptul de smart contract a apărut undeva în anii 90 când Nick Szabo a teoretizat prima data ideea unui contract care sa fie executat (pus in aplicare) de computer.


                     
           Prima definite ar fi sunat asa: a set of promises, specified in digital form, including protocols within which the parties perform on the other promises(Nick Szabo). 

                       Practic era ideea de a scrie o secvență de cod prin care sa se poată verifica niște promisiuni dintre doua parti și în funcție de realizarea lor sau nu, computerul sa ia niște decizii.



           
                     În zilele noaste o definiție mai riguroasă în contextul Ethereum ar fi immutable computer programs that run deterministically in the context of an Ethereum Virtual Machine as part of the Ethereum network protocol(Andreas Antonopoulos).


                        Cuvantul “contract” nu are vreo valoare legală, un smart contract este un cod executabil care este stocat in blockchain (imuabil - nu mai poate fi modificat după ce a fost creat). 

                        Deterministic insemana ca pentru un anume input va produce acelasi output ori de cate ori vom rula un smart contract (este important pentru ca toate nodurile din rețea trebuie sa execute același smart contract si sa verifice output-ul). 

                        În contextul EMV se referea la faptul ca un contract poate sa acceseze date lui (state-ul propriu) informații despre tranzacția curentă și despre blocul în care va fi stocat.

                         Un smart contract este definit de o clasa (asemanator programarii OOP), pe baza acestei clase se creeaza un sigur obiect (Singleton). Un contract poate mosteni alt contract si este prezent si conceptul de interfata pe care un contract o poate implementa. 

                          Prin intermediul interfetelor un contact poate apela alt contract.

                          La fel ca in conceptul OOP un contract are un constructor care se apeleaza cand un contract este salvat (deploy) in blockchain.


          Componentele principale ale unui smart contract


                          Partea de date care se mai numește și state. În aceasta zona sunt salvate date și de fiecare data cand se modifica ceva se face o noua “poza” a datelor și aceasta este salvată în blockchain. 

                          Practic se poate vedea istoricul execuțiilor unor metode ale unui smart contract, toate executiile sunt in blockchain, deci execuția este transparenta, blockchain-ul fiind public.


                          Metodele care se executa sunt de 2 tipuri


                         Metode care schimba zona de date - aceste metode sunt executate si scrise in blockchain de un nod (cel care gaseste solutia PoW) si acesta percepe o taxa in gas (ether tokens) care este proporțională cu număr de instrucțiuni pe care EVM a trebuit sa le execute, apoi toate celelalte noduri verifica execuția

                         Metode care doar citesc din zona de date - aceste metode sunt executate doar de un nod și nu costa nimic (ma refer la gas - ether tokens)



           
          Primul smart contract

                         Un smart contract se scrie în limbaje de nivel înalt (în acest curs o sa folosesc Solidity) si apoi este compilat in bytecode de EVM.

                         După ce se compilează și se obține un șir de bytes, acest șir este adaugat în zona de date a unei tranzacții speciale și este scris în blockchain odată cu ea. Foarte important este faptul ca executia unui smart contract trebuie initiata printr-o alta tranzactie, acest cod nu se va executa niciodată singur.




          Zona de date (state) contine doar un intreg, campul “number


          Acest smart contract are doua metode


          function add() public” este rulata de fiecare nod si costa gaz pentru ca modifica zona de date a smart contractului deci adaugă informație în blockchain


          function get() public view return(uint256)” este rulata doar de un singur nod și citește din zona de date a smart contractului și returnează valoare campului “number”


                       ABI (Application Binary interface) - în general este o interfata intre 2 componente software în general între sistemul de operare și un soft creat de programator și definește cum structurile și funcțiile sunt accesate în cod mașină. În Ethereum folosim ABI pentru a coda apelurile metodelor unui smart contract și pentru datele returnate.


          Un exemplu este 


          [{"inputs":[],"name":"add","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"get","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]


                        Acest ABI descrie 2 metode pentru un smart contract: una care nu primește niciun parametru si nu returneza nimic si se numește “add” și cealaltă care nu primește niciun parametru dar returnează un întreg și se numește “get”.


          Executia unui Smart Contract


                    Primul pas este salvarea (deploy) in blockchain a contractului si acest lucru se face printr-o tranzactie speciala, si se executa constructorul (metoda speciala care se defineste cu ajutorul cuvantului cheie constructor).  

                     Tranzactia consuma o cantitate de gaz, gazul trimis in tranzactie trebuie sa fie mai mare decat cel consumat altfel tranzactia esueaza si contractul nu ajunge in blockchain. 

                      Daca este o diferenta intre limita de gaz a tranzactiei si gazul consumat diferenta este returanata celui care a creat tranzactia.




                           Dupa ce a fost salvat in blockchain un contract este instantiat se creeaza primul state si poate fi "executat", se pot apela metodele lui (daca au modificatori de acces corespunzatori). In continuare o sa apelez metodele add si get succesiv.






                    Apelul metodei add se face cu consum de gaz deoarece schimba zona de date (state) a smart contract-ului incrementand proprietatea number.


                    Apelul metodei get se face fara consum de gaz, ea nu schima state-ul, doar returneaza o parte din state. In cazul de fata state-ul este format doar din campul "number" dar in genereal o metoda de acest fel returneaza o parte din state.


                    Ambele metode nu primesc parametrii, ele pot primi parametrii si pot modifica state-ul folosind acei parametrii sau pe baza lor pot returna parti din state.


                   






          • Limbajul Solidity


                       Este un limbaj de nivel înalt creat inițial de Gavin Wood și este din punct de vedere al sintaxei asemanator cu javascript dar este un limbaj type safe (fiecare variabila/obiect are un tip de date stiut in faza de compilare).


                       Tipuri de date

                       Boolean (bool) - valori posilibe true sau false


                       Integer (int/uint) -
            întregi cu semn sau fără semn în increment de 8 biți de la int8 la int256 ( (u)int este alias pentru (u)int256)


                      Fixed point (fixed/ufixed) -
            numere raționale cu sau fără semn, se pot folosi ufixedMxN unde M este numărul de biți pe care este reprezentat și N numărul de zecimale, M este increment de 8 de la 8 la 256 si N este de la 0 la 80, (u)fixed este alias pentru (u)fixed128x18


                      Address (address) -
            reprezinta un sir de 20 bytes si este o adresa Ethereum
                      

                     Fixed Byte array (bytes1..32) - reprezinta un vector de bytes cu lungime fixa bytes1 pana la bytes32


                     Dynamic size arrays (bytes) -
            reprezinta un vector de bytes cu lungime variabila


                     String (string) -
            sir de caractere codat in UTF-8


                     Enum (enum) -
            tip enumerare cu valori întregi care încep de la 0


                     Structs (struct) -
            tipuri complexe de date


                      Mapping (mapping) -
            hash tables, cheile nu sunt stocate doar un hash al lor folosind algoritmul de hashing din Ethereum care este keccak256. Aceste structuri de date nu se pot enumera.


                      Unitati de timp
                      

                      Contin sufixe ca seconds, minutes, hours, days, weeks, years NU exista s-a renuntat la el de la solidity 0.5  (ex 1 minutes == 60 seconds)

                      Variabile si functii legate de tranzactii si blocuri (cand folosesc “returnează” nu mă refer la funcții, cand e vorba de funcții o sa fie prezent cuvantul “returns” in definiție)


                      blockhash(uint) returns (bytes32) -
            returnează hash-ul blocului după număr. Funcționează pentru ultimele 256 de blocuri altfel returnează 0


                      block.chainid -
            returneaza chain-ul curent


                      block.coinbase -
            returnează adresa contului nodului care a scris informatia in blockchain


                      block.gaslimit (uint) -
            returnează limita de gaz a tranzactiei


                      block.number (uint) -
            returnează numărul blocului curent


                      block.timestamp (uint) -
            returnează un număr întreg “unix time” reprezentand ziua/ora blocului curent


                      gasleft() returns (uint256) -
            returnează cat gaz a mai rămas


                      msg.data (bytes) -
            returnează un șir de bytes reprezentand apelul curent


                      msg.sender (address) -
            returnează adresa care a apelat metoda (poate fi EOA sau alt smart contract)


                      msg.value (uint) -
            returnează valoarea de ether token (daca e cazul) cu care a fost apelata metoda, valoarea este exprimata in wei


                      tx.gasprice (uint) -
            returnează prețul gazului setat în tranzacție


                      tx.origin (address) -
            returnează adresa celui care a creat tranzacția, spre deosebire de msg.sender aici gasim EOA - ul care a creat tranzactia


                       Obiectul address


                       address.balance -
            returneaza adresa balantei


                       address.transfer(value) -
            transfera valoarea către aceasta adresa din contul contractului


                       address.send(value) -
            la fel ca transfer doar ca returnează false la eroare, nu excepție


                       address.call(payload) -
            apeleza metoda de la adresa respectiva a unui smart contract


                       keccak256, sha256, sha3, ripemd160 -
            funcții pentru a calcula diferite hash-uri


                       Modificatori de acces


                       public -
            metoda poate fi apelata de orice EOA or contract


                       external -
            la fel ca public doar ca nu pot fi apelat de contract in sine


                       internal -
            pot fi apelata de contract si de cele mostenite din el, un fel de protected in OOP


                       private -
            pot fi apelate doar de contract


                       view -
            metoda nu are voie sa modifice zona de date (state) a contractului


                       pure -
            nu citește și nu modifică state - ul contractului, un fel de helper echivalent cu static într-o clasă care nu este statică


                       payable -
            catre acest gen de metode se pot trimite ether tokens




                       Error Handling


                       assert -
            termina executia cu eroare, se folosește pentru a testa condiții interne unde ne așteptam ca rezultatul sa fie true


                      require -
            se folosește pentru a testa input-ul


                      revert -
            termina execuția și ignora modificările de stare ale contractului


                      

                       Solidity nu este limbaj greu, poate fi invatat cu usurinta, de asemenea conținutul unui smart contract în general nu este foarte complex și cu toate acestea arta dezvoltării de smart contracts este una care se dobandeste timp și cere foarte multa experienta atat în dezvoltarea de software cât și în a înțelege cum funcționează EVM.


                       Cand dezvolți un smart contract spre deosebire de o aplicație clasică centralizata apar unele probleme:
            odata salvat in blockchain, un smart contract nu mai poate fi modificat de aceea nu trebuie sa uităm niciun feature și dacă vrem sa îl puteam folosi în viitor cu cerințe suplimentare trebuie sa facem metode cât mai generale nu trebuie sa aiba “buguri” pentru ca NU le mai putem repara.


                       Securitatea e foarte importantă deoarece codul este public si cu usurinta dacă am omis ceva sau am făcut o greșeală, ea poate fi exploatată




            • Programarea unui Smart Contract


                        In continuare voi creea un smart contract prin care o persoana va putea sa isi protejeze un document (in special este destinat documentelor de proprietate intelectuala dar practic se poate folosi orice fisier). Prin a proteja se intelege ca la un moment de timp se poate genera un HASH al documentului, acest hash este salvat in blockchain si ulterior putem demonsta aratand documentul ca este prorpietatea celui care a salvat hash-ul in blockchain.
                 
                         Contractul va avea si posibilitatea transferarii acestui document (drept de proprietate intelectuala catre altcineva). Schimbarea dreptului se va face in 2 pasi, platforma Ethereum va avea grija ca informatia sa fie scrisa in blockchain si primul detinator al documentului sa fie recompensat cu suma ceruta.


                           Codul sursa al smart contractului se gaseste in continuare:


              // SPDX-License-Identifier: GPL-3.0

              pragma solidity >=0.7.0 <0.9.0;


              contract PI {

                      // unique document id 

                      uint256 hCount;


                      // doc owner address => doc id => document info

                      mapping(address => mapping(uint256 => PIData)) public documents;

                      

                      // count documents per address ... doc owner address => number of documents

                      mapping(address => uint256) documentsCount;


                      mapping(string => address) fileHashes;


                      // doc owner address => doc id => buyer address => amount

                      mapping(address => mapping(uint256 => mapping(address => uint256))) public pendingTransfers;


                      struct PIData  {

                          // document unique id

                          uint256 id;

                          address ownerAddress;

                          string name;

                          string fileHash;

                          uint time;

                      }


                      constructor() {

                              hCount = 1;

                      }


                      // document functions add/verify/get documents from blockchain

                      function AddDocument(string calldata _name, string calldata _fileHash) public {

                              require(fileHashes[_fileHash] == address(0x0));

                              documents[msg.sender][documentsCount[msg.sender]] = 

                                              PIData(hCount, msg.sender, _name, _fileHash, block.timestamp);

                              documentsCount[msg.sender] ++;

                              hCount++;

                              fileHashes[_fileHash] = msg.sender;

                      }


                      function OwnerDocumentCount(address _ownerAddress) public view returns (uint256) {

                              return documentsCount[_ownerAddress];

                      }


                      function VerifyDocumentId(address _ownerAddress, uint256 _id) public view returns (uint, bool, string memory) {

                              for (uint i = 0; i < documentsCount[_ownerAddress]; i++) {

                                      if (documents[_ownerAddress][i].id == _id)

                                              return (documents[_ownerAddress][i].time, true, documents[_ownerAddress][i].fileHash);  

                              }

                              return (0, false, "not found");

                      }



                      function Verify(address _ownerAddress, string memory _fileHash) public view returns (uint256) {

                              for (uint i = 0; i < documentsCount[_ownerAddress]; i++) {

                                      if (compareStrings(documents[_ownerAddress][i].fileHash, _fileHash))

                                              return (documents[_ownerAddress][i].id);        

                              }

                              return (0);

                      }



                      // transaction functions

                      function RequestTransfer(uint256 _docId, address _ownerAddress) public payable {

                              for (uint i = 0; i < documentsCount[_ownerAddress]; i++) {

                                              if (documents[_ownerAddress][i].id == _docId) {

                                                      require(pendingTransfers[_ownerAddress][_docId][msg.sender] == 0);

                                                      pendingTransfers[_ownerAddress][_docId][msg.sender] += msg.value;

                                              }

                              }

                      }


                      function CancelTransfer(uint256 _docId, address _ownerAddress) public  {

                              require(pendingTransfers[_ownerAddress][_docId][msg.sender] > 0);

                              payable(msg.sender).transfer(pendingTransfers[_ownerAddress][_docId][msg.sender]);

                              pendingTransfers[_ownerAddress][_docId][msg.sender] = 0;

                      }


                      function CompleteTransfer(uint256 _docId, address _buyerAddress) public {

                              require(pendingTransfers[msg.sender][_docId][_buyerAddress] > 0);

                              for (uint i = 0; i < documentsCount[msg.sender]; i++) {

                                      if (documents[msg.sender][i].id == _docId) {

                                              require(documents[msg.sender][i].id > 0);


                                              PIData storage pid = documents[msg.sender][i];


                                              documents[_buyerAddress][documentsCount[_buyerAddress]] = 

                                                      PIData(_docId, _buyerAddress, pid.name, pid.fileHash, pid.time); 

                                              documentsCount[_buyerAddress] ++;


                                              DestroyDocument(msg.sender, _docId, _buyerAddress);

                                              break;

                                      }

                              }

                              payable(msg.sender).transfer(pendingTransfers[msg.sender][_docId][_buyerAddress]);

                              pendingTransfers[msg.sender][_docId][_buyerAddress] = 0;

                      }


                      function DestroyDocument(address _adr, uint256 _id, address _buyerAddress) private {

                              for (uint i = 0; i < documentsCount[_adr]; i++) {

                                      if (documents[_adr][i].id == _id)

                                          {

                                              documents[_adr][i].id = 0;

                                              documents[_adr][i].ownerAddress = _buyerAddress;

                                              documents[_adr][i].name = "information transfered";

                                              documents[_adr][i].fileHash = "N/A";

                                              documents[_adr][i].time = block.timestamp;

                                              break;

                                          }       

                              }


                      }


                      // helper functions

                      function compareStrings (string memory a, string memory b) private pure returns (bool) {

                                   return keccak256(abi.encodePacked(a)) == keccak256(abi.encodePacked(b));

                       }


              }


                         Contractul are o parte in care se salveaza date (state) si care contine:


                               - o proprietate de tip uint care stocheaza numarul documentului curent si implicit numarul de documente din contract 


                               - o structura de tip mapping in care se face referinta intre o addresa (identitatea unei persoane) si alta structura de tip mapping care are ca referinta numarul documentului si informatiile despre el. Informatiile despre document sunt tinute intr-o structura PIData, un membru important al acestei structuri fiind fileHash care contine hash-ul documentului,


                                - o structura de tip mapping ce are ca referinta o adresa si valoare  numarul de documente ale persoanei


                                - o structura de tip mapping pentru a corela adrese cu hash-uri de documente


                                - o strucutra de tip mapping destinata memorarii transferurilor intre documente



                          Contractul contine cateva metode publice prin care putem vizualiza continutul lui (state-ul) si metode prin care putem adauga continut nou initia si termina un transfer sau anularea unui transfer.


                           Metoda AddDocument este folosita pentru a a adauga un document in smart contract (state), metoda face o verificare pentru a nu exista in prealabil hash-ul respectiv salvat in blockchain


                                      require(fileHashes[_fileHash] == address(0x0));

                           si foloseste adresa celui care a apelat-o (msg.sender) pentru a face o corelatie intre hash-ul documentului si cel care detine documentul. Astfel adaugarea de document in blockchain se face prin apelul acestei metode in cadrul unei tranzactii, tranzatia fiind semnata de msg.sender.



                          Metoda OwnerDocumentCount este o metoda de tip "view" (nu costa nimic apelarea ei) si returneaza numarul de documente ingrestrate pe o anumita adresa.



                          Medoda VerifyDocumentId este o metoda de tip "view" si oricine poate verifica un document dupa id ca este adaugat de anumita adresa (deci este in posesia celui care detine cheia privata asociata adresei respective).


                          
                          Metoda Verify este identica cu metoda VerifyDocumentId, singura diferenta fiind ca verifica un document dupa hash.
                          


                          Metoda RequestTransfer este o metoda "payable" (metoda poate fi apelata doar daca tranzatia care o executa are si o valoare in ehter tokens, respectiii tokeni sunt transferati in smart contract. Metoda verifica sa nu se mai fi inceput un transfer pentru documentul respectiv


                               require(pendingTransfers[_ownerAddress][_docId][msg.sender] == 0);
                          


                          Metoda CancelTransfer poate fi apelata doar de cel care initiat transferul si acest lucru este verificat


                              require(pendingTransfers[_ownerAddress][_docId][msg.sender] > 0);


                          si are ca scop anularea transferului si restituirea ether token-ilor celui care a initiat un transfer.


                          Metoda CompleteTransfer este o metoda ce poate fi apelata doar de detinatorul unui document 


                             require(pendingTransfers[msg.sender][_docId][_buyerAddress] > 0);


                          ea distruge documentul existent si creeaza unul nou care are ca detinator pe cel care a initiat transferul, apoi plateste suma trimisa de cel care a initiat transferul fostului detinator.  


                           Acesta metoda asigura atat pe cel care vrea sa cumpere un document ca o sa primeasca documentul cand o sa i se cheltuie ether tokenii, dar si pe cel care detine documentul ca va primii ether tokenii cand se transfera documentul. In acest fel fiecare dintre cei doi participanti la transfer nu trebuie sa se cunoasca in prealabil si pot avea incredere unul in celalalt pentu ca reteaua ethereum este arbirtul suprem al tranzactiei


              • Viitorul platformei Ethereum


                            Platforma Ethereum de la lansare si pana acum a avut numeroase imbunatatiri, unele fiind programate inca de la inceputuri, altele fiind dezvoltate pe parcursul ultimilor ani, unele din diferite nevoi altele pentru a corecta anumite imperfectiuni.


                           Fundatia Ethereum esre responsabila pentru dezvoltarea platformei dar ideile vin din cominitate, astfel se creeaza asazisele propuneri de imbunatatire EIP (Ethereum Improvement Proposal) prin care oricine poate propune noi functionalitati sau idei ce pot fi implementate in platforma. Fundatia analizeaza impreuna cu comunitatea EIP-uri si daca se decid impreuna ele se implementeaza si platfoma se dezvolata in directia respectiva.


                           Cel mai importanat "upgrade" ce urmeaza in viitorul apropiat este trecerea de la proof-of-work la proof-of-stake, upgrade ce va permite o viteza mult mai mare a retelei de a procesa tranzactii si implicit a scrie informatie in blockchain.


                           Adoparea de catre mase a acestei platforme se va face in momentul in care vor exista aplicatii usor de folosit care vor permite unei entitati (persona sau companie) sa creeze cu usurinta un smart contarct. Dezvoltarea unui smart contract nu este ceva foarte complicat si daca vom ajunge sa putem creea procese vizuale din interfete grafice care ulterior sa fie transformate in cod executabil pentru o masina virtuala Ethereum oricne cu o gandire usor analitica va putea sa transpuna contracte / intelegeri scrie pe harite astazi in "smart contracts" si asta va schimba cu totul paradigma increderii intre noi. 
                   
                           Nu suntem aproape de a creea automat "smart contracts" si de a putea traduce orice intelegere verbala in cod executabil de computer care sa aiba si metode pentru a verifica intelegerea dar nici nu suntem foarte departe. 


                            Domeniul blockchain este intr-o continua dezvoltare si perfectionare si probabil cea mai dezvoltata ramura este si va avea legatura cu "smart contracts".



                • Materiale de studiu


                  Andreas M. Antonopoulos Mastering Bitcoin: Programming the Open Blockchain. O'Reilly Media.


                  Andreas M. Antonopoulos; Gavin Wood Ph. D.. Mastering Ethereum. O'Reilly Media.


                  https://blockchainlab.com/pdf/Ethereum_white_paper-a_next_generation_smart_contract_and_decentralized_application_platform-vitalik-buterin.pdf


                  https://www.taurushq.com/articles/20201127_ETH2_0/20201127_Ethereum_2.0_Introduction.pdf


                  https://docs.soliditylang.org/en/v0.8.7/


                  https://ethereum.org/en/eth2/beacon-chain/