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.
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.
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à.
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