Pembangunan rantaian sekat untuk industri menggunakan Go. Bahagian 1

Selama empat bulan sekarang saya telah mengusahakan projek yang dipanggil "Pembangunan perlindungan data dan alat pengurusan dalam sektor kerajaan dan perindustrian berdasarkan blockchain."
Sekarang saya ingin memberitahu anda tentang bagaimana saya memulakan projek ini, dan sekarang saya akan menerangkan kod program secara terperinci.

Pembangunan rantaian sekat untuk industri menggunakan Go. Bahagian 1

Ini adalah artikel pertama dalam satu siri artikel. Di sini saya menerangkan pelayan dan protokol. Malah, pembaca juga boleh menulis versi sendiri unsur-unsur blockchain ini.

Dan inilah bahagian kedua β€” mengenai blok blok dan struktur data transaksi, serta mengenai pakej yang melaksanakan interaksi dengan pangkalan data.

Tahun lepas, di hackathon Terobosan Digital, mereka menghasilkan idea untuk membuat sistem yang berguna untuk industri dan ekonomi digital menggunakan teknologi lejar yang diedarkan; geran juga telah dikeluarkan untuk pembangunan oleh Dana Bantuan Inovasi (saya harus menulis yang berasingan artikel tentang geran, bagi mereka yang baru memulakan permulaan ), dan kini dalam susunan.

Pembangunan berlaku dalam bahasa Go, dan pangkalan data di mana blok disimpan ialah LevelDB.
Bahagian utama ialah protokol, pelayan (yang menjalankan TCP dan WebSocket - yang pertama untuk menyegerakkan blockchain, yang kedua untuk menyambungkan pelanggan, menghantar transaksi dan arahan daripada JavaScript, contohnya.

Seperti yang telah disebutkan, blockchain ini diperlukan terutamanya untuk mengautomasikan dan melindungi pertukaran produk antara pembekal dan pelanggan, atau kedua-duanya dalam satu orang. Mereka ini tidak tergesa-gesa untuk mempercayai satu sama lain. Tetapi tugasnya bukan sahaja untuk mencipta "buku cek" dengan kalkulator terbina dalam, tetapi sistem yang mengautomasikan kebanyakan tugas rutin yang timbul apabila bekerja dengan kitaran hayat produk. Bytecode yang bertanggungjawab untuk perkara ini, seperti biasa dengan blockchain, disimpan dalam input dan output urus niaga (urus niaga itu sendiri disimpan dalam blok, blok dalam LevelDB dipra-kod dalam format GOB). Mula-mula, mari kita bercakap tentang protokol dan pelayan (aka nod).

Protokol ini tidak rumit, maksud keseluruhannya adalah untuk beralih kepada mod memuatkan beberapa data, biasanya blok atau transaksi, sebagai tindak balas kepada baris arahan khas, dan ia juga diperlukan untuk menukar inventori, supaya nod mengetahui siapa ia disambungkan kepada dan cara mereka mempunyai perniagaan untuk dilakukan (nod yang disambungkan untuk sesi penyegerakan juga dipanggil "jiran" kerana IP mereka diketahui dan data keadaan mereka disimpan dalam ingatan).

Folder (direktori seperti yang dipanggil Linux) dalam pemahaman pengaturcara Go dipanggil pakej, jadi pada permulaan setiap fail dengan kod Go dari direktori ini mereka menulis folder_nama_pakej_tempat_fail_ini terletak. Jika tidak, anda tidak akan dapat menyuapkan pakej kepada pengkompil. Nah, ini bukan rahsia bagi mereka yang tahu bahasa ini. Ini adalah pakej-pakejnya:

  • Komunikasi rangkaian (pelayan, klien, protokol)
  • Struktur data yang disimpan dan dihantar (blok, transaksi)
  • Pangkalan data (blockchain)
  • Permuafakatan
  • Mesin maya bertindan (xvm)
  • Auxiliary (crypto, type) itu sahaja buat masa ini.

Berikut adalah pautan ke github

Ini adalah versi pendidikan, ia tidak mempunyai interaksi antara proses dan beberapa komponen eksperimen, tetapi strukturnya sepadan dengan yang pembangunan sedang dijalankan. Sekiranya anda mempunyai apa-apa untuk dicadangkan dalam ulasan, saya dengan senang hati akan mengambil kira dalam pembangunan selanjutnya. Dan sekarang untuk penjelasan pelayan dan protokol.

Jom tengok server dulu.

Subrutin pelayan bertindak sebagai pelayan data yang berjalan di atas protokol TCP menggunakan struktur data daripada pakej protokol.

Rutin menggunakan pakej berikut: server, protokol, jenis. Dalam pakej itu sendiri tcp_server.go mengandungi struktur data Sedia untuk dimakan.

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

Ia boleh menerima parameter berikut:

  • Port rangkaian di mana data akan ditukar
  • Fail konfigurasi pelayan dalam format JSON
  • Benderakan untuk berjalan dalam mod nyahpepijat (blockchain peribadi)

Kemajuan:

  • Membaca konfigurasi daripada fail JSON
  • Bendera mod nyahpepijat ditanda: jika ia ditetapkan, penjadual penyegerakan rangkaian tidak dilancarkan dan rantaian blok tidak dimuatkan
  • Memulakan struktur data konfigurasi dan memulakan pelayan

Server

  • Menjalankan pelancaran pelayan TCP dan interaksi rangkaian mengikut protokol.
  • Ia mempunyai struktur data Serve yang terdiri daripada nombor port, saiz penimbal dan penunjuk kepada struktur jenis.Tetapan
  • Kaedah Run memulakan interaksi rangkaian (mendengar sambungan masuk pada port tertentu, apabila sambungan baharu diterima, pemprosesannya dipindahkan ke kaedah pemegang persendirian dalam utas baharu)
  • Π’ mengendalikan data daripada sambungan dibaca ke dalam penimbal, ditukar kepada perwakilan rentetan dan dihantar ke protokol.Pilihan
  • protokol.Pilihan pulangan mengakibatkan atau menyebabkan ralat. mengakibatkan kemudian dipindahkan ke protokol.Mentafsiryang kembali intrpr - objek jenis InterpreteData, atau menyebabkan ralat dalam memproses hasil pemilihan
  • Kemudian suis dilaksanakan intrpr.Arahan[0] yang menyemak salah satu daripada: hasil, inv, ralat dan ada bahagian lalai
  • Dalam bahagian mengakibatkan suis ditemui mengikut nilai intrpr.Arahan[1] yang menyemak nilai panjang penampan ΠΈ versi (dalam setiap kes fungsi yang sepadan dipanggil)

Fungsi GetVersion ΠΈ Panjang Penampan berada dalam fail srvlib.go pakej pelayan

GetVersion(conn net.Conn, version string)

ia hanya mencetak ke konsol dan menghantar versi yang diluluskan dalam parameter kepada klien:

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

.
Fungsi

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

memuatkan blok, transaksi atau data khusus lain seperti berikut:

  • Mencetak ke konsol jenis data yang dinyatakan dalam protokol yang perlu diterima:
    fmt.Println("DataType:", intrpr.Commands[2])
  • Membaca nilai intrpr.Badan kepada pembolehubah berangka buf_len
  • Mencipta penimbal newbuf saiz yang ditetapkan:
    make([]byte, buf_len)
  • Menghantar jawapan ok:
    conn.Write([]byte("result:ok"))
  • Mengisi penimbal sepenuhnya daripada strim baca:
    io.ReadFull(conn, newbuf)

    .

  • Mencetak kandungan penimbal ke konsol
    fmt.Println(string(newbuf))

    dan bilangan bait yang dibaca

    fmt.Println("Bytes length:", n)
  • Menghantar jawapan ok:
    conn.Write([]byte("result:ok"))

Kaedah daripada pakej pelayan dikonfigurasikan untuk memproses data yang diterima menggunakan fungsi daripada pakej protokol.

Protokol

Protokol berfungsi sebagai alat yang mewakili data dalam pertukaran rangkaian.

Pilihan(rentetan str) (rentetan, ralat) menjalankan pemprosesan utama data yang diterima oleh pelayan, menerima perwakilan rentetan data sebagai input dan mengembalikan rentetan yang disediakan untuk Jurubahasa:

  • Rentetan input dibahagikan kepada kepala dan badan menggunakan ReqParseN2(str)
  • kepala dibahagikan kepada elemen dan diletakkan ke dalam kepingan arahan menggunakan ReqParseHead(kepala)
  • Π’ suis(arahan[0]) pilih arahan yang diterima (cmd, kunci, alamat atau bahagian itu dicetuskan lalai)
  • 2 arahan disemak dalam cmd suis(arahan[1]) β€” panjang ΠΈ getversion.
  • panjang menyemak jenis data masuk arahan[2] dan menyimpannya jenis data
  • Semak itu badan mengandungi nilai rentetan
    len(body) < 1
  • Mengembalikan rentetan respons:
    "result:bufferlength:" + datatype + "/" + body
  • getversion mengembalikan rentetan
    return "result:version/auto"

Jurubahasa

Mengandungi struktur InterpreteData dan melaksanakan pemprosesan sekunder data yang dikembalikan daripada Pilihan rentetan dan pembentukan objek InterpreteData.

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

Fungsi

Interprete(str string) (*InterpreteData, error)

menerima rentetan mengakibatkan dan mencipta dan mengembalikan rujukan kepada objek InterpreteData.

Kemajuan:

  • Begitu juga Pilihan kepala dan badan diekstrak menggunakan ReqParseN2(str)
  • kepala dipecahkan kepada unsur menggunakan ReqParseHead(kepala)
  • Objek dimulakan InterpreteData dan penunjuk kepadanya dikembalikan:

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

Objek ini digunakan dalam server.go pakej utama.

Pelanggan

Pakej klien mengandungi fungsi TCPConnect ΠΈ TCPResponseData.

Fungsi

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

berfungsi seperti berikut:

  • Sambungan dibuat kepada sambungan yang dinyatakan dalam objek tetapan yang diluluskan
    net.Dial("tcp", s.Host + ":" + s.Port)
  • Data yang diluluskan dalam parameter data dihantar:
    conn.Write(data)
  • Jawapannya dibaca
    resp, n, _ := TCPResponseData(conn, s.BufSize)

    dan dicetak pada konsol

    fmt.Println(string(resp[:n]))
  • Jika dipindahkan muatan kemudian meneruskannya
    conn.Write(payload)

    dan juga membaca respons pelayan, mencetaknya ke konsol

Fungsi

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

mencipta penimbal dengan saiz yang ditentukan, membaca respons pelayan di sana dan mengembalikan penimbal ini dan bilangan bait yang dibaca, serta objek ralat.

Subrutin pelanggan

Berfungsi untuk menghantar arahan kepada pelayan nod, serta mendapatkan statistik dan ujian ringkas.

Boleh menerima parameter berikut: fail konfigurasi dalam format JSON, data untuk dihantar ke pelayan sebagai rentetan, laluan ke fail untuk dihantar ke muatan, bendera emulasi penjadual nod, jenis data yang dipindahkan sebagai nilai berangka.

  • Mendapatkan konfigurasi
    st := types.ParseConfig(*config)
  • Jika bendera emu diluluskan, ia bermula sheduler
  • Jika bendera f yang menunjukkan laluan ke fail dibekalkan, maka kami memuatkan datanya ke dalam fdb dan kandungan dihantar ke pelayan
    client.TCPConnect(st, []byte(CMD_BUFFER_LENGTH + ":" + strconv.Itoa(*t) + "/" + strconv.Itoa(fdblen)), fdb)
  • Jika fail tidak dinyatakan, maka data dari bendera hanya dihantar -d:
    client.TCPConnect(st, []byte(*data), nil)

Semua ini adalah perwakilan ringkas yang menunjukkan struktur protokol. Semasa pembangunan, fungsi yang diperlukan ditambah pada strukturnya.

Di bahagian kedua saya akan bercakap tentang struktur data untuk blok dan transaksi, dalam 3 tentang pelayan WebSocket untuk menyambung dari JavaScript, dalam 4 saya akan melihat penjadual penyegerakan, kemudian mesin tindanan yang memproses bytecode daripada input dan output, kriptografi dan kolam untuk output.

Sumber: www.habr.com

Tambah komen