Turn 200 lines of code to achieve one of the block chain-----The simplest block chain __ block chain

Source: Internet
Author: User

Write a block chain of your own with only 200 lines of go code. 2018-01-30 12:49 Coral Health 1 0 Read 203

Block chain is currently the hottest topic, the majority of readers have heard of bitcoin, and perhaps the intelligent contract, I believe we all want to know how it all work. This article is to help you use the go language to implement a simple block chain, with less than 200 lines of code to reveal the principle of the block chain. High-availability architecture will also continue to introduce more block-chain articles, welcome to click on the blue "High availability architecture" attention.


"With less than 200 lines of go code, you can implement a block chain of your own." "It sounds interesting." What better way to learn than to develop a block chain of your own? Then let's just come up and practice.


Because we are a technology company in the field of health care, we use the heart-rate data (BPM heartbeat) of human calm as the sample data in this article. Let's start by counting the number of heartbeats you have in a minute, and then write down the numbers that might be used in the next section.

Through this article, you will be able to:


Create your own block chain

Understand how the hash function keeps the integrity of the block chain

How to create and add new blocks

How multiple nodes compete for building blocks

View the entire chain through the browser

All other basic knowledge about block chains


However, for examples such as the workload Proof algorithm (PoW) and the Equity proving algorithm (PoS), this kind of consensus algorithm article will not be involved. At the same time, in order to make you more aware of the block chain and the addition of blocks, we have simplified the process of network interaction, the Peer-to-peer network such as "Full network broadcast" This process, etc. will be in the next article to fill.


let's get started.
Set up


Let's say you already have a little development experience with go language. After installing and configuring the Go development environment, we also need to acquire some of the following dependencies:

Go to Github.com/davecgh/go-spew/spew

Spew can help us view both the struct and slice data structures directly in the console.


Go to Github.com/gorilla/mux

Gorilla's MUX package is very popular and we use it to write Web handler.


Go to Github.com/joho/godotenv

Godotenv can help us read the. env configuration file in the project root directory so that we don't have to hard-code the configuration of HTTP port into the code. Like this:

addr=8080


Next, we create a main.go file. After most of our work revolves around this file, let me start coding.

Import Dependencies


We import all of our dependency packages in a declarative fashion:

Package Main

Import (
"Crypto/sha256"
"Encoding/hex"
"Encoding/json"
"IO"
"Log"
"Net/http"
"OS"
"Time"

"Github.com/davecgh/go-spew/spew"
"Github.com/gorilla/mux"
"Github.com/joho/godotenv"
)

Data Model


We then define a struct that represents the data model of each block that makes up the block chain:

Type block struct {
Index int
Timestamp string
BPM int
Hash String
Prevhash String
}

Index is the position of this block throughout the chain

Timestamp is obviously the time stamp of block generation.

Hash is the hash value that this block generates through the SHA256 algorithm.

Prevhash represents the SHA256 hash value of the previous block

The number of heartbeats per minute, which is the heart rate. Remember the beginning of the article said.


Then we define a struct to represent the entire chain, and the simplest representation is the slice of a block:

var blockchain []block


We use the hash algorithm (SHA256) to determine and maintain the correct order of blocks and blocks in the chain, ensuring that each block's Prevhash value equals the Hash value in the previous block, thus constructing the chain in the correct block order:



hashing and building blocks


Why do we need to hash it out? There are two main reasons:

Uniquely identifies data in space-saving premises. The hash is computed from the data of the entire block, and in our example, the entire block's data is computed through SHA256 into a fixed-length, not-forged string.

Maintain the integrity of the chain. By storing the hash value of the previous block, we are able to ensure that each block is in the correct order in the chain. Any tampering with the data changes the hash value and destroys the chain. In our healthcare sector, for example, if a malicious third party modifies the price of "human life insurance" by modifying the unhealthy BPM values in one or more blocks, the entire chain becomes discredited.


We then write a function to compute the SHA256 hash value of the given data:

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)
}


The Calculatehash function takes a block, calculates the SHA256 hash value by the index,timestamp,bpm in the block, and the Prevhash value. Next we can take a function of building blocks:

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
}


In which, the index is derived from the given first piece of the index increment, the timestamp is directly through time. Now (), the hash value is computed from the previous Calculatehash function, and the Prevhash is the hash value of the given previous block.


Check Block


With the block generated, we then need a function to help us determine if a block has been tampered with. Check the Index to see whether this block is correct increment, check the Prevhash and the previous block of the hash is consistent, and then through the Calculatehash check the current block hash value is correct. With these steps we can write a validation function:

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
}


In addition to the check block, we will also encounter a problem: Two nodes are generated blocks and added to their own chain, then we should be whichever. The details here are set aside for the next article, let's remember one principle: always choose the longest chain.



Generally, a longer chain indicates that its data (state) is updated, so we need a function

can help us to switch the local outdated chain to the latest chain:

Func Replacechain (newblocks []block) {
If Len (newblocks) > len (blockchain) {
Blockchain = Newblocks
}
}



In this step, we basically complete all the important functions. Next, we need a convenient and intuitive way to view our chain, including data and status. Viewing Web pages from a browser may be the most appropriate way to do this.

Web Services

I'm guessing you're familiar with the traditional Web services and development, so you're sure to see this part.
With the help of Gorilla/mux package, we first write a function to initialize our Web services:

Func run () error {
MUX: = Makemuxrouter ()
HTTPADDR: = os. Getenv ("ADDR")
Log. Println ("Listening on", OS. Getenv ("ADDR"))
S: = &http. server{
ADDR: " :" + httpaddr,
Handler: Mux,
ReadTimeout: Ten * time. Second,
WriteTimeout: Ten * time. Second,
Maxheaderbytes:1 << 20,
}

If err: = S.listenandserve (); Err!= Nil {
return err
}

return Nil
}


The port number is obtained by using the. Env mentioned above, and then adding some basic configuration parameters, the Web service can already be listen and serve.
Next we will define different endpoint and corresponding handler. For example, for "/" GET requests we can view the entire chain, "/" POST requests can create blocks.

Func makemuxrouter () http. Handler {
Muxrouter: = Mux. Newrouter ()
Muxrouter.handlefunc ("/", Handlegetblockchain). Methods ("Get")
Muxrouter.handlefunc ("/", Handlewriteblock). Methods ("POST")
Return Muxrouter
}


Handler of GET Request:

Func Handlegetblockchain (w http. Responsewriter, R *http. Request) {
Bytes, err: = json. Marshalindent (Blockchain, "", "" )
If Err!= nil {
http. Error (W, err.) Error (), HTTP. Statusinternalservererror)
Return
}
Io. WriteString (w, string (bytes))
}


To simplify, we return the entire chain directly in JSON format, and you can access localhost:8080 or 127.0.0.1:8080 in the browser (8080 is the port number you defined in. env ADDR).

The handler of Post requests is slightly more complex, so let's first define the payload of the POST request:

Type message struct {
BPM int
}


And look at the implementation of handler:

Func Handlewriteblock (w http. Responsewriter, R *http. Request) {
VAR m message

Decoder: = JSON. Newdecoder (R.body)
If err: = decoder. Decode (&M); Err!= Nil {
Respondwithjson (W, R, http.) Statusbadrequest, R.body)
Return
}
Defer R.body.close ()

Newblock, err: = Generateblock (Blockchain[len (Blockchain)-1], M.BPM)
If Err!= nil {
Respondwithjson (W, R, http.) Statusinternalservererror, M)
Return
}
If Isblockvalid (Newblock, Blockchain[len (Blockchain)-1]) {
Newblockchain: = Append (Blockchain, newblock)
Replacechain (Newblockchain)
Spew. Dump (Blockchain)
}

Respondwithjson (W, R, http.) statuscreated, Newblock)

}


The payload defined above can be used in our POST request body, for example:

{"BPM": 75}


Remember the Generateblock function we wrote earlier? It accepts a "previous block" parameter, and a BPM value. Post handler can obtain the BPM value in the request body after accepting the request, then can generate a new block by using the function of the building block and the function of the check block.

In addition, you can also:

Use spew. Dump This function can be very beautiful and easy to read the struct, slice and other data printed in the console, convenient for us to debug.

When you test a POST request, you can use the Postman Chrome plug-in, which is more intuitive and convenient than curl.


After the POST request has been processed, we need to return a response from the client, whether or not the block was created successfully:

Func Respondwithjson (w http. Responsewriter, R *http. Request, code int, payload interface{}) {
Response, Err: = json. Marshalindent (Payload, "", "" )
If Err!= nil {
W.writeheader (http. Statusinternalservererror)
W.write ([]byte ("HTTP 500:internal Server Error")
Return
}
W.writeheader (Code)
W.write (response)
}

it's almost done.


Next, we put these functions on the block chain, the functions of the Web Services "assembled":

Func Main () {
ERR: = godotenv. Load ()
If Err!= nil {
Log. Fatal (ERR)
}

Go func () {
T: = time. Now ()
Genesisblock: = block{0, t.string (
Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

Tags Index: