注意端口配置寫在.env裏面。node
源碼:https://github.com/mycoralhealth/blockchain-tutorial/tree/master/networkingios
Part 2: Networking — Code your own blockchain in less than 200 lines of Go!
Have you checked out Part 1 of this series yet? If not, go take a look. Don’t worry, we’ll wait…git
Welcome back!github
We were stunned at the reception we received in our first 「Code your own blockchain in less than 200 lines of Go!」 post. What was meant to be a little tutorial for beginning blockchain developers has taken on a life of its own. We’ve been bombarded with requests to do an add-on post where we integrate networking.golang
Before we get started, make sure to join our Telegram chat! This is the best place to ask us questions, give feedback and request new tutorials. If you need some help with your code, this is the perfect place to ask!web
The last post showed you how to code up your own blockchain, complete with hashing and validation of each new block. But it all ran in a single terminal (node). How do we get another node to connect to our main instance and have them contribute new blocks, and how do we broadcast the updated blockchain to all the other nodes?算法
We’ll show you here.編程
Workflow
- The first terminal creates a genesis block and a TCP server to which new nodes can connect
Step 1json
- Additional terminals are opened and TCP connections are made to the first terminal
- New terminals write a block to the first terminal
Step 2數組
- The first terminal validates the block
- The first terminal broadcasts the new blockchain to each of the new nodes
Step 3
- All terminals now have synced blockchains!
After the tutorial, try this yourself: have each of the new terminals also act as 「First」 terminals with different TCP ports and have the other terminals connect to it for a true network!
What you will be able to do
- Run a terminal that provides a genesis block
- Fire up as many additional terminals as you like and have them write blocks to the first terminal
- Have the first terminal broadcast updated blocks to the new terminals
What you won’t be able to do
Like the last post, the aim of this tutorial is to get a basic network of nodes working so you can decide on where your blockchain journey goes from here. You won’t be able to have computers in other networks writing to your first terminal, but this can be readily achieved by putting your binary in the cloud. Also, blockchain broadcasting will be simulated to each of the nodes. Don’t worry, we’ll explain all of this shortly.
Let’s get coding!
Some of this will be a review of the last post. We’ll be using many of the same block generation, hashing and validation functions. But we won’t be using any of the HTTP functionality since we’ll be viewing results in the console and we’ll be using TCP for networking.
What’s the difference between TCP and HTTP?
We won’t get into much detail here but all you need to know is that TCP is a base protocol that transmits data. HTTP is built on top of TCP to utilize this data transmission on the web and in browsers. When you view a website, you’re using HTTP, which is supported by an underlying data transmission protocol, called TCP.
For this tutorial, we’ll be working with TCP as we won’t be needing to view anything in a browser. Go has a nice net
package that provides all the TCP connection functions we need.
Setup, Imports and Review
Some of this will be a review from Part 1. For blockchain generation and validation, we’ll be using the same functions from the last post. Bear with us while we do a quick review. Don’t worry, we’ll get to the new stuff soon!
Setup
Create a .env
file in your root directory and add the following line:
ADDR=9000
We store the TCP port number we want to use (in this case 9000) in an environment variable called ADDR
.
If you haven’t done it already, grab the following packages:
go get github.com/davecgh/go-spew/spew
to pretty print our blockchain to the console
go get github.com/joho/godotenv
to load the variables in our .env
file
Create an empty main.go
file. We’ll be putting all our code here.
Imports
Let’s do our standard package declaration and write up the imports we’ll need.
Review
The following code snippets are explained in much greater detail in Part 1. Refer to it if you need a refresher. We’ll be moving fast through this.
Let’s create our Block
struct and declare our Blockchain
as a slice ofBlock
Now create our hashing function that we need when generating new blocks.
Our block generation function:
Make sure our new block is valid by checking its PrevHash
against the Hash
of the previous block.
Now we ensure we take the longest chain as the true blockchain:
Nice! We’ve basically got all the blockchain related functions we need with all the HTTP related stuff from Part 1 stripped out. We can now proceed to networking.
Networking
Finally! We’re at the good stuff. Let’s set up a network that can pass around new blocks, integrate them into our blockchain, and broadcast new blockchains back to the network.
Let’s start with our main function, as that is a nice abstraction that will help us understand the overall flow.
Right before we do that, let’s declare a global variable called bcServer
(short for blockchain server) under our other struct declarations that is a channel that takes in incoming blocks.
Side note: Channels are one of the most popular features of Go and allow for elegant streamlining of data reading/writing and are most often used to prevent data races. They become particularly powerful when used concurrently, as multiple Go routines can write to the same channel. Traditionally in Java and other C-like language, you’d have to open and close the 「gates」 for incoming data through mutexes. Channels in Go make this much easier, although there are still places for mutexes in Go. Learn more about channels here.
Now let’s declare our main
function and load up the environment variable from our .env
file that sits in our root directory. Remember, the only environment variable is ADDR
which is our TCP port number 9000 which we’ll use in a second. Also, let’s instantiate our bcServer
in the main
function.
Now we need to write up our TCP server. Remember, you can think of TCP servers as being similar to HTTP servers but there is no browser component. All data transmission will be done in the console through our terminal. We will be handling multiple connections to our TCP port. Add this to your main
function below the last line.
This fires up our TCP server at port 9000. It’s important to defer server.Close()
so the connection closes cleanly when we no longer need it. Learn more about defer
here.
Now we need to create a new connection each time we receive a connection request, and we need to serve it. Add this below the last line.
We just made an infinite loop where we accept new connections. We want to concurrently deal with each connection through a separate handler in a Go routine go handleConn(conn)
, so we don’t clog up our for
loop. This is how we can serve multiple connections concurrently.
The perceptive reader will jump up and say, 「hey wait! We don’t have ahandleConn
function!」. You’re right. But let’s take a quick breather. Nice job, we just wrote up our entire main function. It looks like this:
Let’s write up that handleConn
function now. It only takes in one argument, a nicely packaged net.Conn
interface. Interfaces in Go are amazing and in our opinion, what separates Go from every other C-based language. Concurrency and Go routines get all the hype but interfaces and the fact that they’re satisfied implicitly are the language’s most powerful feature. If you don’t use interfaces in Go yet, get familiar with them as quickly as you can. Interfaces are your next step in your journey to becoming a 10x Go developer!
Put in the skeleton of the function and start it off with a clean defer
statement to close each connection when we’re done with it.
Now we need to allow the client to add new blocks for us to integrate into the blockchain. We’re going to use the same pulse rate from Part 1. Take your own pulse over a minute and keep that number in your head. That will be our BPM (beats per minute).
To achieve the above we need to:
- prompt the client to enter their BPM
- scan the client’s input from
stdin
- create a new block with this data, using the
generateBlock
,isBlockValid
, and replaceChain
functions we created previously
- put the new blockchain in the channel we created to be broadcast to the network
- allow the client to enter a new BPM
Here is the code to do that, in the exact order described above.
We create a new scanner. Thefor scanner.Scan()
loop is tucked away in its own Go routine so it can run concurrently and separately from other connections. We do a quick string conversion of our BPM (which will always be an integer, so we check for that). We do our standard block generation and validation checks and create a new blockchain with the new block.
The syntax bcServer <- Blockchain
just means we’re throwing our new blockchain into the channel we created. Then we prompt the client to enter a new BPM to create the next block.
Broadcasting
We need to broadcast the new blockchain to all the connections being served by our TCP server. Since we’re coding this up on one computer, we’ll be simulating how data gets transmitted to all clients. Under the last line of code, in the same handleConn
function, we need to
- Marshall our new blockchain into JSON so we can read it nicely
- write the new blockchain to the consoles of each of our connections
- set a timer to do this periodically so we’re not getting inundated with blockchain data. This is also what you see in live blockchain networks, where new blockchains are broadcast every X minutes. We’ll use 30 seconds
- Pretty print the main blockchain to the first terminal, just so we can see what’s going on and ensure blocks being added by different nodes are indeed being integrated into the main blockchain
Here is the code, in this exact order.
Nice! Our handleConn
function is done. In fact, the whole program is done and we’ve kept it to under 200 lines. That wasn’t bad at all was it?
Check out the completed code here!
The Fun Stuff
Let’s try this baby out! Let’s fire up our application by going to our directory and go run main.go
As expected, we see our genesis block. What’s happening at the same time is that we’ve started a TCP server at port 9000 that can take in multiple connections. So let’s do that.
Open a new terminal window and connect to our TCP server with nc localhost 9000
. We’ll be using different color terminals to make it clear these are different clients. Do this a couple times with a couple terminal sessions to activate multiple clients.
Now type in a BPM to any of the clients. And KAPOW! We see the new block added to the first terminal! Networking in action!
Here’s where it gets REALLY cool. Wait 30 seconds. Go to one of the other clients and you’ll see the new blockchain broadcast to all the clients, even if those clients never inputted a BPM!
Congratulations! Not only did you create your own blockchain from the last tutorial, you’ve now added networking ability to it. There are several places you can go from here:
- To have a bigger network running on your local environment, create multiple directories that hold a copy of the application each with different TCP ports. For each terminal session, serve a TCP port and connect to a different one so you can receive and send data.
- Connect data being streamed from multiple ports. This is a topic for another tutorial but is done readily.
This is all a blockchain network is. It needs to take in incoming data and also broadcast data externally. Doing both in a single terminal session is effectively what a mining setup is.
- If you want to try this with you friends, set up the server in the cloud using your favorite hosting provider. Have your friends connect to it and send in data. There are some additional security considerations here. If there is demand we’ll write up a tutorial for this too.
You are well on your way to intimately understanding multiple facets of the blockchain. From here, we’d recommend reading up on consensus algorithms like Proof of Work or Proof of Stake.
Or…you can just wait for us to write a new blog post about it :-)
Again, the best place to tell us what you want to see is to join our Telegramchat! Don’t miss out on some cool sneak peeks on the tutorials we’re going to be releasing next. Maybe if you get to us early enough we’ll change our minds and write a tutorial on what you want to see. Make sure to follow us on Twitter too!
We released a follow-up on how to store data through the blockchain using IPFS. Take a look here!
To learn more about Coral Health and how we’re using the blockchain to advance personalized medicine research, visit our website.
Until next time!
原創 2018-02-09 Coral Health 高可用架構
在第一篇文章[1]中,咱們向你們展現瞭如何經過精煉的Go代碼實現一個簡單的區塊鏈。如何計算每一個塊的 Hash 值,如何驗證塊數據,如何讓塊連接起來等等,可是全部這些都是跑在一個節點上的。文章發佈後,讀者反響熱烈,紛紛留言讓我快點填坑(網絡部分),因而就誕生了這第二篇文章。
https://mp.weixin.qq.com/s?__biz=MzAwMDU1MTE1OQ==&mid=2653549384&idx=1&sn=fce9e6fa059c044a6abfcf2cc3241ba5&chksm=813a62d0b64debc657e09718d6c851ee1cc7c37d3cb5b0a4213732a331dcd4bd5aae38a5fdf4&scene=21#wechat_redirect
這篇文章在以前的基礎上,解決多個節點網絡內,如何生成塊、如何通訊、如何廣播消息等。
流程

Step 1
Step 2
-
第一個節點驗證新生成塊
-
驗證以後廣播(鏈的新狀態)給其餘節點
Step 3
以後你能夠重複上面的步驟,使得每一個節點都建立TCP server並監聽(不一樣的)端口以便其餘節點來鏈接。經過這樣的流程你將創建一個簡化的模擬的(本地的)P2P網絡,固然你也能夠將節點的代碼編譯後,將二進制程序部署到雲端。
開始coding吧
設置與導入依賴
參考以前第一篇文章,咱們使用相同的計算 hash 的函數、驗證塊數據的函數等。
設置
在工程的根目錄建立一個 .env
文件,並添加配置:
ADDR=9000
經過 go-spew
包將鏈數據輸出到控制檯,方便咱們閱讀:
go get github.com/davecgh/go-spew/spew
經過 godotenv
包來加載配置文件:
go get github.com/joho/godotenv
以後建立 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
結構體,並聲明一個Block
類型的 slice,Blockchain
:
// Block represents each 'item' in the blockchain
type Block struct {
Index int
Timestamp string
BPM int
Hash string
PrevHash string
}
// Blockchain is a series of validated Blocks
var Blockchain []Block
建立塊時計算hash值的函數:
// SHA256 hashing
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)
}
建立塊的函數:
// create a new block using previous block's hash
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
}
驗證塊數據的函數:
// make sure block is valid by checking index,
// and comparing the hash of the previous block
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
}
確保各個節點都以最長的鏈爲準:
// make sure the chain we're checking is longer than
// the current blockchain
func replaceChain(newBlocks []Block) {
if len(newBlocks) > len(Blockchain) {
Blockchain = newBlocks
}
}
網絡通訊
接着咱們來創建各個節點間的網絡,用來傳遞塊、同步鏈狀態等。
咱們先來聲明一個全局變量 bcServer
,以 channel(譯者注:channel 相似其餘語言中的 Queue,代碼中聲明的是一個 Block 數組的 channel)的形式來接受塊。
// bcServer handles incoming concurrent Blocks
var bcServer chan []Block
注:Channel 是 Go 語言中很重要的特性之一,它使得咱們以流的方式讀寫數據,特別是用於併發編程。經過這裏[2]能夠更深刻地學習 Channel。
接下來咱們聲明 main
函數,從 .env
加載配置,也就是端口號,而後實例化 bcServer
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)
}
接着建立 TCP server 並監聽端口:
// start TCP and serve TCP server
server, err := net.Listen("tcp", ":"+os.Getenv("ADDR"))
if err != nil {
log.Fatal(err)
}
defer server.Close()
須要注意這裏的 defer server.Close()
,它用來以後關閉連接,能夠從這裏[3]瞭解更多 defer
的用法。
for {
conn, err := server.Accept()
if err != nil {
log.Fatal(err)
}
go handleConn(conn)
}
經過這個無限循環,咱們能夠接受其餘節點的 TCP 連接,同時經過 go handleConn(conn)
啓動一個新的 go routine(譯者注:Rob Pike 不認爲go routine 是協程,所以沒有譯爲協程)來處理請求。
接下來是「處理請求」這個重要函數,其餘節點能夠建立新的塊並經過 TCP 鏈接發送出來。在這裏咱們依然像第一篇文章同樣,以 BPM 來做爲示例數據。
func handleConn(conn net.Conn) {
io.WriteString(conn, "Enter a new BPM:")
scanner := bufio.NewScanner(conn)
// take in BPM from stdin and add it to blockchain after
// conducting necessary validation
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:")
}
}()
defer conn.Close()
}
咱們建立一個 scanner,並經過 for scanner.Scan()
來持續接收鏈接中發來的數據。爲了簡化,咱們把 BPM 數值轉化成字符串。bcServer <- Blockchain
是表示咱們將新的鏈寫入 channel 中。
經過 TCP 連接將最新的鏈廣播出去時,咱們須要:
-
將數據序列化成 JSON 格式
-
經過 timer 來定時廣播
-
在控制檯中打印出來,方便咱們查看鏈的最新狀態
// simulate receiving broadcast
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
函數差很少就完成了,經過這裏[4]能夠得到完整的代碼。
有意思的地方
如今讓咱們來啓動整個程序,
go run main.go

就像咱們預期的,首先建立了「創世塊」,接着啓動了 TCP server 並監聽9000端口。
接着咱們打開一個新的終端,鏈接到那個端口。(咱們用不一樣顏色來區分)
nc localhost 9000



接下來咱們輸入一個BPM值:


接着咱們從第一個終端(節點)中能看到(依據輸入的BPM)建立了新的塊。

咱們等待30秒後,能夠從其餘終端(節點)看到廣播過來的最新的鏈。
下一步
到目前爲止,咱們爲這個例子添加了簡單的、本地模擬的網絡能力。固然,確定有讀者以爲這不夠有說服力。但本質上來講,這就是區塊鏈的網絡層。它能接受外部數據並改變內在數據的狀態,又能將內在數據的最新狀態廣播出去。
接下來你須要學習的是一些主流的共識算法,好比 PoW (Proof-of-Work) 和 PoS (Proof-of-Stake) 等。固然,咱們會繼續在後續的文章中將共識算法添加到這個例子中。
下一篇文章再見!
參考連接
[1] https://mp.weixin.qq.com/s?__biz=MzAwMDU1MTE1OQ==&mid=2653549361&idx=1&sn=019f54713891cf33ef3bef3b24773a96&chksm=813a62a9b64debbfdd24a8507bb974048a4456e5b0a2d5f685fb3bdf40366a25764c5df8afec&scene=21
[2] https://golangbot.com/channels/
[3] https://blog.golang.org/defer-panic-and-recover
[4] https://github.com/mycoralhealth/blockchain-tutorial/blob/master/networking/main.go
相關閱讀:
只用200行Go代碼寫一個本身的區塊鏈!
特別推薦:
比特幣、以太坊、ERC20、PoW、PoS、智能合約、閃電網絡……
想深刻了解及討論這些話題?高可用架構在知識星球(小密圈)建立了區塊鏈學習小組,共同窗習區塊鏈包括數字貨幣前沿技術,歡迎點擊連接加入。
區塊鏈學習小組
本文做者 Coral Health,由魏佳翻譯。轉載譯文請註明出處,技術原創及架構實踐文章,歡迎經過公衆號菜單「聯繫咱們」進行投稿。
高可用架構
改變互聯網的構建方式

長按二維碼 關注「高可用架構」公衆號
Code your own blockchain in less than 200 lines of Go!
If this isn’t your first time reading this post, check out Part 2: Networkinghere!
This tutorial is adapted from this excellent post about writing a basic blockchain using Javascript. We’ve ported it over to Go and added some extra goodies like viewing your blockchain in a web browser. If you have any questions about the following tutorial, make sure to join our Telegramchat. Ask us anything!
The data examples in this tutorial will be based on your resting heartbeat. We are a healthcare company after all :-) For fun, count your pulse for a minute (beats per minute) and keep that number in mind throughout the tutorial.
Almost every developer in the world has heard of the blockchain but most still don’t know how it works. They might only know about it because of Bitcoin and because they’ve heard of things like smart contracts. This post is an attempt to demystify the blockchain by helping you write your own simple blockchain in Go, with less than 200 lines of code! By the end of this tutorial, you’ll be able to run and write to a blockchain locally and view it in a web browser.
What better way to learn about the blockchain than to create your own?
What you will be able to do
- Create your own blockchain
- Understand how hashing works in maintaining integrity of the blockchain
- See how new blocks get added
- See how tiebreakers get resolved when multiple nodes generate blocks
- View your blockchain in a web browser
- Write new blocks
- Get a foundational understanding of the blockchain so you can decide where your journey takes you from here!
What you won’t be able to do
To keep this post simple, we won’t be dealing with more advanced consensus concepts like proof of work vs. proof of stake. Network interactions will be simulated so you can view your blockchain and see blocks added, but network broadcasting will be reserved for a future post.
Let’s get started!
Setup
Since we’re going to write our code in Go, we assume you have had some experience with Go. After installing and configuring Go, we’ll also want to grab the following packages:
go get github.com/davecgh/go-spew/spew
Spew allows us to view structs
and slices
cleanly formatted in our console. This is nice to have.
go get github.com/gorilla/mux
Gorilla/mux is a popular package for writing web handlers. We’ll need this.
go get github.com/joho/godotenv
Gotdotenv lets us read from a .env
file that we keep in the root of our directory so we don’t have to hardcode things like our http ports. We’ll need this too.
Let’s also create a .env
file in the root of our directory defining the port that will serve http requests. Just add one line to this file:
ADDR=8080
Create a main.go
file. Everything from now on will be written to this file and will be less than 200 lines of code. Let’s get coding!
Imports
Here are the imports we’ll need, along with our package declaration. Let’s write these to main.go
Data model
Let’s define the struct
of each of our blocks that will make up the blockchain. Don’t worry, we’ll explain what all of these fields mean in a minute.
Each Block
contains data that will be written to the blockchain, and represents each case when you took your pulse rate (remember you did that at the beginning of the article?).
Index
is the position of the data record in the blockchain
Timestamp
is automatically determined and is the time the data is written
BPM
or beats per minute, is your pulse rate
Hash
is a SHA256 identifier representing this data record
PrevHash
is the SHA256 identifier of the previous record in the chain
Let’s also model out the blockchain itself, which is simply a slice
ofBlock
:
So how does hashing fit into blocks and the blockchain? We use hashes to identify and keep the blocks in the right order. By ensuring the PrevHash
in each Block
is identical to Hash
in the previous Block
we know the proper order of the blocks that make up the chain.
Hashing and Generating New Blocks
So why do we need hashing? We hash data for 2 main reasons:
- To save space. Hashes are derived from all the data that is on the block. In our case, we only have a few data points but imagine we have data from hundreds, thousands or millions of previous blocks. It’s much more efficient to hash that data into a single SHA256 string or hash the hashes than to copy all the data in preceding blocks over and over again.
- Preserve integrity of the blockchain. By storing previous hashes like we do in the diagram above, we’re able to ensure the blocks in the blockchain are in the right order. If a malicious party were to come in and try to manipulate the data (for example, to change our heart rate to fix life insurance prices), the hashes would change quickly and the chain would 「break」, and everyone would know to not trust that malicious chain.
Let’s write a function that takes our Block
data and creates a SHA256 hash of it.
This calculateHash
function concatenates Index
, Timestamp
, BPM
,PrevHash
of the Block
we provide as an argument and returns the SHA256 hash as a string. Now we can generate a new Block
with all the elements we need with a new generateBlock
function. We’ll need to supply it the previous block so we can get its hash and our pulse rate in BPM. Don’t worry about the BPM int
argument that’s passed in. We’ll address that later.
Notice that the current time is automatically written in the block withtime.Now()
. Also notice that our prior calculateHash
function was called.PrevHash
is copied over from the hash of the previous block. Index
is incremented from the Index of the previous block.
Block Validation
Now we need to write some functions to make sure the blocks haven’t been tampered with. We do this by checking Index
to make sure they’ve incremented as expected. We also check to make sure our PrevHash
is indeed the same as the Hash
of the previous block. Lastly, we want to double check the hash of the current block by running the calculateHash
function again on the current block. Let’s write a isBlockValid
function that does all these things and returns a bool
. It’ll return true
if it passes all our checks:
What if we run into an issue where two nodes of our blockchain ecosystem both added blocks to their chains and we received them both. Which one do we pick as the source of truth? We choose the longest chain. This is a classic blockchain issue and has nothing to do with nefarious actors.
Two well meaning nodes may simply have different chain lengths, so naturally the longer one will be the most up to date and have the latest blocks. So let’s make sure the new chain we’re taking in is longer than the current chain we have. If it is, we can overwrite our chain with the new one that has the new block(s).
We simply compare the length of the slices of the chains to accomplish this:
If you’ve made it this far, pat yourself on the back! We’ve basically written up the guts of our blockchain with all the various functions we need.
Now we want a convenient way to view our blockchain and write to it, ideally in a web browser so we can show our friends!
Web Server
We assume you’re already familiar with how web servers work and have a bit of experience wiring them up in Go. We’ll walk you through the process now.
We’ll be using the Gorilla/mux package that you downloaded earlier to do the heavy lifting for us.
Let’s create our server in a run
function that we’ll call later.
Note that port we choose comes from our .env
file that we created earlier. We give ourselves a quick console message with log.Println
to let us know the server is up and running. We configure the server a bit and thenListenAndServe
. Pretty standard Go stuff.
Now we need to write the makeMuxRouter
function that will define all our handlers. To view and write to our blockchain in a browser, we only need 2 routes and we’ll keep them simple. If we send a GET
request to localhost
we’ll view our blockchain. If we send a POST
request to it, we can write to it.
Here’s our GET
handler:
We simply write back the full blockchain, in JSON format, that we can view in any browser by visiting localhost:8080
. We have ourADDR
variable set as 8080 in our `.env` file so if you change it, make sure to visit your correct port.
Our POST
request is a little bit more complicated, but not by much. To start, we’ll need a new Message
struct
. We’ll explain in a second why we need it.
Here’s the code for the handler that writes new blocks. We’ll walk you through it after you’ve read it.
The reason we used a separate Message
struct is to take in the request body of the JSON POST request we’ll use to write new blocks. This allows us to simply send a POST request with the following body and our handler will fill in the rest of the block for us:
{"BPM":50}
The 50
is an example pulse rate in beats per minute. Use your own by changing that integer to your own pulse rate.
After we’re done decoding the request body into our var m Message
struct, we create a new block by passing in the previous block and our new pulse rate into the generateBlock
function we wrote earlier . This is everything the function needs to create a new block. We do a quick check to make sure the new block is kosher using the isBlockValid
function we created earlier.
A couple notes
spew.Dump
is a convenient function that pretty prints our structs into the console. It’s useful for debugging.
- for testing POST requests, we like to use Postman.
curl
works well too, if you just can’t get away from the terminal.
When our POST requests are successful or unsuccessful, we want to be alerted accordingly. We use a little wrapper function respondWithJSON
to let us know what happened. Remember, in Go, never ignore errors. Handle them gracefully.
Almost done!
Let’s wire all these different blockchain functions, web handlers and the web server in a short, clean main
function:
So what’s going on here?
godotenv.Load()
allows us to read in variables like our port number from the.env
file we placed at the root of our directory so we don’t have to hardcode them (gross!) throughout our app.
genesisBlock
is the most important part of the main
function. We need to supply our blockchain with an initial block, or else a new block will not be able to compare its previous hash to anything, since a previous hash doesn’t exist.
- We isolate the genesis block into its own go routine so we can have a separation of concerns from our blockchain logic and our web server logic. This will work without the go routine but it’s just cleaner this way.
Tada! We’re done!
Here’s the full code:
Now for the fun stuff. Let’s try it out :-)
Fire up your application from terminal using go run main.go
In terminal, we see that the web server is up and running and we get a printout of our genesis block.
Now, visit localhost
with your port number, which for us is 8080. As expected, we see the same genesis block.
Now, let’s send some POST requests to add blocks. Using Postman, we’re going to add a some new blocks with various BPMs.
Let’s refresh our browser. Lo and behold, we now see all our new blocks in our chain with the PrevHash
of our new ones matching the Hash
of the old ones, just as we expected!
Next Steps
Congrats!! You just wrote up your own blockchain with proper hashing and block validation. You should now be able to control your own blockchain journey and explore more complicated topics like Proof of Work, Proof of Stake, Smart Contracts, Dapps, Side Chains and more.
What this tutorial doesn’t address is how new blocks get mined using Proof of Work. This would be a separate tutorial but plenty of blockchains exist without Proof of Work mechanisms. In addition, the network broadcasting is currently simulated by writing and viewing the blockchain in a web server. There is no P2P component in this tutorial.
If you’d like us to add things like Proof of Work and Networking, make sure to tell us in our Telegram chat and follow us on Twitter! That’s the best way to communicate with us. Ask us questions, give feedback, and suggest new tutorials. We’d love to hear from you!
By popular demand we’ve added Part 2: Networking to this tutorial! Check it out!
We also released a tutorial on how to store data through the blockchain using IPFS. Take a look here!
To learn more about Coral Health and how we’re using the blockchain to advance personalized medicine research, visit our website.