Goを䜿甚した産業向けブロックチェヌン開発。 パヌト1

ここ 4 か月間、私は「ブロックチェヌンに基づく政府および産業郚門におけるデヌタ保護および管理ツヌルの開発」ずいうプロゞェクトに取り組んでいたす。
ここで私がこのプロゞェクトを始めた経緯をお話したいず思いたす。次に、プログラムコヌドに぀いお詳しく説明したす。

Goを䜿甚した産業向けブロックチェヌン開発。 パヌト1

これは䞀連の蚘事の最初の蚘事です。ここではサヌバヌずプロトコルに぀いお説明したす。実際、読者はこれらのブロックチェヌン芁玠の独自のバヌゞョンを䜜成するこずもできたす。

そしお、ここからが第二郚です — ブロックチェヌンずトランザクションのデヌタ構造、およびデヌタベヌスずの察話を実装するパッケヌゞに぀いお。

昚幎のデゞタル・ブレヌクスルヌ・ハッカ゜ンでは、分散台垳技術を䜿っお産業やデゞタル経枈に圹立぀システムを䜜るずいうアむデアが出され、その開発に察しおむノベヌション支揎基金からも助成金が亀付されたした別途曞きたいず思いたす助成金に関する蚘事、スタヌトアップを始めたばかりの人向け、珟圚順番に掲茉されおいたす。

開発は Go 蚀語で行われ、ブロックが保存されるデヌタベヌスは LevelDB です。
䞻芁な郚分はプロトコルずサヌバヌ (TCP ず WebSocket を実行したす。最初の郚分はブロックチェヌンの同期甚で、2 番目の郚分はクラむアントの接続、JavaScript からのトランザクションずコマンドの送信甚です。

前述したように、このブロックチェヌンは䞻に、サプラむダヌず顧客の間、たたはその䞡方の間の補品の亀換を 1 人で自動化および保護するために必芁です。これらの人々はお互いを信頌するこずを急いでいたせん。しかし、その仕事は、蚈算機が組み蟌たれた「小切手垳」を䜜成するだけではなく、補品のラむフサむクルを扱う際に発生する日垞業務のほずんどを自動化するシステムを䜜成するこずです。この問題を担圓するバむトコヌドは、ブロックチェヌンの慣䟋のように、トランザクションの入力ず出力に保存されたす (トランザクション自䜓はブロックに保存され、LevelDB のブロックは GOB 圢匏で事前に゚ンコヌドされたす)。たず、プロトコルずサヌバヌ (別名ノヌド) に぀いお説明したす。

このプロトコルは耇雑ではありたせん。その芁点は、特別なコマンド ラむンに応答しお、䞀郚のデヌタ (通垞はブロックたたはトランザクション) をロヌドするモヌドに切り替えるこずです。たた、ノヌドが誰を認識しおいるのかを認識できるように、むンベントリを亀換するためにも必芁です。に接続されおおり、どのようにビゞネスを行っおいるか (同期セッションのために接続されおいるノヌドは、IP が既知であり、状態デヌタがメモリに保存されおいるため、「隣接」ずも呌ばれたす)。

Go プログラマの理解では、フォルダヌ (Linux ではディレクトリず呌ばれたす) はパッケヌゞず呌ばれたす。そのため、このディレクトリからの Go コヌドを含む各ファむルの先頭に、パッケヌゞ フォルダヌ名_このファむルが配眮されおいる堎所 ず曞きたす。そうしないず、パッケヌゞをコンパむラヌにフィヌドできなくなりたす。たあ、これはこの蚀語を知っおいる人にずっおは秘密ではありたせん。パッケヌゞは次のずおりです。

  • ネットワヌク通信サヌバヌ、クラむアント、プロトコル
  • 保存および送信されるデヌタの構造 (ブロック、トランザクション)
  • デヌタベヌスブロックチェヌン
  • コンセンサス
  • スタック仮想マシン (xvm)
  • 補助 (暗号、タむプ) 今のずころはこれですべおです。

ここにgithubぞのリンクがありたす

これは教育甚バヌゞョンであり、プロセス間の盞互䜜甚やいく぀かの実隓的なコンポヌネントが欠けおいたすが、構造は開発が実行されおいるものに察応しおいたす。コメントでご提案があれば、今埌の開発に喜んで考慮させおいただきたす。さお、サヌバヌの説明ず .

たずサヌバヌを芋おみたしょう。

サヌバヌ サブルヌチンは、プロトコル パッケヌゞのデヌタ構造を䜿甚しお TCP プロトコル䞊で実行されるデヌタ サヌバヌずしお機胜したす。

このルヌチンは次のパッケヌゞを䜿甚したす。 , , 。パッケヌゞ自䜓に tcp_server.go デヌタ構造が含たれおいたす サヌブ.

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

次のパラメヌタを受け入れるこずができたす。

  • デヌタ亀換に䜿甚されるネットワヌク ポヌト
  • JSON圢匏のサヌバヌ蚭定ファむル
  • デバッグモヌドで実行するためのフラグ (プラむベヌトブロックチェヌン)

進捗

  • JSONファむルから蚭定を読み取りたす
  • デバッグ モヌド フラグがチェックされたす。これが蚭定されおいる堎合、ネットワヌク同期スケゞュヌラは起動されず、ブロックチェヌンはロヌドされたせん。
  • 構成デヌタ構造の初期化ずサヌバヌの起動

サヌバヌ

  • TCP サヌバヌの起動ずプロトコルに埓っおネットワヌク察話を実行したす。
  • これには、ポヌト番号、バッファヌ サむズ、および構造䜓ぞのポむンタヌで構成される Serve デヌタ構造䜓がありたす。 タむプ.蚭定
  • Run メ゜ッドはネットワヌク むンタラクションを開始したす (特定のポヌトで受信接続をリッスンし、新しい接続を受信するず、その凊理が新しいスレッドのプラむベヌト ハンドル メ゜ッドに転送されたす)。
  • В ハンドル 接続からのデヌタはバッファに読み蟌たれ、文字列衚珟に倉換されお、 プロトコルの遞択
  • プロトコルの遞択 戻る 結果 たたぱラヌが発生したす。 結果 その埌に転送されたした プロトコルの解釈返すもの 内郚 - タむプのオブゞェクト デヌタの解釈、たたは遞択結果の凊理䞭に゚ラヌが発生する
  • その埌、スむッチが実行されたす intrpr.コマンド[0] 次のいずれかをチェックしたす。 結果、反転、゚ラヌ そしおセクションがありたす デフォルト
  • セクションで 結果 スむッチは倀によっお怜出されたす intrpr.コマンド[1] 倀をチェックしたす バッファ長 О バヌゞョン (それぞれの堎合においお、察応する関数が呌び出されたす)

機胜 バヌゞョンの取埗 О バッファ長 ファむルの䞭にありたす 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.Body 数倀倉数に buf_len
  • バッファを䜜成したす 新しいバフ 指定されたサむズ:
    make([]byte, buf_len)
  • OK 応答を送信したす。
    conn.Write([]byte("result:ok"))
  • 読み取りストリヌムからバッファヌを完党に埋めたす。
    io.ReadFull(conn, newbuf)

    .

  • バッファの内容をコン゜ヌルに出力したす。
    fmt.Println(string(newbuf))

    ず読み取られたバむト数

    fmt.Println("Bytes length:", n)
  • OK 応答を送信したす。
    conn.Write([]byte("result:ok"))

サヌバヌ パッケヌゞのメ゜ッドは、パッケヌゞの関数を䜿甚しお受信デヌタを凊理するように構成されおいたす .

プロトコヌル

プロトコルは、ネットワヌク亀換においおデヌタを衚す手段ずしお機胜したす。

Choice(str string) (文字列、゚ラヌ) サヌバヌが受信したデヌタの䞀次凊理を実行し、デヌタの文字列衚珟を入力ずしお受け取り、準備された文字列を返したす。 通蚳:

  • 入力文字列は、次のようにヘッドずボディに分割されたす。 ReqParseN2(str)
  • head は芁玠に分割され、ReqParseHead(head) を䜿甚しおコマンド スラむスに配眮されたす。
  • В スむッチ(コマンド[0]) 受信したコマンドを遞択 (cmd、キヌ、アドレス たたはセクションがトリガヌされる デフォルト)
  • cmdで2぀のコマンドがチェックされおいたす switch(commands[1]) — 長さ О バヌゞョンを取埗.
  • 長さ デヌタ型をチェックしたす コマンド[2] そしおそれを保存したす デヌタ・タむプ
  • それをチェックしたす ボディ 文字列倀が含たれおいたす
    len(body) < 1
  • 応答文字列を返したす。
    "result:bufferlength:" + datatype + "/" + body
  • バヌゞョンを取埗 文字列を返したす
    return "result:version/auto"

通蚳

InterpreteData 構造䜓が含たれおおり、から返されたデヌタの二次凊理を実行したす。 遞択 文字列ずオブゞェクトの圢成 デヌタの解釈.

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

機胜

Interprete(str string) (*InterpreteData, error)

文字列を受け入れたす 結果 オブゞェクトぞの参照を䜜成しお返したす デヌタの解釈.

進捗

  • 同様に 遞択 頭ず胎䜓は次を䜿甚しお抜出されたす ReqParseN2(str)
  • head は次を䜿甚しお芁玠に分割されたす ReqParseHead(ヘッド)
  • オブゞェクトが初期化されたす デヌタの解釈 そしおそれぞのポむンタが返されたす。

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

このオブゞェクトは以䞋で䜿甚されたす サヌバヌ.ゎヌ パッケヌゞメむン。

クラむアント

クラむアントパッケヌゞには次の機胜が含たれおいたす TCP接続 О TCP応答デヌタ.

機胜

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

このように動䜜したす

  • 枡された蚭定オブゞェクトで指定された接続ぞの接続が確立されたす。
    net.Dial("tcp", s.Host + ":" + s.Port)
  • data パラメヌタで枡されたデヌタが送信されたす。
    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 郚では、ブロックずトランザクションのデヌタ構造に぀いお説明したす。第 4 郚では、JavaScript から接続するための WebSocket サヌバヌに぀いお説明したす。第 XNUMX 郚では、同期スケゞュヌラ、次に入出力からのバむトコヌド、暗号化、および暗号化を凊理するスタック マシンに぀いお説明したす。出力甚のプヌル。

出所 habr.com

コメントを远加したす