Nauči šta je blockchain tako što ćeš napraviti svoj

Najbolji način da shvatimo suštinu blockchain tehnologije jeste da se upoznamo sa njenom primenom na praktičnom primeru. A koji je bolji praktični primer nego da napravimo svoj Blockchain?

Čedomir Rackov - 19. Jun, 2018.

Kako bi dedi objasnio šta je blockchain?

“Deda, to je knjiga iz koje se ne mogu isčupati stranice!”

– Aleksandar Čolić, naš Project Manager

Svakih nekoliko godina doleti brdo novih tehnologija, ali malo koja je brže postigla popularnost od blokchaina. Kao što svi znamo, u svet popularnih tehnologija blockchain je došao zahvaljujući Bitcoinu, najpoznatijoj kriptovaluti.

Drugim rečima, Bitcoin, kao i ostale kriptovalute, je baziran na ovoj novoj tehnologiji i predstavlja ideologiju digitalnog novca i uopšte novog finansijskog sistema. Ovaj sistem isključuje banke kao posrednike svih većih novčanih transakcija, i omogućava slanje novca između bilo koje dve osobe bez posrednika, bez obzira na to gde se nalaze ili koliki iznos šalju.

To je lepo u teoriji, ali kako bismo baš mi došli do toga da želimo da koristimo neku kriptovalutu?

Bez obzira na to da li nas interesuje samo da čujemo više o blockchain tehnologiji ili želimo da je koristimo važno je da shvatimo šta je ova tehnologija u suštini. Najbolji način da shvatimo tu suštinu je da se upoznamo sa njenom primenom na praktičnom primeru. A koji je bolji praktični primer nego da napravimo svoj Blockchain?

(Ako imaš ogromnu želju da samo uskočiš u kod što pre i već znaš osnove kriptovaluta i tehnologiju iza njih, možeš da preskočiš sledeće poglavlje.)

Idemo na piće

S drugarima izlazimo na piće s vremena na vreme. Nemamo uvek svi sitno, pa kad dođe vreme da se plati račun, često nije izvodljivo da svako plati svoj deo. Onda se obično desi da jedna osoba plati sve ili napravimo neku drugu kombinaciju.

Da bismo ovo izbegli možemo da se dogovorimo da beležimo ko je kome platio šta. Predaju novca jedan drugom beležimo u neku zajedničku beležnicu kako ne bismo nakon svakog pića morali da lupamo glavu oko vraćanja novca osobi koja je platila drugima. Dogovor je da ćemo na kraju svakog meseca da izimirimo dugove i da nastavimo beleženje za sledeći mesec. I tako beležimo transakcije — „Ana je dala Peri 200 dinara”, „Pera je dao Miki 300 dinara”, „Ana je dala Jovani 100 dinara”. Tu nastaje problem.

Šta ako neko odluči da se prosto ne pojavi na kraju meseca iako duguje ostalima veću količinu novca?

Zato možemo da promenimo dogovor. Umesto da na kraju meseca izmirujemo dugovanja, nalazimo se na početku meseca i stavljlamo na zajedničko mesto po 5.000 dinara. Tada upišemo u beležnicu za svakoga ko je priložio novac — „Pera je dao 5.000 dinara”, „Ana je dala 5.000 dinara”. Tako smo sigurni da niko ne može da nestane sa neizmirenim dugom. U isto vreme, pre svakog upisivanja transakcije proveravamo da niko nije upisao da je dao više novca nego što ima.

Međutim, pojavljuje se sledeći problem. Šta ako Pera odluči da zabeleži lažnu transakciju i napiše da je Ana njemu dala 2.000 dinara? Odnosno, sada moramo da budemo sigurni da se pri upisivanju transakcije onaj koji daje novac slaže s tim. To možemo da rešimo tako što ćemo za svaku transakciju da zahtevamo potpis osobe koja šalje novac.

Koji se problem sada pojavljuje? Pera zna da falsifikuje potpise.

Tu u pomoć dolazi kriptografija. U slučaju digitalnih potpisa, koji su nam potrebni, koristi se takozvana „public key” kriptografija (za one koji ne znaju šta je to preporučujem da pogledaju primere na Wikipediji). Osnova je u tome da je ovakve potpise skoro nemoguće falsifikovati, a vrlo je lako proveriti da li je potpis pravi.

Ako jedan od naših drugara drži kafić, može i on da se priljuči zajedničkom beleženju transkacija, pa tako da ne moramo ni njemu da predajemo novac svaki put kad sednemo da popijemo kafu u njegovom lokalu. Na ovaj način polako dobijamo sistem koji nam omogućava da nikad ne koristimo pravi novac i sve možemo da rešimo upisivanjem transakcija u zajedničku beležnicu.

Ipak, problemi i dalje nisu iscrpljeni. Šta se dešava ako se izgubi beležnica? Gube se sve informacije. Rešenje ovog problema je da svako kod sebe drži kopiju beležnice. Kad se napravi nova transakcija, osoba koja ju je napravila šalje je svim ljudima koje zna, a ako dobije od nekoga gotovu transakciju, samo je prosleđuje ostalima.

To je Blockchain i njegova primena u finansijkom svetu. Iz ovoga se situacija razvila, pa su se ljudi zapitali šta je sa drugim tipovima informacija koji želimo na siguran način da beležimo? Šta ako umesto transakcija želimo da upisujemo neke druge informacije? Time ulazimo u srž blockchaina.

Tvoj Blockchain

Koje komponente čine blockchain? Da bismo odgovorili na ovo pitanje koristićemo primere sa github projekta NaiveChain koje je objavio Lauri Hartika pod Apache 2.0 licencom. (Toplo preporučujem da se poigrate ovim projektom.)

U ovom trenutku preporučljivo je da znamo osnove JavaScripta, kao i osnove WebSocketa, http protokola i Express biblioteke za pisanje http servera u JavaScript jeziku.

(Za više informacija preporučujem tekst „A blockchain in 200 lines of code” na Medium.com koji je takođe napisao gore pomenuti Lauri Hartika.)

Blockchain

Zahvaljujući njenoj nagloj popularnosti postoji veliki broj definicija ove tehnologije. U osnovi, to je distribuirana baza podataka koja kriptografiski onemogućava brisanje i izmenu podataka. U zavisnosti od projkta blockchain može biti i mnogo više. Primer je Ethereum projekat koji pretstavlja platformu za distribuirane aplikacije.

Ovu distribuiranu bazu podataka predstavlja mreža čvorova (u daljem tekstu — node). Svaki node sadrži listu blokova, a svaki blok određene informacije, najčešće transakcije.

Hajde da objasnimo ove koncepte obrnutim redosledom.

Transakcija

Ili— Ana je Peri dala 100 dinara. Transakcije su deo većine Blockchain projekata, iako postoje i drugi koji beleže npr. potpisane dokumente ili neki kod. Ovaj projekat će jednostavno da beleži običan tekst.

Blok

Blok je objekat koji node-ovi dele međusobno. On sadrži index koji mu određuje mesto na listi blokova, hash prethodnog bloka kako bi se znalo koji je prethodni blok, timestamp da bi se znalo kad je napravljen blok, podatke koje čuvamo, i hash od prethodno navedenih podataka kako bismo kriptografski garantovali da su podaci ispravni.

class Block {
 constructor(index, previousHash, timestamp, data, hash) {
  this.index = index;
  this.previousHash = previousHash.toString();
  this.timestamp = timestamp;
  this.data = data;
  this.hash = hash.toString();
 }
}

Svaki blockchain ima početni blok na koji se dalje nastavljaju svi novi blokovi. On često dobija ime Genesis Block. Za razliku od ostalih blokova, ovaj je definisan u kodu i uvek je poznat. Jedina funkcija ovog bloka je da svaki sledeći ima validno polje previousHash.

var getGenesisBlock = () => {
 return new Block(0, "0", 1465154705, "my genesis block!!", "816534932c2b7154836da6afc367695e6337db8a921823784c14378abed4f7d7");
};

Sad možemo da definišemo lanac blokova.

var blockchain = [getGenesisBlock()];

A potrebno je da imamo i neki način da napravimo novi blok.

var generateNextBlock = (blockData) => {
 var previousBlock = getLatestBlock();
 var nextIndex = previousBlock.index + 1;
 var nextTimestamp = new Date().getTime() / 1000;
 var nextHash = calculateHash(nextIndex, previousBlock.hash, nextTimestamp, blockData);
 return new Block(nextIndex, previousBlock.hash, nextTimestamp, blockData, nextHash);
};

Kao i način da ukoliko neko podeli već napravljen blok, proverimo da li je važeći.

var addBlock = (newBlock) => {

 if (isValidNewBlock(newBlock, getLatestBlock())) {

  blockchain.push(newBlock);

 }

};

var isValidNewBlock = (newBlock, previousBlock) => {

 if (previousBlock.index + 1 !== newBlock.index) {

  console.log('invalid index');

  return false;

 } else if (previousBlock.hash !== newBlock.previousHash) {

  console.log('invalid previoushash');

  return false;

 } else if (calculateHashForBlock(newBlock) !== newBlock.hash) {

  console.log(typeof (newBlock.hash) + ' ' + typeof calculateHashForBlock(newBlock));

  console.log('invalid hash: ' + calculateHashForBlock(newBlock) + ' ' + newBlock.hash);

  return false;

 }

 return true;

};

Postoji nekoliko pomoćnih funkcija koje možete da pogledate na gitu. Na primer, calculateHashForBlock.

Node

Node predstavlja jedinicu na Blockchainu. To je softver zadužen za povezivanje sa ostalim učesnicima (node-ovima) na mreži, preuzimanje podataka koje je potrebno sačuvati, i, naravno, čuvanje pomenutih podataka.

Ako smo već definisali blokove, ostalo je da napravimo način na koji će node-ovi međusobno da dele informacije i način za upisivanje novih blokova.

Za rešavanje ovog zadatka pomaže nam Http server koji će biti zadužen za interakciju sa korisnikom. Korisnik će da dodaje nove blokove, ima pregled blokova koji su trenutno na Blockchainu, kao i mogućnost međusobnog povezivanja node-ova.

Node-ovi u velikim Blockchain projektima sami umeju da nađu druge node-ove. (Ostavljam tu funkcionalnost radoznalima da istraže jer prevazilazi kapacitete jednog teksta.)

Da bismo povukli trenutni lanac blokova prvo treba da napravimo rutu sa koje je to moguće učiniti.

app.get('/blocks', (req, res) => res.send(JSON.stringify(blockchain)));

Zatim, treba da imamo rutu kojom dodajemo novi blok. Za to treba da prosledimo serveru podatke koje želimo da vidimo u bloku i server će da izgeneriše novi blok i da ga podeli sa svim node-ovima koji su u mreži.

app.post('/mineBlock', (req, res) => {

 var newBlock = generateNextBlock(req.body.data);

 addBlock(newBlock);

 broadcast(responseLatestMsg());

 console.log('block added: ' + JSON.stringify(newBlock));

 res.send();

});

Za sledeće dve rute je potrebno znanje WebSocketa. Prva je zadužena za preuzimanje liste svih node-ova sa kojima je povezan node kom pristupamo, dok druga omogućava da dodamo nove node-ove na mrežu node-ova.

app.get('/peers', (req, res) => {

 res.send(sockets.map(s => s._socket.remoteAddress + ':' + s._socket.remotePort));

});

 

app.post('/addPeer', (req, res) => {

 connectToPeers([req.body.peer]);

 res.send();

});

Posle ovoga, ostalo nam je da omogućimo razgovor između node-ova. Nakon inicijalizacije i povezivanja node-ova, važno je da kad jednom primimo poruku preko WebSocket-a ta poruka može da bude zahtev za listu blokova ili poslednji blok, ali i da može da bude i odgovor u obliku liste blokova.

ws.on('message', (data) => {
 var message = JSON.parse(data);
 console.log('Received message' + JSON.stringify(message));
 switch (message.type) {
  case MessageType.QUERY_LATEST:
   write(ws, responseLatestMsg());
   break;
  case MessageType.QUERY_ALL:
   write(ws, responseChainMsg());
   break;
  case MessageType.RESPONSE_BLOCKCHAIN:
   handleBlockchainResponse(message);
   break;
 }
});

Najvažniji deo je primanje liste blokova. Kada node dobije listu blokova, prvo se proveri da li poslednji dobijeni blok dolazi nakon poslednjeg lokalnog bloka. Nakon toga postoji nekoliko mogućnosti. Ili se dobijeni blok samo dodaje na listu lokalnih blokova (ako se poklapa hash). Ili je potrebno zameniti lokalnu listu blokova. Ukoliko je primljena cela lista blokova, onda samo zamenimo njome lokalnu listu. U suprotnom, node pravi novi zahtev — zahtev za sve blokove.

var handleBlockchainResponse = (message) => {
 var receivedBlocks = JSON.parse(message.data).sort((b1, b2) => (b1.index - b2.index));
 var latestBlockReceived = receivedBlocks[receivedBlocks.length - 1];
 var latestBlockHeld = getLatestBlock();
 if (latestBlockReceived.index > latestBlockHeld.index) {
  console.log('blockchain possibly behind. We got: ' + latestBlockHeld.index + ' Peer got: ' + latestBlockReceived.index);
  if (latestBlockHeld.hash === latestBlockReceived.previousHash) {
   console.log("We can append the received block to our chain");
   blockchain.push(latestBlockReceived);
   broadcast(responseLatestMsg());
  } else if (receivedBlocks.length === 1) {
   console.log("We have to query the chain from our peer");
   broadcast(queryAllMsg());
  } else {
   console.log("Received blockchain is longer than current blockchain");
   replaceChain(receivedBlocks);
  }
 } else {
  console.log('received blockchain is not longer than current blockchain. Do nothing');
 }
};

To je to za početak

Ovim smo prošli kroz osnovne funkcije blockchaina i osnovni kod potreban za jedan ovakav projekat. Nadam se da ste dobili ideju za neku interesantnu primenu blockchaina. A i ukoliko niste, ova tehnologija je još uvek nova i proći će još nekoliko godina pre nego što zaživi. Ipak, ako vas interesuje da naučite više o njoj ovo je verovatno pravi trenutak da krenete u tu avanturu.


O autoru: Čedomir Rackov je deo razvojnog tima Round Globe Technologies, koji se bavi razvojem sistema baziranih na blockchain tehnologiji. Čedomira možete zapratiti na Instagramu, @thecarce, gde često objavljuje informacije koje mogu da pomognu drugim programerima. Ako imate neka pitanja ili predloge, možete mu pisati na cedomir.rackov@roundglobe.tech ili na već pomenuti Instagram.

Pridruži se → prvo predstavljanje rada Tesla Nationa