Već četiri mjeseca radim na projektu pod nazivom „Razvoj alata za zaštitu podataka i upravljanje u državnim i industrijskim sektorima na bazi blockchaina“.
Sada bih vam želio reći kako sam započeo ovaj projekat, a sada ću detaljno opisati programski kod.
Ovo je prvi članak u nizu članaka. Ovdje opisujem server i protokol. Zapravo, čitatelj može čak i napisati vlastite verzije ovih blokchain elemenata.
Prošle godine su na hackathonu Digital Breakthrough došli na ideju da naprave koristan sistem za industriju i digitalnu ekonomiju koristeći tehnologiju distribuirane knjige, a za razvoj je izdat i grant od strane Fonda za pomoć inovacijama (trebao bih napisati posebnu članak o grantu, za one koji tek pokreću startape), a sada redom.
Razvoj se odvija u jeziku Go, a baza podataka u kojoj su pohranjeni blokovi je LevelDB.
Glavni dijelovi su protokol, server (koji pokreće TCP i WebSocket - prvi za sinkronizaciju blockchaina, drugi za povezivanje klijenata, slanje transakcija i naredbi iz JavaScripta, na primjer.
Kao što je spomenuto, ovaj blockchain je prvenstveno potreban za automatizaciju i zaštitu razmjene proizvoda između dobavljača i kupaca, ili oboje u jednoj osobi. Ovi ljudi ne žure da veruju jedni drugima. Ali zadatak nije samo kreiranje „čekovne knjižice“ sa ugrađenim kalkulatorom, već i sistem koji automatizuje većinu rutinskih zadataka koji se javljaju pri radu sa životnim ciklusom proizvoda. Bajtkod koji je odgovoran za ovo pitanje, kao što je uobičajeno kod blockchaina, pohranjuje se na ulazima i izlazima transakcija (sama transakcije su pohranjene u blokovima, blokovi u LevelDB-u su unaprijed kodirani u GOB formatu). Prvo, hajde da pričamo o protokolu i serveru (aka čvor).
Protokol nije komplikovan, cijela mu je poenta da se prebaci na način učitavanja nekih podataka, obično bloka ili transakcije, kao odgovor na posebnu komandnu liniju, a potreban je i za razmjenu inventara, kako bi čvor znao ko je je povezan i na koji način imaju posla (čvorovi povezani za sesiju sinhronizacije se također nazivaju „susjednim“ jer je njihova IP adresa poznata i podaci o njihovom stanju su pohranjeni u memoriji).
Fascikle (direktorijumi kako ih Linux naziva) u razumijevanju Go programera nazivaju se paketi, tako da na početku svake datoteke sa Go kodom iz ovog direktorija pišu naziv foldera_gdje se_ova_datoteka nalazi. U suprotnom, nećete moći predati paket kompajleru. Pa, to nije tajna za one koji znaju ovaj jezik. Ovo su paketi:
- Mrežna komunikacija (server, klijent, protokol)
- Strukture pohranjenih i prenesenih podataka (blok, transakcija)
- Baza podataka (blockchain)
- Konsenzus
- Naslagana virtuelna mašina (xvm)
- Pomoćni (kripto, tipovi) to je sve za sada.
Ovo je obrazovna verzija, nedostaje joj međuprocesna interakcija i nekoliko eksperimentalnih komponenti, ali struktura odgovara onoj na kojoj se odvija razvoj. Ako imate nešto da predložite u komentarima, rado ću to uzeti u obzir u daljem razvoju. A sada za objašnjenje servera i protokol.
Pogledajmo prvo server.
Podrutina servera djeluje kao poslužitelj podataka koji radi na vrhu TCP protokola koristeći strukture podataka iz paketa protokola.
Rutina koristi sljedeće pakete: server, protokol, vrste. U samom paketu tcp_server.go sadrži strukturu podataka Serve.
type Serve struct {
Port string
BufSize int
ST *types.Settings
}
Može prihvatiti sljedeće parametre:
- Mrežni port preko kojeg će se podaci razmjenjivati
- Konfiguracijski fajl servera u JSON formatu
- Oznaka za rad u načinu za otklanjanje grešaka (privatni blockchain)
napredak:
- Čita konfiguraciju iz JSON datoteke
- Oznaka načina otklanjanja grešaka je označena: ako je postavljena, planer mrežne sinkronizacije se ne pokreće i blockchain se ne učitava
- Inicijalizacija strukture podataka konfiguracije i pokretanje servera
server
- Vrši pokretanje TCP servera i mrežnu interakciju u skladu sa protokolom.
- Ima strukturu podataka Serve koja se sastoji od broja porta, veličine bafera i pokazivača na strukturu vrste.Postavke
- Metoda Run pokreće mrežnu interakciju (osluškujući dolazne veze na datom portu, kada se primi nova veza, njena obrada se prenosi na metodu privatnog rukovanja u novoj niti)
- В rukovati podaci iz veze se čitaju u bafer, pretvaraju u nizove i prosljeđuju u protokol.Izbor
- protokol.Izbor vraća rezultat ili uzrokuje grešku. rezultat zatim prebačen u protokol. Interpretekoji se vraća intrpr - objekt tipa InterpreteData, ili uzrokuje grešku u obradi rezultata odabira
- Zatim se izvršava prebacivanje intrpr.Commands[0] koji provjerava jedno od: rezultat, inv, greška i postoji dio default
- U sekciji rezultat prekidač se nalazi po vrijednosti intrpr.Commands[1] koji provjerava vrijednosti baferlength и verzija (u svakom slučaju se poziva odgovarajuća funkcija)
Funkcije GetVersion и BufferLength nalaze se u fajlu srvlib.go serverski paket
GetVersion(conn net.Conn, version string)
jednostavno se ispisuje na konzolu i klijentu šalje verziju proslijeđenu u parametru:
conn.Write([]byte("result:" + version))
.
funkcija
BufferLength(conn net.Conn, intrpr *protocol.InterpreteData)
učitava blok, transakciju ili druge specifične podatke na sljedeći način:
- Ispisuje na konzolu tip podataka naveden u protokolu koji treba prihvatiti:
fmt.Println("DataType:", intrpr.Commands[2])
- Čita vrijednost intrpr.Body na numeričku varijablu buf_len
- Kreira bafer newbuf navedena veličina:
make([]byte, buf_len)
- Šalje u redu odgovor:
conn.Write([]byte("result:ok"))
- Potpuno popunjava bafer iz toka čitanja:
io.ReadFull(conn, newbuf)
.
- Ispisuje sadržaj bafera na konzolu
fmt.Println(string(newbuf))
i broj pročitanih bajtova
fmt.Println("Bytes length:", n)
- Šalje u redu odgovor:
conn.Write([]byte("result:ok"))
Metode iz serverskog paketa su konfigurirane za obradu primljenih podataka korištenjem funkcija iz paketa protokol.
protokol
Protokol služi kao sredstvo koje predstavlja podatke u mrežnoj razmjeni.
Izbor (str niz) (niz, greška) obavlja primarnu obradu podataka primljenih od servera, prima string reprezentaciju podataka kao ulaz i vraća string pripremljen za Tumač:
- Ulazni niz se dijeli na glavu i tijelo pomoću ReqParseN2(str)
- glava je podijeljena na elemente i smještena u komad komandi pomoću ReqParseHead(head)
- В prekidač (naredbe[0]) izaberite primljenu komandu (cmd, ključ, adresa ili se sekcija aktivira default)
- 2 komande su provjerene u cmd switch(commands[1]) — dužina и getversion.
- dužina provjerava tip podataka naredbe[2] i sprema ga tip podataka
- Provjerava to tijelo sadrži vrijednost niza
len(body) < 1
- Vraća niz odgovora:
"result:bufferlength:" + datatype + "/" + body
- getversion vraća string
return "result:version/auto"
Tumač
Sadrži strukturu InterpreteData i obavlja sekundarnu obradu podataka vraćenih iz izbor nizovi i formiranje objekata InterpreteData.
type InterpreteData struct {
Head string
Commands []string
Body string
IsErr bool
ErrCode int
ErrMessage string
}
funkcija
Interprete(str string) (*InterpreteData, error)
prihvata niz rezultat i kreira i vraća referencu na objekt InterpreteData.
napredak:
- Slično tome izbor glava i tijelo se izvlače pomoću ReqParseN2(str)
- glava se dijeli na elemente pomoću ReqParseHead(glava)
- Objekt je inicijaliziran InterpreteData i pokazivač na njega se vraća:
res := &InterpreteData{
Head: head,
Commands: commands,
Body: body,
}
return res, nil
Ovaj objekat se koristi u server.go paket glavni.
Klijent
Klijentski paket sadrži funkcije TCPConnect и TCPResponseData.
funkcija
TCPConnect(s *types.Settings, data []byte, payload []byte)
djeluje na sljedeći način:
- Uspostavlja se veza sa vezom navedenom u prenesenom objektu postavki
net.Dial("tcp", s.Host + ":" + s.Port)
- Podaci proslijeđeni u parametru podataka se prenose:
conn.Write(data)
- Odgovor je pročitan
resp, n, _ := TCPResponseData(conn, s.BufSize)
i odštampan na konzoli
fmt.Println(string(resp[:n]))
- Ako se prenese nosivost onda ga prenosi dalje
conn.Write(payload)
i takođe čita odgovor servera, štampajući ga na konzoli
funkcija
TCPResponseData(conn net.Conn, bufsiz int) ([]byte, int, error)
kreira bafer određene veličine, tamo čita odgovor servera i vraća ovaj bafer i broj pročitanih bajtova, kao i objekat greške.
Podprogram klijenta
Služi za slanje komandi serverima čvorova, kao i za dobijanje kratke statistike i testiranja.
Može prihvatiti sljedeće parametre: konfiguracionu datoteku u JSON formatu, podatke koji se šalju na server kao string, putanju do datoteke koja se šalje u korisni teret, zastavicu emulacije planera čvora, tip podataka koji se prenosi kao numerička vrijednost.
- Dobivanje konfiguracije
st := types.ParseConfig(*config)
- Ako je emu zastava proslijeđena, počinje sheduler
- Ako je data oznaka f koja označava putanju do datoteke, tada učitavamo njene podatke fdb a sadržaj se šalje na server
client.TCPConnect(st, []byte(CMD_BUFFER_LENGTH + ":" + strconv.Itoa(*t) + "/" + strconv.Itoa(fdblen)), fdb)
- Ako datoteka nije navedena, tada se podaci iz zastavice jednostavno šalju -d:
client.TCPConnect(st, []byte(*data), nil)
Sve ovo je pojednostavljena reprezentacija koja pokazuje strukturu protokola. Tokom razvoja, njegovoj strukturi se dodaje potrebna funkcionalnost.
U drugom dijelu ću govoriti o strukturama podataka za blokove i transakcije, u 3. o WebSocket serveru za povezivanje sa JavaScript-a, u 4. ću pogledati planer sinhronizacije, zatim stack mašinu koja obrađuje bajt kod sa ulaza i izlaza, kriptografiju i bazeni za izlaze.
izvor: www.habr.com