Vorgurakendused 2 prax 1 2024 kevad

Allikas: Lambda

Shut-up-and-take-my-bitcoin.jpg

Ülesanne

Sul on võimalik valida kahe erineva ülesande vahel:

  • Lihtsa P2P võrgu realiseerimine ja sellele distributed ledgeri mõne aluskomponendi (mitte veel terve ledgeri) realiseerimine koos test/katsesüsteemiga.
  • Enda valitud ja õppejõuga kooskõlastatud alternatiivne sobiv ülesanne.

Mõlemil juhul on sul alustuseks vaja implementeerida lihtne P2P protokoll üle HTTP, nii et:

  • protokoll oleks realiseeritud HTTP protokolli peale (vaja implementeerida ka HTTP server ja klient)
  • mitu sinu rakenduse klooni suudavad suhelda nii samas masinas, töötades eri portide peal, kui mitmes erinevas masinas eri IP-de peal.
  • eesmärk on kõigi rakendused omavahel suhtlema ja ühise võrguna tegutsema panna

Programmeerimiskeel on vabalt valitav. Masin(ad), kus su süsteem töötab, on vabalt valitavad: võid kasutada oma laptoppi, arvutiklassi arvutit, dijkstrat või mõnda muud serverit.

NB! Siin praksis ei või kasutada nö suurt veebiserverit a la Apache, Nginx vms. Lihtsad http teegid on samas OK - näiteks Pythonisse sisseehitatud SocketServer. Ei tohiks kasutada ka veebiraamistikke a la Spring, Flask või keerukamaid implementatsioone nagu AIOHTTP: need ei ole esimese praksi jaoks mõttekad

Praktikumi lõpus pead tegema juhendajale oma grupiga väikese demo - et kuidas töötab - ja seletama natuke oma koodi ehitust. Kõik tudengid saavad demo jälgida.

Väga soovitav on teha jooksvalt demosid enne hindamist, jällegi kõigile huvilistele vaadatavana.

Kuidas alustada

Sul on kõigepealt vaja teha väike P2P rakendus, ehk proge, mis suudaks oma kloonidega suhelda. Konkreetsemalt:

  • sinu proge on käsurea rakendus ilma kasutajaliideseta
  • ta kuulab, kas temaga tahetakse võtta ühendust ja võtab ise teistega ühendust
  • tahame saavutada, et meil käib korraga N koopiat, samas masinas ja eri masinates, ja nad süngivad omavahel datat (ledgeri puhul) või saadavad päringuid teistele laiali (tori puhul).
  • "teiste kuulamine tähendab", et ta on server
  • eeldame, et ühendus toimub üle http

Kõigepealt tee nii, et sinu proge reageeriks http päringutele ja vastaks neile mingi testvastuse, et sa saaks ise aru, et ta on värgi kätte saanud.

Järgmine asi on panna ta ise teistega ühendust võtma: siis ta avab urli nagu brauser.

Küsimus, et kuidas päringuid kodeerida.

võtame GET näite urliga

  http://1.2.3.4:4500/request?param1=val1&param2=val2

siin http://1.2.3.4:4500/ ütleb, mis masinaga (1.2.3.4) ühendust võtta mis pordilt (4500) ja see

  request?param1=val1&param2=val2 

on string, mis rakendus kätte saab ja ise parsima peab, ja mida võib kodeerida ehk ka näiteks nii

  /val1/val2/


POST puhul see osa

   request?param1=val1&param2=val2 

on mittevajalik ja parem oleks teha ainult

    http://1.2.3.4:4500/ 

ja saata sisu jsoni tekstina a la

   {"param1":val1, "param2":val2}

kuigi saab ka saata postiga lihtsalt

    param1=val1&param2=val2 

mis on veidi vähem mainstream.

Mis teeb käsurea rakendus? Panen ta käima, ta jääbki käima ja trükib vajadusel debuginfot. Tal peab olema pordikuulamise tükk sees ja talle peab kuskil ütlema, et mis porti kuulata. Tal võiks olla default port a la 5134 ja saad käivitades öelda pordi a la ühes aknas

   prog.py 6345

teises aknas aga

   prog.py 7890

NB! Iga kloon samas masinas peaks olema eri pordil.

HTTP server/klient

HTTP baasil töötav protokoll näeb välja umbes järgmine:

 GET http://1.2.3.4/request?param1=val1&param2=val
 POST http://1.2.3.5/response
 ...
 param1=val1&param3=val3

jne. Seega tuleb meil teha:

  1. HTTP server, mis suudaks vastu võtta GET ja POST päringut ning parseerida pathi ja parameetrid (query stringi). Meid huvitab ka IP, kust päring tuli, see tuleb edaspidi kasutamiseks meelde jätta. POST päringu puhul peab lugema päringu "keha" (body).
  2. Selle peale peaks serveris käivituma mingi funktsioon. Selle võime jätta hetkel tühjaks
  3. Lõpuks saadame vastuse samuti HTTP päringuga. Seega vaja selleks HTTP klienti.

Server tuleb realiseerida ise, kasutades võrgust leitavaid näiteid mikro-http-serveri jaoks (tüüpiliselt paar lehekülge koodi). Selliseid näitekoode võib täiesti otse kasutada.

C jaoks on sobiv mikroserver näiteks tiny, java jaoks sobib alustuseks sisseehitatud HTTP server. Socketi tasemel alternatiividest on see server väga hea väike näide, aga selgitava tekstita, ning selgitavate tekstidega servereid leiad mh siit ja siit.Loe java socketitest põhjalikumalt siit. Pythoni serverinäite saad siit; lühem ja uuem. Http kohta võib lugeda näiteks siit.

Ülesande detailid: distributed ledgeri komponent

Ülesandel on kaks osa:

  • Põhiosa: sul on vaja kirjutada lihtne bitcoini-tüüpi rakendus, mis suudab leida oma kloone ehk sõlmi võrgus, küsida neilt olemasolevaid ledgeri plokke ja saata neile endale teadaolevaid blokke ja uusi transaktsioone (transaktsioonid on ülekanded ehk mistahes info, millest blokk kokku pannakse).
  • Katseosa: samuti on sul vaja kirjutada test/katserakendus, mis suudab käivitada suure hulga sõlmi ja panna mõned neist sõnumeid saatma, mõned sõlmed ära kaduma ja mõned lisanduma. Ehk siis, test/katserakendus simuleerib väikese P2P võrgu tööd. Sul on vaja mh testida, et kui palju sõlmi reaalselt suudab sinu võrgus (ühel masinal või paaril masinal) töötada ja mis saatmis/kadumis/lisamiskoormust ta vastu peab.

"Ledgeri blokk" võib selles praksis olla lihtsalt suvaline string või json struktuur: neid ei pea kontrollima, sünkima ega kaevandama. Piisab lihtsalt nende kogumisest ja soovijatele laialisaatmisest.

Sa võid ise valida, kas

  • realiseerid lihtsustatud protokolli, millega saad ise distributed ledgeri ehitada, ei saa aga suhelda päris-bitcoini sõlmedega.
  • või realiseerid alamhulga tegelikust bitcoini protokollist: see on tehniliselt päris keeruline (protokoll on bititasemel ja seal on palju detaile), samas saad siis ise leida päris-bitcoini võrgusõlmi ja katsetada, mis juhtub, kui neile näiteks ise ülekandeid vms saadad. Kui seda kaalud, siis loe enne bitcoini materjale kursuse põhilehel ja tutvu hardcore dokumentatsiooniga algul siit https://bitcoin.org/en/developer-guide#p2p-network ja siis siit https://en.bitcoin.it/wiki/Protocol_documentation

Nüüd detailsemalt meie oma lihtsustatud protokollist. Edaspidises eeldame, et http päringud on GET päringud, kui mõne puhul pole spetsiaalselt öeldud, et tegu on POST päringuga. Pane tähele, et sul on vaja realiseerida nii kloonide/blokkide küsimine kui nende küsimisele vastamine!

Kloonide ehk sõlmede leidmine võrgus

Klooni leidmine tähendab, et saad teada ip aadressi ja pordi, kus võiks olla töötav kloon. Sinu rakendusel peaks kõigepealt olema väike konfifail, kuhu saad kirjutada järjest mõned ip aadressid ja pordid: soovitav on see esitada teha jsoni listina. Käivitades hakkab sinu rakendus neid läbi käima ja küsima neilt, milliseid teisi kloone nad teavad. Nii kogud kokku pikema listi kloonidest. Samuti pead suutma vastata endale teadaolevate kloonide päringule.

Soovitav on realiseerida päring http protokolliga, näiteks nii:

 http://xx.xx.xx.xx:yyyy/addr

millele vastatakse kloonide json listiga, samas formaadis, kui sinu konfifailis.

Reaalse töö käigus ei ole sul vaja leida kõiki töötavaid kloone, piisab mingist "mõistlikust" hulgast.

Hea mõte on taustaks läbi lugeda need lühikesed jutud kursuse põhilehelt (arusaadavalt ei pea sa neid meetodeid realiseerima):

Ledgeri blokkide küsimine

Sul on vaja regulaarselt küsida ja kettal hoida nö ametliku ledgeri kõiki blokke. Ledger on lihtsalt blokkide list. Igal blokil on oma tekstiline id (bitcoini puhul bloki hash) ja sisu. Bloki hash tuleb arvutada bloki tekstilise esituse pealt sha-256 hashifunktsiooniga, ning konvertida hex-kujule. Hashe saadame siis alati hex-kujul.

Nagu öeldud, ei pea me esimeses praksis blokkide sisuga ja nende kontrollimisega tegelema, selleks on teine praks.

Kuna sul võib juba olla mingi hulk ledgeri blokke salvestatud, siis on kasulik saada küsida ka blokke alates mingist teadaolevast blokist (ehk tema hashist).

Blokkide järjestuse võid teha esialgu lihtsalt nii, et hoiad blokke saabumise järjekorras. Lõplikus ledgeri variandis peaks blokid olema hashchaini järjestuses (blokk N+1 hash moodustatakse bloki sisust+eelmise bloki hashist, vaata seda pilti, kus on näha bloki sees olev hashide merkle puu ja blokkide järjestus lihtsa hashiahelana), aga seda hashchaini ja kontrolli ei ole esialgu vaja teha.

Blokkide küsimine peaks välja nägema nii, et saad

  • küsida korraga blokkide nimistut ehk hashide listi (kas tervet või ainult uuemaid)
  • küsida konkreetseid blokke vastavalt nende hashidele.

Kõigi blokkide nimistu küsimine võiks välja näha nii:

 http://xx.xx.xx.xx:yyyy/getblocks

ja alates-blokist-Z nii:

 http://xx.xx.xx.xx:yyyy/getblocks/Z

kus Z on bloki id ehk hash.

Vastuseks võiksid saada bloki hashide listi.

Ühe konkreetse bloki küsimine võiks välja näha nii:

 http://xx.xx.xx.xx:yyyy/getdata/H

kus H on bloki hash, millele vastavat blokki tahad.

Uute transaktsioonide ja uute ledgeri blokkide laialisaatmine

Siin toimub tehingute ja blokkide laviinitaoline laialisaatmine kõigile kloonidele: iga kloon salvestab talle saadetud info ja saadab selle siis teistele edasi.

Sul olema võimalik omal initsiatiivil laiali saata transaktsioone ehk ülekandeid (a la Jaan kannab 2018-02-15 Antsule 0.0001 bitcoini).

See päring võiks olla POST päring, kus url on

 http://xx.xx.xx.xx:yyyy/inv

ning postitatud väärtus (st tekst peale http päiste järel olevat tühja rida) on on transaktsiooni hash ja tema json-esitus. Transaktsiooni sisu võiks esialgu olla suvaline (json) string. Sellise postitatud päringu vastuseks võiks anda kas arvu 1 kui transaktsioon aktsepteeriti või veateate (näiteks {"errcode": ..., "errmsg": ...} kui teda ei aktsepteeritud.

Kättesaadud transaktsioon tuleks salvestada ja omakorda teistele kloonidele laiali saata. Pane tähele, et kui sa oled mingi hashiga transaktsiooni saad, siis peaksid vaatama, kas ta sul juba on, ja kui on, siis mitte edasi saatma.

Samuti peab sul olema võimalik saata teistele kloonidele omal initsiatiivil uusi blokke, mis nemad peaks oma ahela lõppu lisama, kontrolle pole esialgu vaja (teises praksis hakkame tegelema blokkide kontrolli ja "ametliku" ahela sünkimisega. Blokk koosneb üldjuhul hulgast kontrollitud transaktsioonidest.

See päring võiks olla POST päring, kus url on

 http://xx.xx.xx.xx:yyyy/block

ning postitatud väärtus (st tekst peale http päiste järel olevat tühja rida) on bloki hash ja tema tekstiline sisu (vali ise, kuidas neid kodeerid). Sellise postitatud päringu vastuseks võiks anda kas arvu 1 kui blokk aktsepteeriti või veateate (näiteks {"errcode": ..., "errmsg": ...} kui teda ei aktsepteeritud.

Jällegi, kättesaadud blokk tuleks salvestada ja omakorda teistele kloonidele laiali saata. Pane tähele, et kui sa oled mingi hashiga bloki saad, siis peaksid vaatama, kas ta sul juba on, ja kui on, siis mitte edasi saatma.

Märkmeid presentatsiooni kohta

Arvesta, et sul on mitu node:

  • eristamiseks vaja porti, AGA ip ka! Siis saab mitme masinaga katsetada.
  • raporteeri, et mis juhtus mitme masinaga katsetamisel
  • raporteeri ka oma test/katserakenduse tulemustest

Protokoll suhtlemiseks:

  • tahaks aru saada protokollist
  • selleks peaks olema näitefail, kus on päringute ja vastuste näited



Tähelepanekuid P2P paremaks organiseerimiseks

P2P realiseerimise märkmeid