Развој на блокчејн за индустријата што користи Go. Дел 1

Веќе четири месеци работам на проект наречен „Развој на алатки за заштита на податоци и управување во владините и индустриските сектори базирани на блокчејн“.
Сега би сакал да ви кажам како го започнав овој проект, а сега детално ќе го опишам програмскиот код.

Развој на блокчејн за индустријата што користи Go. Дел 1

Ова е прва статија од серијата статии. Овде ги опишувам серверот и протоколот. Всушност, читателот може дури и да напише свои верзии на овие блокчејн елементи.

И еве го вториот дел — за блокчејн и структури на податоци за трансакции, како и за пакетот што спроведува интеракција со базата на податоци.

Минатата година, на хакатонот Дигитален пробив, тие дојдоа до идеја да направат корисен систем за индустријата и дигиталната економија користејќи дистрибуирана технологија; статија за грантот, за оние кои штотуку почнуваат да прават стартапи ), и сега во ред.

Развојот се одвива во јазикот Go, а базата на податоци во која се чуваат блоковите е LevelDB.
Главните делови се протоколот, серверот (кој работи TCP и WebSocket - првиот за синхронизирање на блокчејнот, вториот за поврзување клиенти, испраќање трансакции и команди од JavaScript, на пример.

Како што беше споменато, овој блокчејн е потребен првенствено за автоматизирање и заштита на размената на производи помеѓу добавувачите и клиентите, или и двете во едно лице. Овие луѓе не брзаат да си веруваат еден на друг. Но, задачата не е само да се создаде „чековна книшка“ со вграден калкулатор, туку систем што ги автоматизира повеќето рутински задачи што се јавуваат при работа со животниот циклус на производот. Бајтекодот кој е одговорен за ова прашање, како што е вообичаено кај блокчејновите, се чува во влезовите и излезите на трансакциите (самите трансакции се складираат во блокови, блоковите во LevelDB се претходно кодирани во формат GOB). Прво, ајде да зборуваме за протоколот и серверот (ака јазол).

Протоколот не е комплициран, целата негова поента е да се префрли на режимот на вчитување на некои податоци, обично блок или трансакција, како одговор на посебна командна линија, а исто така е потребен и за размена на залихи, така што јазолот знае кој е е поврзан со и како имаат работа (јазлите поврзани за сесијата за синхронизација се нарекуваат и „соседни“ бидејќи нивната IP е позната и податоците за нивната состојба се зачувани во меморијата).

Папките (директориумите како што ги нарекува Linux) во разбирањето на Go програмерите се нарекуваат пакети, така што на почетокот на секоја датотека со Go код од овој директориум пишуваат пакет folder_name_where_this_file is located. Во спротивно, нема да можете да го нахраните пакетот до компајлерот. Па, ова не е тајна за оние кои го знаат овој јазик. Ова се пакетите:

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

Еве ја врската до github

Ова е образовна верзија, нема интерпроцесна интеракција и неколку експериментални компоненти, но структурата одговара на онаа на која се изведува развојот. Ако имате нешто да предложите во коментарите, со задоволство ќе го земам предвид во понатамошниот развој. И сега за објаснување на серверот и протокол.

Ајде прво да го погледнеме серверот.

Подпрограмата на серверот делува како податочен сервер кој работи на врвот на протоколот TCP користејќи структури на податоци од протоколскиот пакет.

Рутината ги користи следниве пакети: сервер, протокол, видови. Во самото пакување tcp_server.go содржи структура на податоци Служи.

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

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

  • Мрежна порта преку која ќе се разменуваат податоците
  • Датотека за конфигурација на серверот во JSON формат
  • Ознака за работа во режим за отстранување грешки (приватен блокчејн)

Напредок:

  • Ја чита конфигурацијата од JSON-датотеката
  • Знамето на режимот за отстранување грешки е проверено: ако е поставено, распоредувачот за синхронизација на мрежата не е стартуван и блокчејнот не е вчитан
  • Иницијализирање на конфигурациската структура на податоци и стартување на серверот

сервер

  • Врши стартување на TCP серверот и мрежната интеракција во согласност со протоколот.
  • Има структура на податоци Serve која се состои од број на порта, големина на баферот и покажувач кон структурата типови.Поставки
  • Методот Run започнува мрежна интеракција (слушање за дојдовни врски на дадена порта, кога ќе се прими нова врска, нејзината обработка се пренесува на методот на приватна рачка во нова нишка)
  • В се справи со податоците од врската се читаат во бафер, се претвораат во претстава на низа и се пренесуваат до протокол.Избор
  • протокол.Избор се враќа резултира или предизвикува грешка. резултира потоа префрлени на протокол.Толкувааткој се враќа intrpr - објект од типот InterpreteData, или предизвикува грешка при обработката на резултатот од изборот
  • Потоа прекинувачот се извршува intrpr.Команди[0] кој проверува едно од: резултат, инв, грешка и има дел стандардно
  • Во делот резултира прекинувачот се наоѓа по вредност intrpr.Команди[1] кој ги проверува вредностите тампон должина и верзија (во секој случај се повикува соодветната функција)

Функции GetVersion и Должина на тампон се во досието 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
  • Создава бафер новобуф одредена големина:
    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"))

Методите од серверскиот пакет се конфигурирани да обработуваат примени податоци користејќи функции од пакетот протокол.

Протокол

Протоколот служи како средство кое ги претставува податоците во мрежната размена.

Избор (string str) (низа, грешка) врши примарна обработка на податоците добиени од серверот, прима низа претставување на податоците како влез и враќа низа подготвена за Толкувач:

  • Влезната низа се дели на глава и тело користејќи ReqParseN2(ул)
  • главата се дели на елементи и се става во парче команди користејќи ReqParseHead(глава)
  • В прекинувач (наредби[0]) изберете ја добиената команда (cmd, клуч, адреса или се активира делот стандардно)
  • Во cmd се проверуваат 2 команди прекинувач (наредби[1]) - должина и верзија.
  • должина го проверува типот на податоци команди[2] и го зачувува во тип на податоци
  • Го проверува тоа тело содржи стринг вредност
    len(body) < 1
  • Ја враќа низата за одговор:
    "result:bufferlength:" + datatype + "/" + body
  • верзија враќа низа
    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(ул)
  • главата е поделена на елементи користејќи 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)
  • Ако се помине знамето на ему, тоа започнува распоредувач
  • Ако е доставено знаменцето 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

Додадете коментар