Vývoj blockchainu pre priemysel pomocou Go. Časť 1

Už štyri mesiace pracujem na projekte s názvom „Vývoj nástrojov na ochranu a správu údajov vo vládnom a priemyselnom sektore založenom na blockchaine“.
Teraz by som vám rád povedal, ako som začal s týmto projektom, a teraz podrobne opíšem kód programu.

Vývoj blockchainu pre priemysel pomocou Go. Časť 1

Toto je prvý článok zo série článkov. Tu popisujem server a protokol. V skutočnosti môže čitateľ dokonca napísať svoje vlastné verzie týchto prvkov blockchainu.

A tu je druhá časť — o blockchaine a transakčných dátových štruktúrach, ako aj o balíku, ktorý implementuje interakciu s databázou.

Minulý rok na hackathone Digital Breakthrough prišli s nápadom urobiť užitočný systém pre priemysel a digitálnu ekonomiku pomocou technológie distribuovanej účtovnej knihy, na vývoj bol udelený grant aj Fondom pomoci pri inováciách (mal by som napísať samostatný článok o grante, pre tých, ktorí začínajú robiť startupy ), a teraz po poriadku.

Vývoj prebieha v jazyku Go a databáza, v ktorej sú bloky uložené, je LevelDB.
Hlavnými časťami sú protokol, server (na ktorom beží TCP a WebSocket – prvý na synchronizáciu blockchainu, druhý na pripojenie klientov, odosielanie transakcií a príkazov z JavaScriptu napr.

Ako už bolo spomenuté, tento blockchain je potrebný predovšetkým na automatizáciu a ochranu výmeny produktov medzi dodávateľmi a zákazníkmi, prípadne oboma v jednej osobe. Títo ľudia sa neponáhľajú, aby si navzájom dôverovali. Úlohou však nie je len vytvoriť „šekovú knižku“ so vstavanou kalkulačkou, ale systém, ktorý automatizuje väčšinu rutinných úloh, ktoré vznikajú pri práci so životným cyklom produktu. Bytekód, ktorý je za túto záležitosť zodpovedný, ako je pri blockchainoch zvykom, je uložený vo vstupoch a výstupoch transakcií (samotné transakcie sú uložené v blokoch, bloky v LevelDB sú predkódované vo formáte GOB). Najprv si povedzme o protokole a serveri (známy ako uzol).

Protokol nie je zložitý, jeho zmyslom je prepnutie do režimu načítania nejakých údajov, zvyčajne bloku alebo transakcie, v reakcii na špeciálny príkazový riadok a je potrebný aj na výmenu zásob, aby uzol vedel, koho má ku ktorému je pripojený a ako majú robiť (uzly pripojené na synchronizačnú reláciu sa tiež nazývajú „susedné“, pretože ich IP je známa a ich stavové údaje sú uložené v pamäti).

Priečinky (adresáre ako ich Linux nazýva) v ponímaní programátorov Go sa nazývajú balíčky, takže na začiatok každého súboru s kódom Go z tohto adresára napíšu balíček názov_priečinku_kde_tento_súbor sa nachádza. V opačnom prípade nebudete môcť odovzdať balík kompilátoru. Pre tých, ktorí poznajú tento jazyk, to nie je žiadne tajomstvo. Ide o tieto balíčky:

  • Sieťová komunikácia (server, klient, protokol)
  • Štruktúry uložených a prenášaných údajov (blok, transakcia)
  • Databáza (blockchain)
  • Konsenzus
  • Skladaný virtuálny počítač (xvm)
  • Pomocné (kryptomety, typy), to je zatiaľ všetko.

Tu je odkaz na github

Toto je vzdelávacia verzia, chýba jej medziprocesová interakcia a niekoľko experimentálnych komponentov, ale štruktúra zodpovedá tej, na ktorej prebieha vývoj. Ak máte čo navrhnúť v komentároch, rád to zohľadním pri ďalšom vývoji. A teraz vysvetlenie k serveru a protokol.

Najprv sa pozrime na server.

Podprogram servera funguje ako údajový server, ktorý beží nad protokolom TCP pomocou dátových štruktúr z balíka protokolov.

Rutina používa nasledujúce balíky: server, protokol, Typy. V samotnom balení tcp_server.go obsahuje dátovú štruktúru Slúžiť.

type Serve struct {
	Port string
	BufSize int
	ST *types.Settings
}

Môže akceptovať nasledujúce parametre:

  • Sieťový port, cez ktorý sa budú vymieňať údaje
  • Konfiguračný súbor servera vo formáte JSON
  • Príznak pre spustenie v režime ladenia (súkromný blockchain)

Pokrok:

  • Načíta konfiguráciu zo súboru JSON
  • Je skontrolovaný príznak režimu ladenia: ak je nastavený, plánovač synchronizácie siete sa nespustí a blockchain sa nenačíta
  • Inicializácia štruktúry konfiguračných údajov a spustenie servera

server

  • Vykonáva spustenie TCP servera a sieťovej interakcie v súlade s protokolom.
  • Má dátovú štruktúru Serve pozostávajúcu z čísla portu, veľkosti vyrovnávacej pamäte a ukazovateľa na štruktúru typy.Nastavenia
  • Metóda Run spúšťa sieťovú interakciu (počúvanie prichádzajúcich spojení na danom porte, pri prijatí nového spojenia sa jeho spracovanie prenesie do metódy private handle v novom vlákne)
  • В rukoväť údaje z pripojenia sú načítané do vyrovnávacej pamäte, konvertované na reťazcovú reprezentáciu a odovzdané do protokol.Výber
  • protokol.Výber sa vracia následok alebo spôsobí chybu. následok potom prenesený do protokol.Interpretovaťktorý sa vracia intrpr - objekt druhu InterpreteDataalebo spôsobí chybu pri spracovaní výsledku výberu
  • Potom sa prepínač vykoná intrpr.Commands[0] ktorý kontroluje jeden z: výsledok, inv, chyba a je tam sekcia štandardné
  • V sekcii následok prepínač sa nájde podľa hodnoty intrpr.Commands[1] ktorý kontroluje hodnoty dĺžka vyrovnávacej pamäte и verzia (v každom prípade sa volá zodpovedajúca funkcia)

Funkcia GetVersion и BufferLength sú v súbore srvlib.go serverový balík

GetVersion(conn net.Conn, version string)

jednoducho vytlačí do konzoly a odošle verziu odovzdanú v parametri klientovi:

conn.Write([]byte("result:" + version))

.
Funkcia

BufferLength(conn net.Conn, intrpr *protocol.InterpreteData)

načíta blok, transakciu alebo iné špecifické údaje takto:

  • Vytlačí do konzoly typ údajov špecifikovaný v protokole, ktorý je potrebné akceptovať:
    fmt.Println("DataType:", intrpr.Commands[2])
  • Číta hodnotu intrpr.Telo na číselnú premennú buf_len
  • Vytvára vyrovnávaciu pamäť newbuf špecifikovaná veľkosť:
    make([]byte, buf_len)
  • Odošle odpoveď v poriadku:
    conn.Write([]byte("result:ok"))
  • Úplne vyplní vyrovnávaciu pamäť z čítaného toku:
    io.ReadFull(conn, newbuf)

    .

  • Vytlačí obsah vyrovnávacej pamäte do konzoly
    fmt.Println(string(newbuf))

    a počet prečítaných bajtov

    fmt.Println("Bytes length:", n)
  • Odošle odpoveď v poriadku:
    conn.Write([]byte("result:ok"))

Metódy zo serverového balíka sú nakonfigurované na spracovanie prijatých údajov pomocou funkcií z balíka protokol.

Protokol

Protokol slúži ako prostriedok, ktorý reprezentuje dáta v sieťovej výmene.

Choice(str reťazec) (reťazec, chyba) vykoná primárne spracovanie údajov prijatých serverom, prijme reťazcovú reprezentáciu údajov ako vstup a vráti reťazec pripravený pre Tlmočník:

  • Vstupný reťazec je rozdelený na hlavu a telo pomocou ReqParseN2(str)
  • hlava je rozdelená na prvky a umiestnená do segmentu príkazov pomocou ReqParseHead(head)
  • В switch(príkazy[0]) vyberte prijatý príkaz (cmd, kľúč, adresa alebo sa sekcia spustí štandardné)
  • V cmd sa kontrolujú 2 príkazy switch(príkazy[1]) — dĺžka и getversion.
  • dĺžka skontroluje typ údajov príkazy[2] a uloží ho do Dátový typ
  • Kontroluje to telo obsahuje hodnotu reťazca
    len(body) < 1
  • Vráti reťazec odpovede:
    "result:bufferlength:" + datatype + "/" + body
  • getversion vráti reťazec
    return "result:version/auto"

Tlmočník

Obsahuje štruktúru InterpreteData a vykonáva sekundárne spracovanie údajov vrátených z voľba reťazcov a formovanie objektov InterpreteData.

type InterpreteData struct {
	Head string
	Commands []string
	Body string
	IsErr bool
	ErrCode int 
	ErrMessage string
}

Funkcia

Interprete(str string) (*InterpreteData, error)

prijíma reťazec následok a vytvorí a vráti odkaz na objekt InterpreteData.

Pokrok:

  • podobne voľba hlava a telo sa extrahujú pomocou ReqParseN2(str)
  • hlava je rozdelená na prvky pomocou ReqParseHead(head)
  • Objekt sa inicializuje InterpreteData a vráti sa naň ukazovateľ:

res := &InterpreteData{
	Head: head,
	Commands: commands,
	Body: body,
}
return res, nil

Tento objekt sa používa v server.go hlavný balík.

Zákazník

Klientsky balík obsahuje funkcie TCPConnect и TCPResponseData.

Funkcia

TCPConnect(s *types.Settings, data []byte, payload []byte)

funguje takto:

  • Vytvorí sa pripojenie k pripojeniu špecifikovanému v odovzdanom objekte nastavení
    net.Dial("tcp", s.Host + ":" + s.Port)
  • Údaje odovzdané v parametri údajov sa prenesú:
    conn.Write(data)
  • Odpoveď je prečítaná
    resp, n, _ := TCPResponseData(conn, s.BufSize)

    a vytlačené na konzole

    fmt.Println(string(resp[:n]))
  • Ak sa prenesie užitočné zaťaženie potom to odovzdá
    conn.Write(payload)

    a tiež prečíta odpoveď servera a vytlačí ju do konzoly

Funkcia

 TCPResponseData(conn net.Conn, bufsiz int) ([]byte, int, error)

vytvorí vyrovnávaciu pamäť zadanej veľkosti, načíta tam odpoveď servera a vráti túto vyrovnávaciu pamäť a počet prečítaných bajtov, ako aj chybový objekt.

Klientsky podprogram

Slúži na odosielanie príkazov na uzlové servery, ako aj na získanie krátkych štatistík a testovania.

Môže akceptovať nasledujúce parametre: konfiguračný súbor vo formáte JSON, údaje, ktoré sa majú odoslať na server ako reťazec, cesta k súboru, ktorý sa má odoslať do užitočného zaťaženia, príznak emulácie plánovača uzla, typ prenášaných údajov ako číselná hodnota.

  • Získanie konfigurácie
    st := types.ParseConfig(*config)
  • Ak prejde príznak emu, spustí sa plánovač
  • Ak je zadaný príznak f označujúci cestu k súboru, načítame jeho údaje do fdb a obsah sa odošle na server
    client.TCPConnect(st, []byte(CMD_BUFFER_LENGTH + ":" + strconv.Itoa(*t) + "/" + strconv.Itoa(fdblen)), fdb)
  • Ak súbor nie je zadaný, údaje z príznaku sa jednoducho odošlú -d:
    client.TCPConnect(st, []byte(*data), nil)

Toto všetko je zjednodušená reprezentácia zobrazujúca štruktúru protokolu. Počas vývoja sa do jeho štruktúry pridáva potrebná funkcionalita.

V druhej časti budem hovoriť o dátových štruktúrach pre bloky a transakcie, v 3 o WebSocket serveri na pripojenie z JavaScriptu, v 4 sa pozriem na plánovač synchronizácie, potom na zásobníkový stroj, ktorý spracováva bytekód zo vstupov a výstupov, kryptografiu a bazény pre výstupy.

Zdroj: hab.com

Pridať komentár