Sviluppu di Blockchain per l'industria cù Go. Parte 1

Dapoi quattru mesi aghju travagliatu nantu à un prughjettu chjamatu "Sviluppu di strumenti di prutezzione è gestione di dati in i settori di u guvernu è industriale basatu nantu à blockchain".
Avà vogliu dì à voi cumu aghju cuminciatu stu prughjettu, è avà vi discriverà u codice di u prugramma in dettaglio.

Sviluppu di Blockchain per l'industria cù Go. Parte 1

Questu hè u primu articulu in una seria di articuli. Quì descrive u servitore è u protocolu. In fatti, u lettore pò ancu scrive e so versioni di questi elementi di blockchain.

È quì hè a seconda parte - nantu à blockchain è strutture di dati di transazzione, è ancu di u pacchettu chì implementa l'interazzione cù a basa di dati.

L'annu passatu, à l'hackathon di Digital Breakthrough, anu avutu l'idea di fà un sistema utile per l'industria è l'ecunumia digitale utilizendu a tecnulugia di ledger distribuitu; una cuncessione hè stata ancu emessa per u sviluppu da u Fondu d'Assistenza à l'Innovazione (aghju da scrive un documentu separatu). articulu nantu à a cuncessione, per quelli chì sò appena cuminciati startups ), è avà in ordine.

U sviluppu si svolge in a lingua Go, è a basa di dati in quale i blocchi sò almacenati hè LevelDB.
I parti principali sò u protokollu, u servitore (chì corre TCP è WebSocket - u primu per a sincronizazione di u blockchain, u sicondu per a cunnessione di i clienti, l'inviu di transazzione è cumandamenti da JavaScript, per esempiu.

Comu hè statu dettu, stu blockchain hè necessariu principarmenti per automatizà è prutegge u scambiu di prudutti trà i fornituri è i clienti, o i dui in una sola persona. Queste persone ùn anu micca fretta di cunfidassi l'una in l'altru. Ma u compitu ùn hè micca solu di creà un "checkbook" cù una calculatrice integrata, ma un sistema chì automatizeghja a maiò parte di i travaglii di rutina chì nascenu quandu u travagliu cù u ciclu di vita di u produttu. U bytecode chì hè rispunsevuli di sta materia, cum'è l'abitudine cù blockchains, hè guardatu in l'inputs and outputs of transactions (i transazzioni stessi sò stati guardati in blocchi, i blocchi in LevelDB sò pre-codificati in u formatu GOB). Prima, parlemu di u protocolu è u servitore (aka node).

U protokollu ùn hè micca cumplicatu, u so puntu tutale hè di cambià à u modu di carica di qualchi dati, di solitu un bloccu o transazzione, in risposta à una linea di cummanda speciale, è hè ancu necessariu per scambià l'inventariu, perchè u node sapi quale hè. hè cunnessu è cumu anu da fà l'affari (i nodi cunnessi per a sessione di sincronizazione sò ancu chjamati "vicini" perchè a so IP hè cunnisciuta è i so dati statali sò guardati in memoria).

Folders (cartulari cum'è Linux li chjama) in l'intelligenza di i programatori Go sò chjamati pacchetti, cusì à l'iniziu di ogni schedariu cù u codice Go da questu repertoriu scrivenu u pacchettu folder_name_where_this_file hè situatu. Altrimenti, ùn puderete micca alimentà u pacchettu à u compilatore. Eppo, questu ùn hè micca un sicretu per quelli chì cunnosci sta lingua. Eccu i pacchetti:

  • Comunicazione in rete (servitore, cliente, protocolu)
  • Strutture di dati almacenati è trasmessi (bloccu, transazzione)
  • basa di dati (blockchain)
  • Cunsensu
  • Macchina virtuale impilata (xvm)
  • Auxiliary (cripto, tipi) hè tuttu per avà.

Eccu u ligame per github

Questa hè una versione educativa, ùn manca l'interazzione inter-processu è parechji cumpunenti sperimentali, ma a struttura currisponde à quella nantu à quale u sviluppu hè realizatu. Sì avete qualcosa da suggerisce in i cumenti, saraghju felice di piglià in contu in u sviluppu ulteriore. È avà per una spiegazione di u servitore è prutucolu.

Fighjemu prima u servitore.

A subrutina di u servitore agisce cum'è un servitore di dati chì corre nantu à u protocolu TCP utilizendu strutture di dati da u pacchettu di protocolu.

A rutina usa i seguenti pacchetti: servore, prutucolu, tippi. In u pacchettu stessu tcp_server.go cuntene struttura di dati Servite.

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

Pò accettà i seguenti parametri:

  • Port di rete à traversu quale i dati seranu scambiati
  • File di cunfigurazione di u servitore in formatu JSON
  • Bandiera per eseguisce in modu di debug (blockchain privatu)

Prugressu:

  • Leghjite a cunfigurazione da u schedariu JSON
  • A bandiera di u modu di debug hè verificatu: se hè stabilitu, u pianificatore di sincronizazione di a rete ùn hè micca lanciatu è u blockchain ùn hè micca caricatu
  • Initializing the configuration data structure and starting the server

Servidor

  • Esegue u lanciu di u servitore TCP è l'interazzione di a rete in cunfurmità cù u protocolu.
  • Havi una struttura di dati Serve custituita da un numeru di portu, una dimensione di buffer è un puntatore à a struttura tipi.Settings
  • U metudu Run principia l'interazzione di a rete (ascolta e cunnessione entranti in un portu determinatu, quandu una nova cunnessione hè ricevuta, u so prucessu hè trasferitu à u metudu di maniglia privata in un novu filu)
  • В manicura i dati da a cunnessione sò letti in un buffer, cunvertiti in una rapprisintazioni di stringa è passati à protocolu.Scelta
  • protocolu.Scelta torna risurtatu o provoca un errore. risurtatu dopu trasferitu à protocolu.Interpretechì torna intrpr - ughjettu di tipu InterpreteData, o provoca un errore in u processu di u risultatu di selezzione
  • Allora u cambiamentu hè eseguitu intrpr.Cumandamenti[0] chì verifica unu di: risultatu, inv, errore è ci hè una sezione automaticamente
  • In a rùbbrica risurtatu switch hè trovu da u valore intrpr.Cumandamenti[1] chì verifica i valori lunghezza di buffer и versione (in ogni casu a funzione currispundenti hè chjamata)

Funzioni GetVersion и Lunghezza di buffer sò in u schedariu srvlib.go pacchettu di u servitore

GetVersion(conn net.Conn, version string)

simpricimenti stampa à a cunsola è manda a versione passata in u paràmetru à u cliente:

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

.
funziunava

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

carica un bloccu, transazzione, o altri dati specifichi cum'è seguente:

  • Stampa à a cunsola u tipu di dati specificati in u protocolu chì deve esse accettatu:
    fmt.Println("DataType:", intrpr.Commands[2])
  • Leghjite u valore intrpr.Corpu à una variabile numerica buf_len
  • Crea un buffer newbuf taglia specificata:
    make([]byte, buf_len)
  • Manda una risposta ok:
    conn.Write([]byte("result:ok"))
  • Riempite cumplettamente u buffer da u flussu di lettura:
    io.ReadFull(conn, newbuf)

    .

  • Imprime u cuntenutu di u buffer à a cunsola
    fmt.Println(string(newbuf))

    è u numeru di bytes letti

    fmt.Println("Bytes length:", n)
  • Manda una risposta ok:
    conn.Write([]byte("result:ok"))

I metudi da u pacchettu di u servitore sò cunfigurati per processà e dati ricevuti utilizendu funzioni da u pacchettu prutucolu.

Protocol

Un protokollu serve cum'è un mezzu chì rapprisenta dati in u scambiu di rete.

Scelta (stringa di stringa) (stringa, errore) esegue u trattamentu primariu di e dati ricevuti da u servitore, riceve una rappresentazione di stringa di e dati cum'è input è torna una stringa preparata per Interpretu:

  • A stringa di input hè divisa in testa è corpu usendu ReqParseN2(str)
  • a testa hè divisa in elementi è piazzata in una fetta di cumandamenti cù ReqParseHead (head)
  • В cambia (cumandamenti [0]) sceglite u cumandamentu ricevutu (cmd, chjave, indirizzu o a rùbbrica hè attivata automaticamente)
  • 2 cumandamenti sò verificati in cmd switch (cumandamenti [1]) - lunghezza и getversione.
  • durata verifica u tipu di dati in cumandamenti [2] è u salva in tippu di dati
  • Cuntrolla chì corpu cuntene un valore di stringa
    len(body) < 1
  • Ritorna a stringa di risposta:
    "result:bufferlength:" + datatype + "/" + body
  • getversione torna una stringa
    return "result:version/auto"

Interpretu

Contene a struttura InterpreteData è eseguisce u trattamentu secundariu di e dati restituiti Zitellu corde è furmazione di l'ughjettu InterpreteData.

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

funziunava

Interprete(str string) (*InterpreteData, error)

accetta una stringa risurtatu è crea è torna una riferenza à l'ughjettu InterpreteData.

Prugressu:

  • Di listessa manera Zitellu a testa è u corpu sò estratti usendu ReqParseN2(str)
  • testa hè spartutu in elementi cù usu ReqParseHead (testa)
  • L'ughjettu hè inizializatu InterpreteData è un puntatore à questu hè tornatu:

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

Stu oggettu hè usatu in server.go pacchettu principale.

Client

U pacchettu di u cliente cuntene e funzioni TCPConnect и TCPResponseData.

funziunava

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

funziona cusì:

  • Una cunnessione hè fatta à a cunnessione specificata in l'ughjettu di paràmetri passati
    net.Dial("tcp", s.Host + ":" + s.Port)
  • I dati passati in u paràmetru di dati sò trasmessi:
    conn.Write(data)
  • A risposta hè leghje
    resp, n, _ := TCPResponseData(conn, s.BufSize)

    è stampatu nantu à a cunsola

    fmt.Println(string(resp[:n]))
  • Se trasferitu payload poi trasmette
    conn.Write(payload)

    è ancu leghje a risposta di u servitore, stampendu à a cunsola

funziunava

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

crea un buffer di a dimensione specifica, leghje a risposta di u servitore quì è torna stu buffer è u numeru di bytes letti, è ancu un oggettu d'errore.

Subrutina di u cliente

Serve per mandà cumandamenti à i servitori di nodi, è ancu per ottene statistiche brevi è teste.

Pò accettà i seguenti paràmetri: u schedariu di cunfigurazione in u formatu JSON, i dati per esse mandati à u servitore cum'è una stringa, u percorsu à u schedariu per esse mandatu à u payload, u node scheduler emulation flag, u tipu di dati trasferitu cum'è un valore numericu.

  • Ottene a cunfigurazione
    st := types.ParseConfig(*config)
  • Se a bandiera emu hè passata, principia sheduler
  • Se a bandiera f chì indica a strada di u schedariu hè furnita, allora carchemu i so dati in fdb è u cuntenutu hè mandatu à u servitore
    client.TCPConnect(st, []byte(CMD_BUFFER_LENGTH + ":" + strconv.Itoa(*t) + "/" + strconv.Itoa(fdblen)), fdb)
  • Se u schedariu ùn hè micca specificatu, i dati da a bandiera sò simpliciamente mandati -d:
    client.TCPConnect(st, []byte(*data), nil)

Tuttu chistu hè una rapprisintazioni simplificata chì mostra a struttura di u protocolu. Durante u sviluppu, a funziunalità necessaria hè aghjuntu à a so struttura.

In a seconda parte, parraraghju di strutture di dati per blocchi è transacciones, in 3 nantu à u servitore WebSocket per cunnette da JavaScript, in 4 fighjuleraghju à u pianificatore di sincronizazione, dopu una stack machine chì processa bytecode da inputs and outputs, criptografia è piscine per uscite.

Source: www.habr.com

Add a comment