Go erabiliz industriarako blockchain garapena. 1. zatia

Lau hilabete daramatzat “Blokekatean oinarritutako datuak babesteko eta kudeatzeko tresnen garapena gobernu eta industria sektoreetan” izeneko proiektuan lanean nabil.
Orain proiektu hau nola hasi nuen kontatu nahiko nuke, eta orain programaren kodea zehatz-mehatz deskribatuko dut.

Go erabiliz industriarako blockchain garapena. 1. zatia

Artikulu sorta bateko lehen artikulua da. Hemen zerbitzaria eta protokoloa deskribatzen ditut. Izan ere, irakurleak bloke-katearen elementu horien bertsio propioak ere idatzi ditzake.

Eta hona hemen bigarren zatia — blockchain eta transakzio datuen egiturei buruz, baita datu-basearekin interakzioa ezartzen duen paketeari buruz ere.

Iaz, Digital Breakthrough hackatoian, industriarako eta ekonomia digitalerako sistema baliagarri bat egiteko ideia bat bururatu zitzaien erregistro banatuaren teknologia erabiliz; Berrikuntzarako Laguntza Funtsak garatzeko beka bat ere eman zuen (bereiz idatzi beharko nuke. bekari buruzko artikulua, startup-ak hasi berriak direnentzat ), eta orain ordenan.

Garapena Go hizkuntzan egiten da, eta blokeak gordetzen diren datu-basea LevelDB da.
Zati nagusiak protokoloa, zerbitzaria (TCP eta WebSocket exekutatzen dituena - lehenengoa blockchain-a sinkronizatzeko, bigarrena bezeroak konektatzeko, transakzioak eta JavaScript-etik komandoak bidaltzeko, adibidez).

Esan bezala, bloke-kate hau hornitzaileen eta bezeroen arteko produktuen trukea automatizatzeko eta babesteko behar da, edo biak pertsona bakarrean. Pertsona hauek ez dute elkarrengan konfiantza izateko presarik. Baina zeregina ez da soilik kalkulagailu integratua duen "txeke-koadernoa" sortzea, produktuaren bizi-zikloarekin lan egitean sortzen diren ohiko zeregin gehienak automatizatzen dituen sistema bat baizik. Gai honen arduraduna den bytecodea, blockchainekin ohikoa den bezala, transakzioen sarrera eta irteeretan gordetzen da (transakzioak berak blokeetan gordetzen dira, LevelDB-ko blokeak GOB formatuan aurrez kodetuta daude). Lehenik eta behin, hitz egin dezagun protokoloaz eta zerbitzariaz (aka nodoaz).

Protokoloa ez da konplikatua, bere helburua datu batzuk kargatzeko modura aldatzea da, normalean bloke edo transakzio bat, komando-lerro berezi bati erantzunez, eta inbentarioa trukatzeko ere beharrezkoa da, nodoak nor den jakin dezan. konektatuta dagoen eta nola egin behar duten negozioa (sinkronizazio-saiorako konektatutako nodoei "inguruko" deitzen zaie, IP ezagutzen dutelako eta haien egoeraren datuak memorian gordetzen direlako).

Karpetei (Linuxek deitzen dien bezala direktorioei) Go programatzaileen ulermenean paketeak deitzen dira, beraz, direktorio honetako Go kodea duen fitxategi bakoitzaren hasieran paketea idazten dute karpeta_izena_non_fitxategi hau kokatzen den. Bestela, ezingo duzu paketea elikatu konpilatzaileari. Bada, hau ez da sekretua hizkuntza hau dakitenentzat. Hauek dira paketeak:

  • Sareko komunikazioa (zerbitzaria, bezeroa, protokoloa)
  • Biltegiratutako eta transmititutako datuen egiturak (blokea, transakzioa)
  • Datu-basea (blockchain)
  • Adostasuna
  • Pilatutako makina birtuala (xvm)
  • Laguntzaile (kripto, motak) hori da oraingoz.

Hona hemen github-erako esteka

Bertsio hezitzailea da, prozesuen arteko elkarrekintza eta hainbat osagai esperimental falta ditu, baina egitura garapena egiten ari denarekin bat dator. Iruzkinetan zerbait iradokitzeko baduzu, pozik hartuko dut kontuan garapenean. Eta orain zerbitzariaren azalpena eta protokoloa.

Ikus dezagun zerbitzaria lehenik.

Zerbitzariaren azpierrutinak TCP protokoloaren gainean exekutatzen den datu-zerbitzari gisa jokatzen du, protokolo paketearen datu-egiturak erabiliz.

Errutinak pakete hauek erabiltzen ditu: zerbitzaria, protokoloa, motak. Paketean bertan tcp_server.go datuen egitura dauka zerbitzatzeko.

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

Parametro hauek onar ditzake:

  • Datuak trukatuko diren sareko ataka
  • Zerbitzariaren konfigurazio fitxategia JSON formatuan
  • Markatu arazketa moduan exekutatzeko (bloke-kate pribatua)

Aurrerapena:

  • JSON fitxategitik konfigurazioa irakurtzen du
  • Arazketa moduaren bandera egiaztatuta dago: ezarrita badago, sareko sinkronizazio-planifikatzailea ez da abiarazten eta bloke-katea ez da kargatzen.
  • Konfigurazio-datuen egitura hasieratzea eta zerbitzaria abiaraztea

Server

  • TCP zerbitzariaren eta sareko interakzioa abiarazten du protokoloaren arabera.
  • Portu-zenbaki batez, buffer-tamainaz eta egiturako erakusle batez osaturiko Serve datu-egitura du motak.Ezarpenak
  • Exekutatu metodoak sareko elkarrekintza abiarazten du (portu jakin batean sarrerako konexioak entzuten, konexio berri bat jasotzen denean, bere prozesamendua kudeatzaile pribatuaren metodora transferitzen da hari berri batean)
  • В kudeatzeko konexioko datuak buffer batean irakurtzen dira, katearen irudikapen bihurtzen dira eta bertara pasatzen dira protokoloa.Aukera
  • protokoloa.Aukera itzultzen ondorioz edo errore bat eragiten du. ondorioz gero transferitu protokoloa.Interpretatuitzultzen dena intrpr - motako objektua InterpretatuData, edo errore bat eragiten du hautapenaren emaitza prozesatzen
  • Ondoren, etengailua exekutatzen da intrpr.Komandoak[0] hauetako bat egiaztatzen duena: emaitza, inv, errore eta atal bat dago lehenetsi
  • atalean ondorioz etengailua balioaren arabera aurkitzen da intrpr.Komandoak[1] balioak egiaztatzen dituena bufferren luzera и bertsioa (kasu bakoitzean dagokion funtzioari deitzen zaio)

funtzio LortuBertsioa и BufferLength fitxategian daude srvlib.go zerbitzari paketea

GetVersion(conn net.Conn, version string)

kontsolara inprimatu besterik ez du eta parametroan emandako bertsioa bezeroari bidaltzen dio:

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

.
Funtzioa

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

bloke, transakzio edo beste datu zehatz batzuk kargatzen ditu honela:

  • Onartu beharreko protokoloan zehaztutako datu motak inprimatzen ditu kontsolara:
    fmt.Println("DataType:", intrpr.Commands[2])
  • Balioa irakurtzen du intrpr.Gorputza zenbakizko aldagai bati buf_len
  • Buffer bat sortzen du berribuf zehaztutako tamaina:
    make([]byte, buf_len)
  • Ongi erantzun bat bidaltzen du:
    conn.Write([]byte("result:ok"))
  • Irakurketa korrontetik bufferra guztiz betetzen du:
    io.ReadFull(conn, newbuf)

    .

  • Bufferaren edukia kontsolara inprimatzen du
    fmt.Println(string(newbuf))

    eta irakurritako byte kopurua

    fmt.Println("Bytes length:", n)
  • Ongi erantzun bat bidaltzen du:
    conn.Write([]byte("result:ok"))

Zerbitzariaren paketearen metodoak jasotako datuak prozesatzeko konfiguratuta daude paketearen funtzioak erabiliz protokoloa.

Protokoloa

Protokolo batek sare-trukean datuak adierazten dituen bitarteko gisa balio du.

Aukera (katea) (katea, errorea) zerbitzariak jasotako datuen lehen tratamendua egiten du, datuen katearen irudikapena jasotzen du sarrera gisa eta prestatutako kate bat itzultzen du. Interpretea:

  • Sarrerako katea buruan eta gorputzean zatitzen da erabiliz ReqParseN2(str)
  • burua elementuetan zatitzen da eta komandoen zati batean jartzen da ReqParseHead(head) erabiliz
  • В aldatu(aginduak[0]) hautatu jasotako komandoa (cmd, giltza, helbidea edo atala abiarazten da lehenetsi)
  • 2 komando markatuta daude cmd-n switch(aginduak[1]) — luzera и getbertsioa.
  • luzera datu-mota egiaztatzen du komandoak[2] eta bertan gordetzen du datatype
  • Hori egiaztatzen du gorputza kate-balio bat dauka
    len(body) < 1
  • Erantzun katea ematen du:
    "result:bufferlength:" + datatype + "/" + body
  • getbertsioa kate bat itzultzen du
    return "result:version/auto"

Interpretea

InterpreteData egitura dauka eta itzulitako datuen bigarren mailako prozesamendua egiten du Choice kateak eta objektuen eraketa InterpretatuData.

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

Funtzioa

Interprete(str string) (*InterpreteData, error)

kate bat onartzen du ondorioz eta objektuari erreferentzia bat sortu eta itzultzen du InterpretatuData.

Aurrerapena:

  • Era Choice burua eta gorputza ateratzen dira erabiliz ReqParseN2(str)
  • burua elementuetan banatzen da erabiliz ReqParseHead(burua)
  • Objektua hasieratzen da InterpretatuData eta horren erakusle bat itzultzen da:

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

Objektu hau erabiltzen da zerbitzari.go pakete nagusia.

Bezero

Bezero paketeak funtzioak ditu TCPConnect и TCPResponseData.

Funtzioa

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

honela funtzionatzen du:

  • Konexio bat egiten da gainditutako ezarpenen objektuan zehaztutako konexioarekin
    net.Dial("tcp", s.Host + ":" + s.Port)
  • Datu parametroan pasatzen diren datuak transmititzen dira:
    conn.Write(data)
  • Erantzuna irakurtzen da
    resp, n, _ := TCPResponseData(conn, s.BufSize)

    eta kontsolan inprimatuta

    fmt.Println(string(resp[:n]))
  • Transferitu bada karga gero pasatzen du
    conn.Write(payload)

    eta zerbitzariaren erantzuna ere irakurtzen du, kontsolara inprimatuz

Funtzioa

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

zehaztutako tamainako buffer bat sortzen du, hor zerbitzariaren erantzuna irakurtzen du eta buffer hori eta irakurritako byte kopurua itzultzen ditu, baita errore-objektu bat ere.

Bezeroaren azpierrutina

Nodo zerbitzarietara komandoak bidaltzeko balio du, baita estatistika eta proba laburrak lortzeko ere.

Parametro hauek onar ditzake: konfigurazio-fitxategia JSON formatuan, zerbitzariari kate gisa bidali beharreko datuak, kargara bidali beharreko fitxategiaren bidea, nodo-planifikatzailearen emulazio-marka, zenbakizko balio gisa transferitutako datu-mota.

  • Konfigurazioa lortzea
    st := types.ParseConfig(*config)
  • Emu bandera pasatzen bada, hasten da egitaraua
  • Fitxategiaren bidea adierazten duen f bandera ematen bada, orduan kargatuko ditugu bere datuak fdb eta edukia zerbitzarira bidaltzen da
    client.TCPConnect(st, []byte(CMD_BUFFER_LENGTH + ":" + strconv.Itoa(*t) + "/" + strconv.Itoa(fdblen)), fdb)
  • Fitxategia zehazten ez bada, banderako datuak besterik gabe bidaltzen dira -d:
    client.TCPConnect(st, []byte(*data), nil)

Hau guztia protokoloaren egitura erakusten duen irudikapen sinplifikatua da. Garapenean, beharrezko funtzionaltasuna gehitzen zaio bere egiturari.

Bigarren zatian blokeen eta transakzioen datu-egiturei buruz hitz egingo dut, 3.ean JavaScript-etik konektatzeko WebSocket zerbitzariari buruz, 4.ean sinkronizazio-planifikatzaileari begiratuko diot, gero sarrera eta irteeratik bytecode prozesatzen duen pila-makina, kriptografia eta irteerarako igerilekuak.

Iturria: www.habr.com

Gehitu iruzkin berria