Blockchain-udvikling til industrien ved hjælp af Go. Del 1

I fire måneder nu har jeg arbejdet på et projekt kaldet "Udvikling af databeskyttelses- og styringsværktøjer i offentlige og industrielle sektorer baseret på blockchain."
Nu vil jeg gerne fortælle dig om, hvordan jeg startede dette projekt, og nu vil jeg beskrive programkoden i detaljer.

Blockchain-udvikling til industrien ved hjælp af Go. Del 1

Dette er den første artikel i en serie af artikler. Her beskriver jeg serveren og protokollen. Faktisk kan læseren endda skrive sine egne versioner af disse blockchain-elementer.

Og her er anden del — om blockchain- og transaktionsdatastrukturer, samt om pakken, der implementerer interaktion med databasen.

Sidste år, på Digital Breakthrough hackathon, kom de med en idé om at lave et nyttigt system til industrien og den digitale økonomi ved hjælp af distribueret hovedbogsteknologi; der blev også udstedt en bevilling til udviklingen af ​​Innovation Assistance Foundation (jeg burde skrive en separat artikel om bevillingen, for dem der lige er begyndt at lave startups ), og nu i orden.

Udviklingen foregår i Go-sproget, og databasen, som blokkene er gemt i, er LevelDB.
Hoveddelene er protokollen, serveren (som kører TCP og WebSocket - den første til synkronisering af blockchain, den anden til at forbinde klienter, sende transaktioner og kommandoer fra f.eks. JavaScript.

Som nævnt er denne blockchain primært nødvendig for at automatisere og beskytte udvekslingen af ​​produkter mellem leverandører og kunder, eller begge dele i én person. Disse mennesker har ikke travlt med at stole på hinanden. Men opgaven er ikke kun at lave et "checkhæfte" med en indbygget lommeregner, men et system, der automatiserer de fleste af de rutineopgaver, der opstår, når man arbejder med produktets livscyklus. Bytekoden, der er ansvarlig for denne sag, som det er sædvanligt med blockchains, lagres i input og output af transaktioner (selve transaktionerne er lagret i blokke, blokkene i LevelDB er præ-kodet i GOB-formatet). Lad os først fortælle dig om protokollen og serveren (alias node).

Protokollen er ikke kompliceret, hele dens pointe er at skifte til tilstanden til at indlæse nogle data, normalt en blok eller transaktion, som svar på en speciel kommandolinje, og den er også nødvendig for at udveksle inventar, så noden ved, hvem den er forbundet til, og hvordan de har forretninger at gøre (noderne forbundet til synkroniseringssessionen kaldes også "naboer", fordi deres IP er kendt, og deres tilstandsdata er gemt i hukommelsen).

Mapper (mapper som Linux kalder dem) i forståelsen af ​​Go-programmører kaldes pakker, derfor skriver de i begyndelsen af ​​hver fil med Go-kode fra denne mappe pakken folder_name_where_this_file er placeret. Ellers vil du ikke være i stand til at sende pakken til compileren. Nå, dette er ingen hemmelighed for dem, der kender dette sprog. Dette er pakkerne:

  • Netværkskommunikation (server, klient, protokol)
  • Strukturer af lagrede og transmitterede data (blokering, transaktion)
  • Database (blockchain)
  • Konsensus
  • Stablet virtuel maskine (xvm)
  • Auxiliary (krypto, typer) det er alt for nu.

Her er linket til github

Dette er en pædagogisk version, den mangler inter-proces interaktion og flere eksperimentelle komponenter, men strukturen svarer til den, som udviklingen udføres på. Hvis du har noget at foreslå i kommentarerne, vil jeg gerne tage det i betragtning i den videre udvikling. Og nu til en forklaring af serveren og protokol.

Lad os først se på serveren.

Serverunderrutinen fungerer som en dataserver, der kører oven på TCP-protokollen ved hjælp af datastrukturer fra protokolpakken.

Rutinen bruger følgende pakker: server, protokol, typer. I selve pakken tcp_server.go indeholder datastruktur Tjene.

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

Den kan acceptere følgende parametre:

  • Netværksport, hvorigennem data vil blive udvekslet
  • Serverkonfigurationsfil i JSON-format
  • Flag for at køre i fejlretningstilstand (privat blockchain)

Fremskridt:

  • Læser konfiguration fra JSON-fil
  • Fejlfindingstilstandsflaget er markeret: hvis det er indstillet, startes netværkssynkroniseringsplanlæggeren ikke, og blockchainen indlæses ikke
  • Initialisering af konfigurationsdatastrukturen og start af serveren

Server

  • Udfører lanceringen af ​​TCP-serveren og netværksinteraktion i overensstemmelse med protokollen.
  • Den har en Serve-datastruktur bestående af et portnummer, en bufferstørrelse og en pegepind til strukturen typer.Indstillinger
  • Kør-metoden starter netværksinteraktion (lytter efter indgående forbindelser på en given port, når en ny forbindelse modtages, overføres dens behandling til den private håndteringsmetode i en ny tråd)
  • В håndtere data fra forbindelsen læses ind i en buffer, konverteres til en strengrepræsentation og sendes til protokol.Valg
  • protokol.Valg vender tilbage resultere eller forårsager en fejl. resultere derefter overført til protokol. Fortolkesom vender tilbage intrpr - typeobjekt Fortolke Data, eller forårsager en fejl i behandlingen af ​​udvælgelsesresultatet
  • Derefter udføres skiftet intrpr.Commands[0] som tjekker en af: resultat, inv, fejl og der er et afsnit standard
  • I afsnittet resultere switch findes efter værdi intrpr.Commands[1] som tjekker værdierne bufferlængde и udgave (i hvert tilfælde kaldes den tilsvarende funktion)

Funktioner GetVersion и Bufferlængde er i filen srvlib.go serverpakke

GetVersion(conn net.Conn, version string)

den udskriver simpelthen til konsollen og sender den version, der er sendt i parameteren, til klienten:

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

.
Funktion

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

indlæser en blok, transaktion eller andre specifikke data som følger:

  • Udskriver til konsollen den type data, der er angivet i protokollen, der skal accepteres:
    fmt.Println("DataType:", intrpr.Commands[2])
  • Læser værdien intrpr.Body til en numerisk variabel buff_len
  • Opretter en buffer newbuf specificeret størrelse:
    make([]byte, buf_len)
  • Sender et ok svar:
    conn.Write([]byte("result:ok"))
  • Fylder bufferen fra læsestrømmen fuldstændigt:
    io.ReadFull(conn, newbuf)

    .

  • Udskriver indholdet af bufferen til konsollen
    fmt.Println(string(newbuf))

    og antallet af læste bytes

    fmt.Println("Bytes length:", n)
  • Sender et ok svar:
    conn.Write([]byte("result:ok"))

Metoder fra serverpakken er konfigureret til at behandle modtagne data ved hjælp af funktioner fra pakken protokol.

protokol

En protokol tjener som et middel, der repræsenterer data i netværksudveksling.

Valg(str streng) (streng, fejl) udfører primær behandling af data modtaget af serveren, modtager en strengrepræsentation af dataene som input og returnerer en streng forberedt til Tolk:

  • Indtastningsstrengen opdeles i hoved og krop vha ReqParseN2(str)
  • hovedet opdeles i elementer og placeres i et kommandoudsnit ved hjælp af ReqParseHead(head)
  • В switch(kommandoer[0]) vælg den modtagne kommando (cmd, nøgle, adresse eller afsnittet udløses standard)
  • 2 kommandoer er afkrydset i cmd switch(kommandoer[1]) — længde и getversion.
  • længde tjekker datatypen ind kommandoer[2] og gemmer den ind datatype
  • Tjekker det krop indeholder en strengværdi
    len(body) < 1
  • Returnerer svarstrengen:
    "result:bufferlength:" + datatype + "/" + body
  • getversion returnerer en streng
    return "result:version/auto"

Tolk

Indeholder InterpreteData-strukturen og udfører sekundær behandling af de data, der returneres fra Valg strenge og objektdannelse Fortolke Data.

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

Funktion

Interprete(str string) (*InterpreteData, error)

accepterer en streng resultere og opretter og returnerer en reference til objektet Fortolke Data.

Fremskridt:

  • Tilsvarende Valg hoved og krop udvindes vha ReqParseN2(str)
  • hovedet opdeles i elementer vha ReqParseHead(hoved)
  • Objektet initialiseres Fortolke Data og en pointer til det returneres:

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

Dette objekt bruges i server.go hovedpakke.

Klient

Klientpakken indeholder funktionerne TCPConnect и TCPResponseData.

Funktion

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

virker sådan her:

  • Der oprettes forbindelse til den forbindelse, der er angivet i det beståede indstillingsobjekt
    net.Dial("tcp", s.Host + ":" + s.Port)
  • De data, der sendes i dataparameteren, overføres:
    conn.Write(data)
  • Svaret er læst
    resp, n, _ := TCPResponseData(conn, s.BufSize)

    og trykt på konsollen

    fmt.Println(string(resp[:n]))
  • Hvis overført nyttelast så sender det videre
    conn.Write(payload)

    og læser også serversvaret og udskriver det til konsollen

Funktion

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

opretter en buffer af den angivne størrelse, læser serversvaret der og returnerer denne buffer og antallet af læste bytes samt et fejlobjekt.

Klientunderrutine

Tjener til at sende kommandoer til nodeservere, samt opnå korte statistikker og test.

Kan acceptere følgende parametre: konfigurationsfil i JSON-format, data, der skal sendes til serveren som en streng, sti til filen, der skal sendes til nyttelast, nodeplanlægnings-emuleringsflag, type data, der overføres som en numerisk værdi.

  • Henter konfigurationen
    st := types.ParseConfig(*config)
  • Hvis emu-flaget passeres, starter det sheduler
  • Hvis f-flaget, der angiver stien til filen, er leveret, indlæser vi dens data i fdb og indholdet sendes til serveren
    client.TCPConnect(st, []byte(CMD_BUFFER_LENGTH + ":" + strconv.Itoa(*t) + "/" + strconv.Itoa(fdblen)), fdb)
  • Hvis filen ikke er angivet, sendes dataene fra flaget simpelthen -d:
    client.TCPConnect(st, []byte(*data), nil)

Alt dette er en forenklet repræsentation, der viser strukturen af ​​protokollen. Under udviklingen tilføjes den nødvendige funktionalitet til dens struktur.

I anden del vil jeg tale om datastrukturer for blokke og transaktioner, i 3 om WebSocket-serveren til tilslutning fra JavaScript, i 4 vil jeg se på synkroniseringsplanlæggeren, derefter en stackmaskine, der behandler bytekode fra input og output, kryptografi og puljer til output.

Kilde: www.habr.com

Tilføj en kommentar