
このシリーズの最初の部分を読みましたか? そうでない場合は、見てください。 心配しないで、お待ちください...
ようこそ
最初の投稿「Goでの200行未満のコードでのブロックチェーンの記述」からのフィードバックに驚きました。 初心者のブロックチェーン開発者向けの小さなレッスンで意図されていたことが、新しい生活を始めました。 ネットワークを追加する投稿を行うリクエストが殺到しました。
始める前に、 Telegramチャットに参加できます! これは私たちに質問し、フィードバックを与え、新しいレッスンを求めるのに最適な場所です。 コードに関するヘルプが必要な場合は、これが最適な場所です。
前回の投稿では、新しいブロックをハッシュして検証する独自のブロックチェーンを作成する方法を示しました。 しかし、これはすべて1つのメモで実行されました。 別のノードをメインアプリケーションに接続して新しいブロックを作成し、他のすべてのノードでブロックチェーン全体を更新するにはどうすればよいですか?
作業プロセス

- 最初のターミナルは、最初のベースユニットと、新しいノードが接続できるTCPサーバーを作成します。
ステップ1
- 追加の端末と最初の端末へのTCP接続が開きます
- 新しいターミナルはブロックを最初のターミナルに書き込みます
ステップ2
- 最初の端末はブロックをチェックします
- 最初のターミナルは、新しい各ノードに新しいブロックチェーンを送信します
ステップ3
レッスンの後、自分でやってみてください。それぞれの新しいターミナルは「最初の」ターミナルとしても機能しますが、異なるTCPポートを持ち、それぞれがネットワークの正しい操作のための接続を持っています。
あなたにできること
- 最初のベースユニットを提供するターミナルを起動する
- 必要なだけ新しい追加のターミナルを実行し、最初のターミナルにブロックを書き込みます
- 最初の端末は、新しい端末の更新されたブロックを送信する必要があります
できないこと
前の投稿と同様に、このレッスンの目的は、ノードからコアネットワークを取得することです。これにより、ブロックチェーンを自分でさらに学習できます。 最初の端末に書き込む別のネットワークからコンピューターを追加することはできませんが、これはクラウドでバイナリを実行することで実現できます。 さらに、各ノードのブロックのチェーンがモデル化されます。 心配しないで、すぐにすべてを説明します。
コーディングを始めましょう!
場所は、以前の投稿のレビューになります。 ブロック生成、ハッシュ、チェックなど、多くの機能を残しましょう。 HTTP機能は使用しませんが、コンソールで結果を表示し、TCPを使用してネットワークで作業します。
TCPとHTTPの違いは何ですか?
詳細については説明しませんが、知っておく必要があるのは、TCPがデータを送信する基礎となるプロトコルであるということだけです。 HTTPは、インターネットとブラウザ間のこのデータ転送を使用するために、TCPスタックの上に構築されます。 Webサイトを閲覧するときは、HTTPプロトコルを使用しています。 このレッスンでは、ブラウザで何も表示する必要がないため、TCPを使用します。 Goには、必要なすべてのTCP接続機能を提供する優れたネットワークパッケージがあります。
インストール、インポート、および概要
いくつかの実装は、 最初の部分ですでに検討されています。 ブロックチェーンを生成して検証するには、前の記事の関数を使用します。
設置
メインディレクトリに.env
ファイルを作成し、 .env
の行を追加します。
ADDR=9000
使用するTCPポート番号(この場合は9000)をADDR
と呼ばれる環境変数に保存します。
まだ行っていない場合は、次のパッケージをインストールします。
go get github.com/davecgh/go-spew/spew
コンソールにブロックチェーンの美しいプリントを
go get github.com/joho/godotenv
.env
ファイルから変数を読み取ります。
空のmain.go
ファイルを作成します。 コードをそこに配置します。
輸入品
必要なパッケージ宣言とインポート:
package main import ( "bufio" "crypto/sha256" "encoding/hex" "encoding/json" "io" "log" "net" "os" "strconv" "time" "github.com/davecgh/go-spew/spew" "github.com/joho/godotenv" )
復習
次のコードフラグメントは、 最初の部分で詳しく説明されています。
Block
構造を作成してブロックスライスを宣言しましょう。これがブロックチェーンになります。
type Block struct { Index int Timestamp string BPM int Hash string PrevHash string } var Blockchain []Block
また、新しいブロックを作成するときに必要になるハッシュ関数も宣言します。
func calculateHash(block Block) string { record := string(block.Index) + block.Timestamp + string(block.BPM) + block.PrevHash h := sha256.New() h.Write([]byte(record)) hashed := h.Sum(nil) return hex.EncodeToString(hashed) }
ブロックを作成する機能:
func generateBlock(oldBlock Block, BPM int) (Block, error) { var newBlock Block t := time.Now() newBlock.Index = oldBlock.Index + 1 newBlock.Timestamp = t.String() newBlock.BPM = BPM newBlock.PrevHash = oldBlock.Hash newBlock.Hash = calculateHash(newBlock) return newBlock, nil }
新しいブロックが正しいことを確認できます。このため、 PrevHash
フィールドが前のブロックのHash
フィールドを参照していることを確認します。
func isBlockValid(newBlock, oldBlock Block) bool { if oldBlock.Index+1 != newBlock.Index { return false } if oldBlock.Hash != newBlock.PrevHash { return false } if calculateHash(newBlock) != newBlock.Hash { return false } return true }
これで、最も長いチェーンを正しいチェーンとすることが保証されます。
func replaceChain(newBlocks []Block) { if len(newBlocks) > len(Blockchain) { Blockchain = newBlocks } }
いいね! ブロックのチェーンを操作するための基本的な機能を取得しました。 これで、ネットワーク接続の作成に進むことができます。
ネットワーク接続
新しいブロックを転送し、チェーンに統合し、ネットワークの新しいチェーンをブロードキャストできるネットワークを作成しましょう。
main関数から始めましょうが、その前に、グローバル変数bcServer
宣言しましょう。これは、着信ブロックを受け入れるチャネルです。
var bcServer chan []Block
注:チャネルはGoで最も人気のあるツールの1つであり、美しい読み取り/書き込みデータ実装を提供し、競合状態を防ぐために最もよく使用されます。 複数のGo-routineが同じチャネルで有能に(並列処理と混同しないように)記述している場合、それらは強力なツールになります。 通常、Javaおよびその他のCライクな言語では、データにアクセスするにはミューテックスをロックおよびロック解除する必要があります。 Goにはチャネルもありますが、Goにはミューテックスがあります。 詳細については、 こちらをご覧ください 。
ここで、メイン関数を宣言し、ルートディレクトリにある.env
ファイルから環境変数をロードしましょう。 また、main関数でbcServer
インスタンスを実行します。
func main() { err := godotenv.Load() if err != nil { log.Fatal(err) } bcServer = make(chan []Block)
次に、TCPサーバーを作成する必要があります。 TCPサーバーはHTTPサーバーに似ていますが、ブラウザーで動作するにはTCPプロトコルだけでは不十分です。 すべてのデータはコンソールを介して表示されます。 TCPポートへのいくつかの接続を処理します。 これをメイン関数に追加します。
server, err := net.Listen("tcp", ":"+os.Getenv("ADDR")) if err != nil { log.Fatal(err) } defer server.Close()
このコードは、ポート9000でTCPサーバーを起動します。接続が不要になったときに接続が閉じるように、 defer server.Close()
を実行defer server.Close()
ことが重要です。 遅延の詳細については、 こちらをご覧ください 。
ここで、接続を確立する要求を受け取るたびに新しい接続を作成する必要があり、それを処理する必要があります。 別のコードを追加します。
for { conn, err := server.Accept() if err != nil { log.Fatal(err) } go handleConn(conn) }
新しい接続を受け入れる無限ループを作成します。 競争力のある処理のために、Goのルーチンgo handleConn(conn)
のハンドラーで各接続を開始するため、ループを停止しません。 したがって、複数の接続を競争的に同時に聞くことができます。
注意深い読者は、 handleConn
ハンドラーhandleConn
宣言されていないことに気付くでしょう。 これまでにメイン関数main
作成しました。 完全に次のようになります。
func main() { err := godotenv.Load() if err != nil { log.Fatal(err) } bcServer = make(chan []Block) // create genesis block t := time.Now() genesisBlock := Block{0, t.String(), 0, "", ""} spew.Dump(genesisBlock) Blockchain = append(Blockchain, genesisBlock) // start TCP and serve TCP server server, err := net.Listen("tcp", ":"+os.Getenv("ADDR")) if err != nil { log.Fatal(err) } defer server.Close() for { conn, err := server.Accept() if err != nil { log.Fatal(err) } go handleConn(conn) } }
ここで、 handleConn
関数を作成しましょう。 引数は1つだけで、これはnet.Conn
インターフェイスです。 私たちの意見では、Goのインターフェイスは印象的であり、すべてのCライクな言語と区別されます。 競争力とGoルーチンは言語を宣伝しますが、インターフェイスと、インターフェイスを明示的に実装できないという事実が最も強力な言語機能です。 Goでインターフェースをまだ使用していない場合は、できるだけ早くそれらを確認してください。 インターフェイスは、Go開発者になるための次のステップです。
ハンドラ関数defer
に遅延接続遅延クロージャを配置して、完了時に閉じることを忘れないようにします。
func handleConn(conn net.Conn) { defer conn.Close() }
次に、クライアントが新しいブロックをチェーンに追加できるようにする必要があります。 データには、 最初の部分と同様に、心拍数を使用します。 心拍数を1分間測定し、この数値を覚えておいてください。 これはBPMパラメーター(ビート/分)になります
上記を実装するには、次のものが必要です。
- クライアントにBPMの入力を求める
stdin
介してクライアントにこの値を要求する- generateBlock、isBlockValid、およびreplaceChain関数を使用して、このデータで新しいブロックを作成します
- ネットワーク経由で送信するために以前に作成したチャネルに新しいブロックのチェーンを配置します
- クライアントが新しいBMP値を入力できるようにします
上記の機能を実装するコード:
io.WriteString(conn, "Enter a new BPM:") scanner := bufio.NewScanner(conn) go func() { for scanner.Scan() { bpm, err := strconv.Atoi(scanner.Text()) if err != nil { log.Printf("%v not a number: %v", scanner.Text(), err) continue } newBlock, err := generateBlock(Blockchain[len(Blockchain)-1], bpm) if err != nil { log.Println(err) continue } if isBlockValid(newBlock, Blockchain[len(Blockchain)-1]) { newBlockchain := append(Blockchain, newBlock) replaceChain(newBlockchain) } bcServer <- Blockchain io.WriteString(conn, "\nEnter a new BPM:") } }()
新しいスキャナーを作成します。 for scanner.Scan()
は、Goルーチンで他の接続とは別に競合的に機能するループです。 BMP値の文字列をすばやく変換します(常にinteger
型になるので、チェックしてください)。 標準のブロック生成を実行し、ブロックの有効性を確認し、新しいブロックをチェーンに追加します。
構文bcServer <- Blockchain
は、以前に作成したチャネルに新しいチェーンをドロップすることを意味します。 次に、クライアントが新しいBPM値を入力して次のブロックを作成することをお勧めします。
放送チャンネル
TCPサーバー上のすべての接続に対して、新しいブロックチェーンを送信する必要があります。 1台のコンピューターでプログラムを作成するため、データがすべてのクライアントに送信される方法をシミュレートする必要があります。 handleConn
関数handleConn
はhandleConn
を追加する必要があります。
- ブロックチェーンをJSON形式に変換して読みやすくしました
- 接続ごとに新しいブロックチェーンをコンソールに書き込む
- ブロックチェーンが常にスパムを送信しないように、周期性のタイムアウトを設定します。 既存のシステムでは、これはX分ごとに発生します。 30秒を使用します
- 何が起こっているかを見ることができるように、最初のターミナルでブロックのメインチェーンを出力します。 したがって、さまざまなノードによって追加されたブロックが、ブロックのメインチェーンに実際に統合されていることを確認します。
すべてを正しい順序で実行するコードを次に示します。
go func() { for { time.Sleep(30 * time.Second) output, err := json.Marshal(Blockchain) if err != nil { log.Fatal(err) } io.WriteString(conn, string(output)) } }() for _ = range bcServer { spew.Dump(Blockchain) }
いいね! handleConn
関数の準備handleConn
できました。 実際、プログラム全体の準備が整っており、200行のコードでコンパクトに保ちました。 それは悪くないですか?
コード全体はこちらから入手できます !
面白いもの
コードを使用してディレクトリに移動し、実行してプログラムを実行しましょうgo run main.go

予想どおり、ベースユニットが表示されます。 同時に、ポート9000でTCPサーバーを起動し、複数の接続を受け入れることができます。
新しいターミナルウィンドウを開き、 nc localhost 9000
を使用してTCPサーバーに接続します。 端末で異なる色を使用するため、これらが異なるクライアントであることは明らかです。 複数のクライアントを起動するには、異なるターミナルセッションでこれを数回行います。



次に、いずれかのクライアントでBPMを入力します。 新しいブロックが最初のターミナルに追加されたことがわかります! ネットワークは機能しています!


30秒待っています。 他のクライアントのいずれかに移動すると、これらのクライアントがBPMに入らなかった場合でも、新しいブロックチェーンがすべてのクライアントに渡されたことがわかります。

次のステップ
おめでとうございます! 前回のレッスンから独自のブロックチェーンを作成しただけでなく、ネットワークも追加しました。 次に進むにはいくつかの方向があります。
- ローカルで機能する大規模なネットワークを取得するには、アプリケーションのコピーを保存するいくつかのディレクトリを作成します。 各コピーには異なるTCPポートが必要です。 端末セッションごとに、TCPポートをリッスンし、別のポートに接続して、データを送受信できるようにします。
- 複数のポートから受信したデータを結合します。 これは別のレッスンのトピックですが、簡単に実行できます。 これはすべてブロックチェーンです。 データを送信するだけでなく、データを受信する必要があります。
- 友達と試して、お気に入りのホスティングプロバイダーを使用してクラウドにサーバーをセットアップできます。 友達に接続してデータを送信してもらいます。 この段階で、少しセキュリティを追加できます。 リクエストがある場合は、この資料に関するチュートリアルを作成します。
あなたはすでにブロックチェーンの多くの側面を理解しています。 Proof of WorkやProof of Stakeなどのアルゴリズムを読むことをお勧めします。
または、新しいブログ投稿を書くまでお待ちください:-)
あなたが見たいものを伝えるために、私たちの電報チャットに参加することを思い出してください! おそらく、今後のレッスンで何を書くかについて考えを変えることができます。 Twitterでもフォローできます。
Coral Healthの詳細と医学研究でブロックチェーンを使用する方法については、当社のWebサイトをご覧ください。
PS翻訳の作者は、翻訳の指摘された誤りと不正確さに感謝します。