Разработка на блокчейн за индустрията с помощта на Go. Част 1

Вече четири месеца работя по проект, наречен „Разработване на инструменти за защита и управление на данни в държавния и индустриалния сектор, базирани на блокчейн“.
Сега бих искал да ви разкажа как започнах този проект и сега ще опиша подробно програмния код.

Разработка на блокчейн за индустрията с помощта на Go. Част 1

Това е първата статия от поредица от статии. Тук описвам сървъра и протокола. Всъщност читателят може дори да напише свои собствени версии на тези блокчейн елементи.

А ето и втората част — за блокчейн и структури от данни за транзакции, както и за пакета, който осъществява взаимодействие с базата данни.

Миналата година на хакатона Digital Breakthrough им хрумна идея да направят полезна система за индустрията и дигиталната икономика, използвайки технологията на разпределения регистър; също беше издаден грант за разработката от Фонда за подпомагане на иновациите (трябва да напиша отделно статия за безвъзмездната помощ, за тези, които тепърва започват да правят стартиращи фирми ), и сега по ред.

Разработката се извършва на езика Go, а базата данни, в която се съхраняват блоковете, е LevelDB.
Основните части са протоколът, сървърът (който изпълнява TCP и WebSocket - първият за синхронизиране на блокчейна, вторият за свързване на клиенти, изпращане на транзакции и команди от JavaScript, например.

Както беше споменато, тази блокчейн е необходима предимно за автоматизиране и защита на обмена на продукти между доставчици и клиенти или и двете в едно лице. Тези хора не бързат да се доверят един на друг. Но задачата е не само да се създаде „чекова книжка“ с вграден калкулатор, а система, която автоматизира повечето от рутинните задачи, които възникват при работа с жизнения цикъл на продукта. Байт кодът, който е отговорен за този въпрос, както е обичайно с блоковите вериги, се съхранява във входовете и изходите на транзакциите (самите транзакции се съхраняват в блокове, блоковете в LevelDB са предварително кодирани във формат GOB). Първо, нека поговорим за протокола и сървъра (известен още като възел).

Протоколът не е сложен, целият му смисъл е да се превключи към режим на зареждане на някои данни, обикновено блок или транзакция, в отговор на специален команден ред, а също така е необходим за обмен на инвентар, така че възелът да знае кой е е свързан и как имат работа (възлите, свързани за сесията за синхронизиране, се наричат ​​също „съседни“, защото техният IP е известен и техните данни за състоянието се съхраняват в паметта).

Папките (директориите, както ги нарича Linux) в разбирането на Go програмистите се наричат ​​пакети, така че в началото на всеки файл с Go код от тази директория те пишат package_name_name_където_този_файл се намира. В противен случай няма да можете да подадете пакета към компилатора. Е, това не е тайна за тези, които владеят този език. Това са пакетите:

  • Мрежова комуникация (сървър, клиент, протокол)
  • Структури на съхранявани и предавани данни (блок, транзакция)
  • База данни (блокчейн)
  • Консенсус
  • Подредена виртуална машина (xvm)
  • Спомагателни (крипто, типове) това е всичко за сега.

Ето връзката към github

Това е образователна версия, в нея липсва междупроцесно взаимодействие и няколко експериментални компонента, но структурата съответства на тази, върху която се извършва разработката. Ако имате какво да предложите в коментарите, ще се радвам да го взема предвид при по-нататъшно развитие. А сега за обяснение на сървъра и протокол.

Нека първо да разгледаме сървъра.

Сървърната подпрограма действа като сървър за данни, който работи върху TCP протокола, използвайки структури от данни от пакета на протокола.

Рутината използва следните пакети: сървър, протокол, видове. В самата опаковка tcp_server.go съдържа структура от данни служа.

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

Може да приеме следните параметри:

  • Мрежов порт, през който ще се обменят данни
  • Конфигурационен файл на сървъра във формат JSON
  • Флаг за работа в режим на отстраняване на грешки (частен блокчейн)

Напредък:

  • Чете конфигурация от JSON файл
  • Флагът за режим на отстраняване на грешки се проверява: ако е зададен, планировчикът за мрежова синхронизация не се стартира и блокчейнът не се зарежда
  • Инициализиране на структурата на конфигурационните данни и стартиране на сървъра

Сървър

  • Извършва стартирането на TCP сървъра и мрежовото взаимодействие в съответствие с протокола.
  • Той има структура от данни за обслужване, състояща се от номер на порт, размер на буфера и указател към структурата типове.Настройки
  • Методът Run стартира мрежово взаимодействие (слушане за входящи връзки на даден порт, когато се получи нова връзка, нейната обработка се прехвърля към частния метод на манипулиране в нова нишка)
  • В дръжка данните от връзката се четат в буфер, преобразуват се в представяне на низ и се предават на протокол.Избор
  • протокол.Избор се завръща резултат или причинява грешка. резултат след това се прехвърля в протокол.Тълккойто се връща intrpr - обект от тип InterpreteData, или причинява грешка при обработката на резултата от избора
  • След това превключването се изпълнява intrpr.Команди[0] който проверява едно от: резултат, инв., грешка и има раздел подразбиране
  • В раздела резултат превключвателят се намира по стойност intrpr.Команди[1] който проверява стойностите буферна дължина и версия (във всеки случай се извиква съответната функция)

функции GetVersion и BufferLength са във файла srvlib.go сървърен пакет

GetVersion(conn net.Conn, version string)

той просто отпечатва на конзолата и изпраща версията, предадена в параметъра, на клиента:

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

.
Функция

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

зарежда блок, транзакция или други специфични данни, както следва:

  • Отпечатва на конзолата типа данни, посочени в протокола, които трябва да бъдат приети:
    fmt.Println("DataType:", intrpr.Commands[2])
  • Прочита стойността intrpr.Тяло към числова променлива buf_len
  • Създава буфер newbuf посочен размер:
    make([]byte, buf_len)
  • Изпраща добър отговор:
    conn.Write([]byte("result:ok"))
  • Изцяло запълва буфера от прочетения поток:
    io.ReadFull(conn, newbuf)

    .

  • Отпечатва съдържанието на буфера на конзолата
    fmt.Println(string(newbuf))

    и броя на прочетените байтове

    fmt.Println("Bytes length:", n)
  • Изпраща добър отговор:
    conn.Write([]byte("result:ok"))

Методите от сървърния пакет са конфигурирани да обработват получените данни с помощта на функции от пакета протокол.

протокол

Протоколът служи като средство за представяне на данни при мрежов обмен.

Избор (низ) (низ, грешка) извършва първична обработка на данни, получени от сървъра, получава низово представяне на данните като вход и връща низ, подготвен за Преводач:

  • Входящият низ се разделя на глава и тяло с помощта ReqParseN2(str)
  • главата се разделя на елементи и се поставя в секция с команди с помощта на ReqParseHead(head)
  • В превключвател (команди [0]) изберете получената команда (cmd, ключ, адрес или секцията се задейства подразбиране)
  • 2 команди са проверени в cmd switch(commands[1]) — дължина и getversion.
  • Дължината проверява типа данни команди [2] и го записва в тип данни
  • Проверява това тяло съдържа низова стойност
    len(body) < 1
  • Връща низа за отговор:
    "result:bufferlength:" + datatype + "/" + body
  • getversion връща низ
    return "result:version/auto"

Преводач

Съдържа структурата InterpreteData и извършва вторична обработка на данните, върнати от Избор низове и образуване на обекти InterpreteData.

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

Функция

Interprete(str string) (*InterpreteData, error)

приема низ резултат и създава и връща препратка към обекта InterpreteData.

Напредък:

  • по същия начин Избор главата и тялото се извличат с помощта на ReqParseN2(str)
  • главата се разделя на елементи с помощта на ReqParseHead(глава)
  • Обектът е инициализиран InterpreteData и се връща указател към него:

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

Този обект се използва в server.go основен пакет.

Удовлетвореност

Клиентският пакет съдържа функциите TCPConnect и TCPResponseData.

Функция

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

работи както следва:

  • Осъществява се връзка към връзката, посочена в обекта на предаваните настройки
    net.Dial("tcp", s.Host + ":" + s.Port)
  • Данните, предадени в параметъра данни, се предават:
    conn.Write(data)
  • Отговорът се чете
    resp, n, _ := TCPResponseData(conn, s.BufSize)

    и се отпечатва на конзолата

    fmt.Println(string(resp[:n]))
  • Ако се прехвърли полезен товар след това го предава
    conn.Write(payload)

    и също така чете отговора на сървъра, отпечатвайки го на конзолата

Функция

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

създава буфер с указания размер, прочита отговора на сървъра там и връща този буфер и броя на прочетените байтове, както и обект за грешка.

Клиентска подпрограма

Служи за изпращане на команди към възлови сървъри, както и за получаване на кратка статистика и тестване.

Може да приеме следните параметри: конфигурационен файл във формат JSON, данни, които да бъдат изпратени на сървъра като низ, път до файла, който да бъде изпратен на полезния товар, флаг за емулация на планировчика на възли, тип на данните, прехвърлени като числова стойност.

  • Получаване на конфигурацията
    st := types.ParseConfig(*config)
  • Ако флагът на emu бъде предаден, той стартира шедулер
  • Ако флагът f, указващ пътя до файла, е предоставен, тогава ние зареждаме неговите данни в FDB и съдържанието се изпраща на сървъра
    client.TCPConnect(st, []byte(CMD_BUFFER_LENGTH + ":" + strconv.Itoa(*t) + "/" + strconv.Itoa(fdblen)), fdb)
  • Ако файлът не е посочен, тогава данните от флага просто се изпращат -d:
    client.TCPConnect(st, []byte(*data), nil)

Всичко това е опростено представяне, показващо структурата на протокола. По време на разработката към структурата му се добавя необходимата функционалност.

Във втората част ще говоря за структури от данни за блокове и транзакции, в 3 за сървъра WebSocket за свързване от JavaScript, във 4 ще разгледам планировчика за синхронизиране, след това стекова машина, която обработва байт код от входове и изходи, криптография и пулове за изходи.

Източник: www.habr.com

Добавяне на нов коментар