Creating a blockchain with Golang requires only 200 lines of code.

Source: Internet
Author: User
Tags sha256 algorithm
This is a creation in Article, where the information may have evolved or changed.

In this article you will use the Go (Golang) language to create your own blockchain, understand how the hash function preserves the integrity of the blockchain, master how to create and add new blocks, implement multiple nodes by competing to generate blocks, view the entire chain through a browser, and learn all the other basics about blockchain.

However, there will not be a consensus algorithm such as the proof of effort (PoW) and the Benefit Proof algorithm (PoS), and in order to make it easier for you to see the blockchain and block additions, we have simplified the process of network interaction, such as "All-network broadcast" This process, among other things, will be included in the next article.

Development environment

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

~$ go get github.com/davecgh/go-spew/spew

spewcan help us see both struct and slice data structures directly in the terminal.

~$ go get github.com/gorilla/mux

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

~$ go get github.com/joho/godotenv

godotenvcan help us read the configuration files in the root directory of the project so that we .env do not have to hard code the configuration of the HTTP port. For example, like this:

ADDR=8080

Next, we create a main.go file. After most of the work around this file, start writing code it!

Importing dependent Packages

We import all the dependency packages in a declarative way:

package mainimport (    "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 for each block that makes up the blockchain:

type Block struct {    Index     int    Timestamp string    BPM       int    Hash      string    PrevHash  string}
    • Index is the position of this block in the entire chain
    • Timestamp is obviously the timestamp when the block was generated.
    • Hash is the hash value generated by this block through the SHA256 algorithm.
    • Prevhash represents the SHA256 hash value of the previous block
    • BPM beats per minute, i.e. heart rate

Next, we define a structure that represents the entire chain, and the simplest representation is the slice of a Block:

var Blockchain []Block

We use the hashing algorithm (SHA256) to determine and maintain the correct order of blocks and blocks in the chain, ensuring that the Prevhash value of each block equals the hash value in the previous block, so that the chain is built in the correct block order:

! [180 line Go code gives you a thorough understanding of what blockchain is] (Http://blog.hubwiz.com/2018/02/04/blockchain-diy-go/chain-model.png

Hashing and generating new blocks

Why do we need a hash? There are two main reasons:

    • Uniquely identifies data in space-saving premises. Hashing is calculated using the entire block of data, in our case, the entire block of data is computed by SHA256 into a fixed-length, non-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 will change the hash value and also destroy the chain. For example, in the area of health care we are engaged in, for example, if a malicious third party modifies the value of a "person's life insurance" for the sake of adjusting the price of a "human", the entire chain becomes untrustworthy.

We then write a function to calculate the SHA256 hash value for 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 that calculates the SHA256 hash value from the index,timestamp,bpm in the block, as well as the Prevhash value. Next we can write a function that generates 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}

Where index is incremented from the index of the given previous piece, the timestamp is passed directly through time. Now () function, the hash value is calculated from the preceding Calculatehash function, and Prevhash is the hash value of the previous block given.

Check Block

Having done with the block generation, we need to have a function to help us determine if a block has been tampered with. Check the Index to see if this block is incremented correctly, check whether the hash of the Prevhash and the previous block is consistent, and then calculatehash check whether the hash value of the current block is correct. With these steps we can write a check 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 also encounter a problem: Two nodes are generated blocks and added to their respective chains, then we should be based on whom? Here's the details we left to the next article, here first let's remember a principle: always choose the longest chain:

In general, a longer chain means that its data (state) is updated, so we need a function that will help us to switch the local expiration chain to the latest chain:

func replaceChain(newBlocks []Block) {    if len(newBlocks) > len(Blockchain) {        Blockchain = newBlocks    }}

At this point, 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 through a browser can be the most appropriate way!

WEB Services

I guess you must be familiar with traditional Web services and development, so this part of you is sure to look at it.

With the Gorilla/mux package, we first write a function to initialize our Web service:

func run() error {    mux := makeMuxRouter()    httpAddr := os.Getenv("ADDR")    log.Println("Listening on ", os.Getenv("ADDR"))    s := &http.Server{        Addr:           ":" + httpAddr,        Handler:        mux,        ReadTimeout:    10 * time.Second,        WriteTimeout:   10 * time.Second,        MaxHeaderBytes: 1 << 20,    }    if err := s.ListenAndServe(); err != nil {        return err    }    return nil}

The port number is obtained by the above mentioned. Env to add some basic configuration parameters, this Web service can already listen and serve!

Then we'll define the different endpoint and the corresponding handler. For example, for a GET request for "/" We can view the entire chain, and the "/" POST request can create blocks.

func makeMuxRouter() http.Handler {    muxRouter := mux.NewRouter()    muxRouter.HandleFunc("/", handleGetBlockchain).Methods("GET")    muxRouter.HandleFunc("/", handleWriteBlock).Methods("POST")    return muxRouter}

Handler for GET requests:

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 here is the port number you defined in. env ADDR).

The handler of the post request is slightly more complicated, so let's define the payload of the POST request first:

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}

Do you 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 with the help of generating block function and check block

In addition, you can also:

    • Use spew. Dump This function can be very beautiful and easy to read the way the struct, slice and other data printed in the console, convenient for us to debug.
    • When testing a POST request, you can use the POSTMAN chrome plugin, which is more intuitive and convenient than curl.

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

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 "assemble" the functions of the blockchain, the Web service, into the function:

func main() {    err := godotenv.Load()    if err != nil {        log.Fatal(err)    }    go func() {        t := time.Now()        genesisBlock := Block{0, t.String(), 0, "", ""}        spew.Dump(genesisBlock)        Blockchain = append(Blockchain, genesisBlock)    }()    log.Fatal(run())}

The Genesisblock (Genesis block) Here is the most important part of the main function, which initializes the blockchain, after all, the Prevhash of the first block is empty.

Oh, yes! Completed the

The complete code can be obtained from here: Github repo

Let's start it up:

~$ go run main.go

In the terminal, we can see the log information that the Web server started and print out the information of the Genesis Block:

Then we open the browser and visit the localhost:8080 address, and we can see that the page shows the current entire blockchain information (of course, there is only one Genesis block):

Next, we'll send some POST requests via POSTMAN:

Refresh the page just now, there are a few more blocks in the chain, exactly what we just generated, and you can see that the order and hash values of the blocks are correct.

Summarize

We have just completed a block chain of our own, although very simple (the burrow), but it has block generation, hash calculation, block check and other basic capabilities. You can then continue to learn more about other important chunks of the blockchain, such as proof of effort, consensus algorithms such as proof of entitlement, or smart contracts, dapp, side-chaining, and so on.

Currently this implementation does not include any peer-to network content, we will supplement this section in the next article, of course, we encourage you to practice on this basis!

If you want to learn more about ethereum dapp development, you can visit the most popular online interactive tutorials offered by the network:

  • Ethereum Dapp for novice Blockchain Beginners Tutorial
  • Blockchain +ipfs+node.js+mongodb+express to Central Ethereum e-commerce application development

Additional content can also be accessed from this Ethereum blog.

Original: Code your own blockchain in less than lines of go!

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.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.