Disvolviĝo de blokĉeno por industrio uzante Go. Parto 1

Jam de kvar monatoj mi laboras pri projekto nomata "Evoluo de datumprotektado kaj administradaj iloj en registaraj kaj industriaj sektoroj bazitaj sur blokĉeno."
Nun mi ŝatus rakonti al vi pri kiel mi komencis ĉi tiun projekton, kaj nun mi detale priskribos la programkodon.

Disvolviĝo de blokĉeno por industrio uzante Go. Parto 1

Ĉi tiu estas la unua artikolo en serio de artikoloj. Ĉi tie mi priskribas la servilon kaj protokolon. Fakte, la leganto eĉ povas skribi siajn proprajn versiojn de ĉi tiuj blokĉenaj elementoj.

Kaj jen la dua parto — pri blokĉeno kaj transakciaj datumstrukturoj, same kiel pri la pakaĵo, kiu efektivigas interagadon kun la datumbazo.

Pasintjare, ĉe la Digital Breakthrough hackathon, ili elpensis ideon fari utilan sistemon por industrio kaj la cifereca ekonomio uzante distribuitan ĉeflibroteknologion; subvencio ankaŭ estis eldonita por la disvolviĝo de la Innovation Assistance Foundation (mi devus skribi apartan artikolo pri la subvencio, por tiuj, kiuj ĵus komencas fari noventreprenojn ), kaj nun en ordo.

Evoluo okazas en la Go-lingvo, kaj la datumbazo en kiu la blokoj estas stokitaj estas LevelDB.
La ĉefaj partoj estas la protokolo, la servilo (kiu kuras TCP kaj WebSocket - la unua por sinkronigi la blokĉenon, la dua por konekti klientojn, sendi transakciojn kaj komandojn de JavaScript, ekzemple.

Kiel menciite, ĉi tiu blokĉeno bezonas ĉefe por aŭtomatigi kaj protekti la interŝanĝon de produktoj inter provizantoj kaj klientoj, aŭ ambaŭ en unu persono. Ĉi tiuj homoj ne rapidas fidi unu la alian. Sed la tasko estas ne nur krei "ĉeklibron" kun enkonstruita kalkulilo, sed sistemon, kiu aŭtomatigas la plej multajn el la rutinaj taskoj, kiuj aperas kiam oni laboras kun la produkta vivociklo. La bajtkodo, kiu respondecas pri ĉi tiu afero, kiel kutimas ĉe blokĉenoj, estas konservita en la enigoj kaj eliroj de transakcioj (la transakcioj mem estas stokitaj en blokoj, la blokoj en LevelDB estas antaŭkodigitaj en la formato GOB). Unue, ni parolu pri la protokolo kaj la servilo (alinome nodo).

La protokolo ne estas komplika, ĝia tuta celo estas ŝanĝi al la reĝimo de ŝarĝo de iuj datumoj, kutime bloko aŭ transakcio, responde al speciala komandlinio, kaj ĝi ankaŭ bezonas por interŝanĝi inventaron, por ke la nodo sciu kiu ĝi estas. estas konektitaj al kaj kiel ili havas komercon por fari (la nodoj ligitaj por la sinkroniga sesio ankaŭ estas nomitaj "najbaraj" ĉar ilia IP estas konata kaj iliaj ŝtatdatenoj estas konservitaj en memoro).

Dosierujoj (dosierujoj kiel Linukso nomas ilin) ​​en la kompreno de Go-programistoj estas nomitaj pakaĵoj, do komence de ĉiu dosiero kun Go-kodo de ĉi tiu dosierujo ili skribas pakaĵon folder_name_where_this_file troviĝas. Alie, vi ne povos provizi la pakaĵon al la kompililo. Nu, ĉi tio ne estas sekreto por tiuj, kiuj konas ĉi tiun lingvon. Ĉi tiuj estas la pakoj:

  • Reta komunikado (servilo, kliento, protokolo)
  • Strukturoj de stokitaj kaj elsenditaj datumoj (bloko, transakcio)
  • Datumbazo (blokĉeno)
  • Interkonsento
  • Staplita virtuala maŝino (xvm)
  • Helpa (kripto, tipoj) jen ĉio por nun.

Jen la ligilo al github

Ĉi tio estas eduka versio, mankas al ĝi interproceza interagado kaj pluraj eksperimentaj komponantoj, sed la strukturo respondas al tiu, sur kiu disvolviĝas. Se vi havas ion por sugesti en la komentoj, mi volonte konsideros ĝin en plua evoluo. Kaj nun por klarigo pri la servilo kaj Protokolo.

Ni unue rigardu servilon.

La servila subrutino funkcias kiel datumservilo kiu funkcias aldone al la TCP-protokolo uzante datumstrukturojn de la protokolpakaĵo.

La rutino uzas la jenajn pakaĵojn: servilo, Protokolo, tipoj. En la pakaĵo mem tcp_server.go enhavas datumstrukturon Servu.

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

Ĝi povas akcepti la sekvajn parametrojn:

  • Reta haveno tra kiu datumoj estos interŝanĝitaj
  • Servila agorda dosiero en JSON-formato
  • Flago por funkciado en sencimiga reĝimo (privata blokĉeno)

Progreso:

  • Legas agordon el JSON-dosiero
  • La sencimiga reĝimo flago estas kontrolita: se ĝi estas agordita, la reto-sinkroniga planilo ne estas lanĉita kaj la blokĉeno ne estas ŝarĝita.
  • Komencante la agordan datuman strukturon kaj lanĉante la servilon

Servilo

  • Realigas la lanĉon de la TCP-servilo kaj retan interago laŭ la protokolo.
  • Ĝi havas Serve-datumstrukturon konsistantan el havenombro, bufrograndeco kaj montrilo al la strukturo tipoj.Agordoj
  • La Run-metodo komencas retan interagadon (aŭskultante envenantajn konektojn sur antaŭfiksita haveno, kiam nova konekto estas ricevita, ĝia prilaborado estas transdonita al la privata tenilo-metodo en nova fadeno)
  • В pritrakti datumoj de la konekto estas legitaj en bufron, konvertitaj al ĉenreprezentantaro kaj pasitaj al protokolo.Elekto
  • protokolo.Elekto revenas rezulto aŭ kaŭzas eraron. rezulto tiam translokite al protokolo.Interpretikiu revenas intrpr - objekto de tipo InterpreteData, aŭ kaŭzas eraron en la prilaborado de la elektorezulto
  • Tiam la ŝaltilo estas ekzekutita intrpr.Komandoj[0] kiu kontrolas unu el: result, inv, eraro kaj estas sekcio defaŭlte
  • En la sekcio rezulto ŝaltilo troviĝas laŭ valoro intrpr.Komandoj[1] kiu kontrolas la valorojn bufrolongo и versio (en ĉiu kazo la responda funkcio estas nomita)

Funkcioj GetVersion и BufferLength estas en la dosiero srvlib.go servila pako

GetVersion(conn net.Conn, version string)

ĝi simple presas al la konzolo kaj sendas la version transdonitan en la parametro al la kliento:

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

.
funkcio

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

ŝarĝas blokon, transakcion aŭ aliajn specifajn datumojn jene:

  • Presas al la konzolo la tipon de datumoj specifitaj en la protokolo, kiu devas esti akceptita:
    fmt.Println("DataType:", intrpr.Commands[2])
  • Legas la valoron intrpr.Korpo al nombra variablo buf_len
  • Kreas bufron newbuf specifita grandeco:
    make([]byte, buf_len)
  • Sendas bonan respondon:
    conn.Write([]byte("result:ok"))
  • Tute plenigas la bufron de la legita fluo:
    io.ReadFull(conn, newbuf)

    .

  • Presas la enhavon de la bufro al la konzolo
    fmt.Println(string(newbuf))

    kaj la nombro da bajtoj legitaj

    fmt.Println("Bytes length:", n)
  • Sendas bonan respondon:
    conn.Write([]byte("result:ok"))

Metodoj de la servilpakaĵo estas agorditaj por prilabori ricevitajn datumojn uzante funkciojn de la pakaĵo Protokolo.

protokolon

Protokolo funkcias kiel rimedo, kiu reprezentas datumojn en reto-interŝanĝo.

Elekto(str-ĉeno) (ĉeno, eraro) elfaras primaran traktadon de datumoj ricevitaj de la servilo, ricevas ĉenprezentadon de la datenoj kiel enigaĵon kaj resendas ĉenon preparitan por Interpretisto:

  • La eniga ŝnuro estas dividita en kapo kaj korpo uzante ReqParseN2(str)
  • kapo estas dividita en elementojn kaj metita en komandtranĉon uzante ReqParseHead (kapo)
  • В ŝanĝi (komandoj[0]) elektu la ricevitan komandon (cmd, ŝlosilo, adreso aŭ la sekcio estas ekigita defaŭlte)
  • 2 komandoj estas kontrolitaj en cmd switch(komandoj[1]) — longeco и getversion.
  • longo kontrolas la datumtipo enen ordonoj [2] kaj konservas ĝin enen datumtipo
  • Kontrolas tion korpo enhavas ĉenvaloron
    len(body) < 1
  • Liveras la respondŝnuron:
    "result:bufferlength:" + datatype + "/" + body
  • getversion resendas ĉenon
    return "result:version/auto"

Interpretisto

Enhavas la InterpreteData strukturon kaj elfaras sekundaran prilaboradon de la datumoj resenditaj de elekto kordoj kaj objektoformado InterpreteData.

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

funkcio

Interprete(str string) (*InterpreteData, error)

akceptas ŝnuron rezulto kaj kreas kaj resendas referencon al la objekto InterpreteData.

Progreso:

  • Simile elekto kapo kaj korpo estas ĉerpitaj uzante ReqParseN2(str)
  • kapo estas dividita en elementoj uzante ReqParseHead(kapo)
  • La objekto estas pravigita InterpreteData kaj montrilo al ĝi estas resendita:

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

Ĉi tiu objekto estas uzata en servilo.iru pako ĉefa.

Kliento

La klientpakaĵo enhavas la funkciojn TCPConnect и TCPResponseData.

funkcio

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

funkcias tiel:

  • Konekto estas farita al la konekto specifita en la pasita agorda objekto
    net.Dial("tcp", s.Host + ":" + s.Port)
  • La datumoj pasigitaj en la datenparametro estas transdonitaj:
    conn.Write(data)
  • La respondo estas legita
    resp, n, _ := TCPResponseData(conn, s.BufSize)

    kaj presita sur la konzolo

    fmt.Println(string(resp[:n]))
  • Se transdonite utila ŝarĝo poste transdonas ĝin
    conn.Write(payload)

    kaj ankaŭ legas la servilan respondon, presante ĝin al la konzolo

funkcio

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

kreas bufron de la specifita grandeco, legas la servilan respondon tie kaj resendas ĉi tiun bufron kaj la nombron da legitaj bajtoj, same kiel erarobjekton.

Klienta subrutino

Servas sendi komandojn al nodaj serviloj, kaj ankaŭ akiri mallongajn statistikojn kaj testadojn.

Povas akcepti la sekvajn parametrojn: agorda dosiero en JSON-formato, datumoj sendotaj al la servilo kiel ŝnuro, vojo al la dosiero sendota al utila ŝarĝo, nodo-planisto emulado flago, tipo de datumoj transdonitaj kiel nombra valoro.

  • Akiro de la agordo
    st := types.ParseConfig(*config)
  • Se la emuflago estas preterpasita, ĝi komenciĝas sheduler
  • Se la f-flago indikanta la vojon al la dosiero estas provizita, tiam ni ŝarĝas ĝiajn datumojn en fdb kaj la enhavo estas sendita al la servilo
    client.TCPConnect(st, []byte(CMD_BUFFER_LENGTH + ":" + strconv.Itoa(*t) + "/" + strconv.Itoa(fdblen)), fdb)
  • Se la dosiero ne estas specifita, tiam la datumoj de la flago estas simple senditaj -d:
    client.TCPConnect(st, []byte(*data), nil)

Ĉio ĉi estas simpligita reprezentado montranta la strukturon de la protokolo. Dum evoluo, la necesa funkcieco estas aldonita al ĝia strukturo.

En la dua parto mi parolos pri datumstrukturoj por blokoj kaj transakcioj, en 3 pri la WebSocket-servilo por konekti de JavaScript, en 4 mi rigardos la sinkronigan planilon, poste stakan maŝinon, kiu prilaboras bajtokodon el enigaĵoj kaj eliroj, kriptografio kaj naĝejoj por eliroj.

fonto: www.habr.com

Aldoni komenton