Datblygiad Blockchain ar gyfer diwydiant gan ddefnyddio Go. Rhan 1

Ers pedwar mis bellach rwyf wedi bod yn gweithio ar brosiect o'r enw “Datblygu offer diogelu data a rheoli yn y llywodraeth a sectorau diwydiannol yn seiliedig ar blockchain.”
Nawr hoffwn ddweud wrthych sut y dechreuais y prosiect hwn, a nawr byddaf yn disgrifio cod y rhaglen yn fanwl.

Datblygiad Blockchain ar gyfer diwydiant gan ddefnyddio Go. Rhan 1

Dyma'r erthygl gyntaf mewn cyfres o erthyglau. Yma rwy'n disgrifio'r gweinydd a'r protocol. Mewn gwirionedd, gall y darllenydd hyd yn oed ysgrifennu ei fersiynau ei hun o'r elfennau blockchain hyn.

A dyma yr ail ran - yn ymwneud â blockchain a strwythurau data trafodion, yn ogystal ag am y pecyn sy'n gweithredu rhyngweithio â'r gronfa ddata.

Y llynedd, yn yr hacathon Digital Breakthrough, fe wnaethon nhw feddwl am syniad i wneud system ddefnyddiol ar gyfer diwydiant a’r economi ddigidol gan ddefnyddio technoleg cyfriflyfr dosranedig; rhoddwyd grant hefyd ar gyfer datblygiad gan y Gronfa Cymorth Arloesedd (dylwn i ysgrifennu datganiad ar wahân). erthygl am y grant, ar gyfer y rhai sydd newydd ddechrau busnesau ), ac yn awr mewn trefn.

Mae datblygiad yn digwydd yn yr iaith Go, a'r gronfa ddata lle mae'r blociau'n cael eu storio yw LevelDB.
Y prif rannau yw'r protocol, y gweinydd (sy'n rhedeg TCP a WebSocket - y cyntaf ar gyfer cydamseru'r blockchain, yr ail ar gyfer cysylltu cleientiaid, anfon trafodion a gorchmynion o JavaScript, er enghraifft.

Fel y crybwyllwyd, mae angen y blockchain hwn yn bennaf i awtomeiddio a diogelu cyfnewid cynhyrchion rhwng cyflenwyr a chwsmeriaid, neu'r ddau mewn un person. Nid yw'r bobl hyn ar unrhyw frys i ymddiried yn ei gilydd. Ond y dasg yw nid yn unig creu “llyfr siec” gyda chyfrifiannell adeiledig, ond system sy'n awtomeiddio'r rhan fwyaf o'r tasgau arferol sy'n codi wrth weithio gyda chylch bywyd y cynnyrch. Mae'r bytecode sy'n gyfrifol am y mater hwn, fel sy'n arferol gyda blockchains, yn cael ei storio ym mewnbynnau ac allbynnau trafodion (mae'r trafodion eu hunain yn cael eu storio mewn blociau, mae'r blociau yn LevelDB wedi'u rhag-amgodio yn y fformat GOB). Yn gyntaf, gadewch i ni siarad am y protocol a'r gweinydd (aka nod).

Nid yw'r protocol yn gymhleth, ei holl bwynt yw newid i'r modd llwytho rhywfaint o ddata, bloc neu drafodiad fel arfer, mewn ymateb i linell orchymyn arbennig, ac mae ei angen hefyd ar gyfer cyfnewid rhestr eiddo, fel bod y nod yn gwybod pwy ydyw. wedi'i gysylltu ag ef a sut mae ganddynt fusnes i'w wneud (gelwir y nodau sy'n gysylltiedig ar gyfer y sesiwn cydamseru hefyd yn “gymdogol” oherwydd bod eu IP yn hysbys a bod data eu cyflwr yn cael ei storio yn y cof).

Gelwir ffolderi (cyfeiriaduron fel y mae Linux yn eu galw) yn nealltwriaeth rhaglenwyr Go yn becynnau, felly ar ddechrau pob ffeil gyda chod Go o'r cyfeiriadur hwn maent yn ysgrifennu pecyn folder_name_where_this_file wedi ei leoli. Fel arall, ni fyddwch yn gallu bwydo'r pecyn i'r casglwr. Wel, nid yw hyn yn gyfrinach i'r rhai sy'n adnabod yr iaith hon. Dyma'r pecynnau:

  • Cyfathrebu rhwydwaith (gweinydd, cleient, protocol)
  • Strwythurau data sy'n cael ei storio a'i drosglwyddo (bloc, trafodiad)
  • Cronfa ddata (blockchain)
  • Consensws
  • Peiriant rhithwir wedi'i bentyrru (xvm)
  • Ategol (crypto, mathau) dyna'r cyfan am y tro.

Dyma'r ddolen i github

Mae hon yn fersiwn addysgol, nid oes ganddo ryngweithio rhyng-broses a nifer o gydrannau arbrofol, ond mae'r strwythur yn cyfateb i'r un y mae datblygiad yn cael ei wneud arno. Os oes gennych unrhyw beth i’w awgrymu yn y sylwadau, byddaf yn hapus i’w gymryd i ystyriaeth wrth ddatblygu ymhellach. Ac yn awr am esboniad ar y gweinydd a protocol.

Gadewch i ni edrych ar y gweinydd yn gyntaf.

Mae is-reolwaith y gweinydd yn gweithredu fel gweinydd data sy'n rhedeg ar ben y protocol TCP gan ddefnyddio strwythurau data o'r pecyn protocol.

Mae'r drefn yn defnyddio'r pecynnau canlynol: gweinydd, protocol, mathau. Yn y pecyn ei hun tcp_server.go yn cynnwys strwythur data Gweinwch.

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

Gall dderbyn y paramedrau canlynol:

  • Porth rhwydwaith lle bydd data'n cael ei gyfnewid
  • Ffeil ffurfweddu gweinydd mewn fformat JSON
  • Baner ar gyfer rhedeg yn y modd dadfygio (blockchain preifat)

Cynnydd:

  • Yn darllen ffurfweddiad o ffeil JSON
  • Mae baner y modd dadfygio yn cael ei gwirio: os yw wedi'i gosod, nid yw'r rhaglennydd cydamseru rhwydwaith yn cael ei lansio ac nid yw'r blockchain wedi'i lwytho
  • Cychwyn y strwythur data cyfluniad a chychwyn y gweinydd

gweinydd

  • Yn lansio'r gweinydd TCP a rhyngweithio rhwydwaith yn unol â'r protocol.
  • Mae ganddo strwythur data Serve sy'n cynnwys rhif porthladd, maint byffer a phwyntydd i'r strwythur mathau.Gosodiadau
  • Mae'r dull Run yn dechrau rhyngweithio rhwydwaith (gwrando am gysylltiadau sy'n dod i mewn ar borth penodol, pan dderbynnir cysylltiad newydd, caiff ei brosesu ei drosglwyddo i'r dull handlen breifat mewn edefyn newydd)
  • В trin mae data o'r cysylltiad yn cael ei ddarllen yn glustog, ei drosi i gynrychioliad llinynnol a'i drosglwyddo i protocol.Choice
  • protocol.Choice yn dychwelyd arwain neu achosi gwall. arwain yna trosglwyddo i protocol.Dehonglisy'n dychwelyd intrapr - gwrthrych o fath DehongliData, neu'n achosi gwall wrth brosesu'r canlyniad dethol
  • Yna mae'r switsh yn cael ei weithredu intrpr.Commands[0] sy'n gwirio un o: canlyniad, inv, gwall ac y mae adran diofyn
  • Yn yr adran arwain canfyddir switsh yn ôl gwerth intrpr.Commands[1] sy'n gwirio'r gwerthoedd byffer hyd и fersiwn (ym mhob achos gelwir y swyddogaeth gyfatebol)

Swyddogaethau GetVersion и Hyd Clustog sydd yn y ffeil srvlib.go pecyn gweinydd

GetVersion(conn net.Conn, version string)

Yn syml, mae'n argraffu i'r consol ac yn anfon y fersiwn a basiwyd yn y paramedr at y cleient:

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

.
Swyddogaeth

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

yn llwytho bloc, trafodiad, neu ddata penodol arall fel a ganlyn:

  • Yn argraffu i'r consol y math o ddata a nodir yn y protocol y mae angen ei dderbyn:
    fmt.Println("DataType:", intrpr.Commands[2])
  • Yn darllen y gwerth intrpr.Corff i newidyn rhifol buf_len
  • Yn creu byffer newbuf maint penodedig:
    make([]byte, buf_len)
  • Anfon ymateb iawn:
    conn.Write([]byte("result:ok"))
  • Yn llenwi'r byffer o'r ffrwd ddarllen yn llwyr:
    io.ReadFull(conn, newbuf)

    .

  • Yn argraffu cynnwys y byffer i'r consol
    fmt.Println(string(newbuf))

    a nifer y bytes a ddarllenwyd

    fmt.Println("Bytes length:", n)
  • Anfon ymateb iawn:
    conn.Write([]byte("result:ok"))

Mae dulliau o'r pecyn gweinydd yn cael eu ffurfweddu i brosesu data a dderbyniwyd gan ddefnyddio swyddogaethau o'r pecyn protocol.

Protocol

Mae protocol yn fodd sy'n cynrychioli data mewn cyfnewid rhwydwaith.

Dewis (llinyn llinyn) (llinyn, gwall) yn perfformio prosesu sylfaenol data a dderbynnir gan y gweinydd, yn derbyn cynrychioliad llinynnol o'r data fel mewnbwn ac yn dychwelyd llinyn a baratowyd ar gyfer Dehonglydd:

  • Rhennir y llinyn mewnbwn yn ddefnydd pen a chorff ReqParseN2(str)
  • mae'r pen wedi'i rannu'n elfennau a'i roi mewn sleisen gorchmynion gan ddefnyddio ReqParseHead(pen)
  • В switsh (gorchmynion[0]) dewiswch y gorchymyn a dderbyniwyd (cmd, allwedd, cyfeiriad neu yr adran yn cael ei sbarduno diofyn)
  • Mae 2 orchymyn yn cael eu gwirio mewn cmd switsh (gorchmynion[1]) - hyd и getversion.
  • hyd yn gwirio'r math o ddata i mewn gorchmynion[2] ac yn ei arbed i mewn datatype
  • Yn gwirio hynny corff yn cynnwys gwerth llinyn
    len(body) < 1
  • Yn dychwelyd y llinyn ymateb:
    "result:bufferlength:" + datatype + "/" + body
  • getversion yn dychwelyd llinyn
    return "result:version/auto"

Dehonglydd

Yn cynnwys y strwythur InterpreteData ac yn perfformio prosesu eilaidd o'r data a ddychwelwyd ohono Dewis llinynnau a ffurfio gwrthrychau DehongliData.

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

Swyddogaeth

Interprete(str string) (*InterpreteData, error)

yn derbyn llinyn arwain ac yn creu ac yn dychwelyd cyfeiriad at y gwrthrych DehongliData.

Cynnydd:

  • Yn yr un modd Dewis pen a chorff yn cael eu tynnu gan ddefnyddio ReqParseN2(str)
  • pen yn cael ei rannu'n elfennau gan ddefnyddio ReqParseHead(pen)
  • Mae'r gwrthrych yn cael ei gychwyn DehongliData a dychwelir pwyntydd ato:

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

Defnyddir y gwrthrych hwn yn gweinydd.go prif becyn.

Cwsmeriaid

Mae'r pecyn cleient yn cynnwys y swyddogaethau TCPConnect и TCPResponseData.

Swyddogaeth

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

yn gweithio fel hyn:

  • Gwneir cysylltiad â'r cysylltiad a nodir yn y gwrthrych gosodiadau a basiwyd
    net.Dial("tcp", s.Host + ":" + s.Port)
  • Mae'r data a drosglwyddir yn y paramedr data yn cael ei drosglwyddo:
    conn.Write(data)
  • Darllenir yr ateb
    resp, n, _ := TCPResponseData(conn, s.BufSize)

    ac wedi ei argraffu ar y consol

    fmt.Println(string(resp[:n]))
  • Os caiff ei drosglwyddo payload yna yn ei drosglwyddo
    conn.Write(payload)

    a hefyd yn darllen ymateb y gweinydd, gan ei argraffu i'r consol

Swyddogaeth

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

yn creu byffer o'r maint penodedig, yn darllen ymateb y gweinydd yno ac yn dychwelyd y byffer hwn a nifer y beitau a ddarllenwyd, yn ogystal â gwrthrych gwall.

Is-reolwaith cleient

Yn gwasanaethu i anfon gorchmynion at weinyddion nodau, yn ogystal â chael ystadegau byr a phrofion.

Yn gallu derbyn y paramedrau canlynol: ffeil ffurfweddu ar ffurf JSON, data i'w hanfon at y gweinydd fel llinyn, llwybr i'r ffeil i'w hanfon i'r llwyth tâl, baner emulation nod scheduler, math o ddata a drosglwyddir fel gwerth rhifol.

  • Cael y cyfluniad
    st := types.ParseConfig(*config)
  • Os bydd y faner emu yn cael ei basio, mae'n dechrau siedlwr
  • Os cyflenwir y faner f sy'n nodi'r llwybr i'r ffeil, yna rydym yn llwytho ei data i mewn fdb ac anfonir y cynnwys i'r gweinydd
    client.TCPConnect(st, []byte(CMD_BUFFER_LENGTH + ":" + strconv.Itoa(*t) + "/" + strconv.Itoa(fdblen)), fdb)
  • Os nad yw'r ffeil wedi'i nodi, yna anfonir y data o'r faner yn syml -d:
    client.TCPConnect(st, []byte(*data), nil)

Mae hyn i gyd yn gynrychiolaeth syml sy'n dangos strwythur y protocol. Yn ystod y datblygiad, ychwanegir y swyddogaeth angenrheidiol at ei strwythur.

Yn yr ail ran byddaf yn siarad am strwythurau data ar gyfer blociau a thrafodion, yn 3 am y gweinydd WebSocket ar gyfer cysylltu o JavaScript, yn 4 byddaf yn edrych ar yr amserlenydd cydamseru, yna peiriant pentwr sy'n prosesu bytecode o fewnbynnau ac allbynnau, cryptograffeg a pyllau ar gyfer allbynnau.

Ffynhonnell: hab.com

Ychwanegu sylw