The principle of block chain and Golang implementation example

Source: Internet
Author: User
Tags sprintf
What is a block chain

Block chain has much fire, I do not have to introduce, you can jump through the search engine here, it proves that you are the fan of the block chain. Since come in, will not let you white, no BB, directly on dry goods.

(prologue, not all nonsense) block chain is one of the most revolutionary technologies in the 21st century, it is still in the growing stage, and there are many potential has not yet emerged. In essence, the block chain is just a distributed database. What makes it unique, however, is that the chunk chain is an open database, not a private database, that is, each person who uses it has a full or partial copy. New records can be added to the database only with the consent of the other database administrator. Moreover, it is because of the block chain that makes the cryptographic currency and the smart contract a reality.

Comprehensive and described, with an image of such as: Block chain is a central, distributed "book Books." The principle of block chain 1. Block

Let's start with "chunks" in the "Block chain". In a block chain, a chunk is a block that stores valid information.
For example, the useful information stored in bitcoin blocks is Bitcoin trading, and transaction information is the essence of all cryptographic currencies. In addition, the blocks also contain technical information, such as the version, the current timestamp, and the hash of the previous block.

Here, we don't implement a chunk chain as described in the Bitcoin specification, but implement a simplified version of the Block chain, which contains only a few key messages. It looks like this:

Type block struct {
Timestamp Int64
Data []byte
Prevblockhash []byte
Hash []byte
}

  -Timestamp is the current timestamp, which is the time the block was created.

  -Data is the actual valid information that is stored in the block.

  -  Prevblockhash stores the hash of the previous block.

  -  Hashing is the hash of the current block.

In the Bitcoin specification, Timestamp, Prevblockhash, Hash is the chunk header (block header), and the chunk header is a separate data structure. And the transaction, which is here, is another separate data structure. For the sake of simplicity, I mixed the two together.

So how do we compute the hash? How to compute the hash is a very important part of the block chain. It is this feature that makes the chain of blocks safe. Calculating a hash is a very difficult operation to compute. Even on high-speed computers, it takes time (which is why people buy GPU to dig bitcoin). This is an intentional architectural design that makes it very difficult to add new blocks, so it is hard to make changes once the blocks are added.

Currently, we take only a few fields of the block structure (Timestamp, Data, and Prevblockhash), connect them to each other, and then compute a SHA-256 hash on the result of the connection. Let's complete this task in the Sethash method:

Func (b *block) Sethash () {
Timestamp: = []byte (StrConv. Formatint (B.timestamp, 10))
Headers: = bytes. Join ([][]byte{b.prevblockhash, B.data, timestamp}, []byte{})
Hash: = sha256. Sum256 (Headers)

B.hash = hash[:]
}

Next, according to Golang's convention, we implement a function that simplifies the creation of a block:

Func newblock (data string, Prevblockhash []byte) *block {
Block: = &block{time. Now (). Unix (), []byte (data), Prevblockhash, []byte{}}
Block. Sethash ()
return block
}

That's the whole story of the chunk. 2. Chain

Now let's implement a block chain. In essence, a block chain is only a database with a specific structure, and is a list of ordered, back links.
This means that the blocks are stored in the order in which they are inserted, and each block is connected to the previous block. Such a structure allows us to quickly get the latest block on the chain and efficiently retrieve a block via hash.
In Golang, this structure can be implemented by an array and a map: array stores ordered hashes (Golang array is ordered), map storage hask-> block pair (Golang, map is unordered). But in the basic prototype phase, we only use array, because we do not need to get the block by hash now.

Type blockchain struct {
Blocks []*block
}

This is our first block chain. I never thought it would be so easy.

Now, let's add a block to it:

Func (BC *blockchain) addblock (data string) {
Prevblock: = Bc.blocks[len (Bc.blocks)-1]
Newblock: = Newblock (data, Prevblock.hash)
Bc.blocks = Append (Bc.blocks, Newblock)
}

Complete. But is that really the case?

In order to add a new block, we have to have an existing block, but now our chain is empty, not one block. So, in any block chain, there must be at least one block. Such a block, which is the first block in the chain, is usually called the Genesis block (Genesis blocks). Let's implement a way to create a Genesis block:

Func Newgenesisblock () *block {
Return Newblock ("Genesis block", []byte{})
}

Now we can implement a function to create a block chain with a Genesis block:

Func Newblockchain () *blockchain {
Return &blockchain{[]*block{newgenesisblock ()}
}

To check whether our block chain is working as scheduled:

Func Main () {
BC: = Newblockchain ()

Bc. Addblock ("Send 1 BTC to Ivan")
Bc. Addblock ("Send 2 more BTC to Ivan")

For _, Block: = Range Bc.blocks {
Fmt. Printf ("Prev. Hash:%x\n", block. Prevblockhash)
Fmt. Printf ("Data:%s\n", block.) Data)
Fmt. Printf ("Hash:%x\n", block. Hash)
Fmt. Println ()
}
a complete code

Package main import ("crypto/sha256" "Encoding/json" "Flag" "FMT" "io" "Log" "Net/http" "Sort" "strings" "Time" "websocket"//"Golang.org/x/net/websocket") const (querylatest = Iota Q Ueryall responseblockchain) var genesisblock = &block{index:0, Previoushash: "0", Timestamp : 1465154705, Data: "My Genesis block!!", Hash: "816534932c2b7154836da6afc367695e6337db8a921823 784c14378abed4f7d7 ",} var (sockets []*websocket. Conn blockchain = []*block{genesisblock} HTTPADDR = flag.
    String ("API", ": 3001", "API server address.") P2PADDR = flag.
    String ("Peer-to-peer", ": 6001", "Peer-to-peer server address.") Initialpeers = flag.
    String ("Peers", "ws://localhost:6001", "initial Peers")) type block struct {index int64 ' JSON: ' Index ' Previoushash string ' JSON: ' Previoushash ' Timestamp Int64 ' json: ' Timestamp ' ' Data string ' json: ' DatA "' Hash string ' JSON: ' Hash '} func (b *block) string () string {return FMT. Sprintf ("Index:%d,previoushash:%s,timestamp:%d,data:%s,hash:%s", B.index, B.previoushash, B.timestamp, B.Data, B.      Hash)} type Byindex []*block func (b byindex) len () int {return len (b)} func (b byindex) Swap (i, J int) {B[i], b[j] = B[j], B[i] func (b byindex) Less (i, J int) bool {return b[i]. Index < B[j].  Index} type responseblockchain struct {type int ' JSON: ' Type ' ' Data string ' JSON: ' Data '} func errfatal (msg String, err Error) {If Err!= nil {log. Fatalln (MSG, err)}} func connecttopeers (peersaddr []string) {for _, Peer: = Range Peersaddr {if peer = = "" {continue} ws, Err: = WebSocket. Dial (Peer, "", peer) if Err!= nil {log. PRINTLN ("dial to Peer", err) Continue} initconnection (WS)} func initconnection (ws *web Socket. Conn) {Go wsHANDLEP2P (WS) Log.
    PRINTLN ("Query latest block.") Ws. Write (Querylatestmsg ())} func handleblocks (w http. Responsewriter, R *http. Request) {bs, _: = json. Marshal (Blockchain) W.write (BS)} func handlemineblock (w http. Responsewriter, R *http. Request {var v struct {Data string ' JSON: ' Data '} decoder: = JSON. Newdecoder (r.body) defer r.body.close () Err: = decoder. Decode (&v) If Err!= nil {w.writeheader (http. Statusgone) log. Println ("[API] Invalid block data:", err. Error ()) W.write ([]byte ("Invalid block data." + Err.) Error () + "\ n")) return} blocks: = Generatenextblock (V.data) addblock (block) broadcast (Responselat Estmsg ())} func handlepeers (w http. Responsewriter, R *http. Request) {var slice []string for _, Socket: = Range Sockets {if socket. Isclientconn () {slice = append (slice, strings. Replace (socket. Localaddr ().
String (), "ws://", "", 1))} else {            Slice = append (slice, socket. Request (). REMOTEADDR)} BS, _: = json. Marshal (Slice) w.write (BS)} func handleaddpeer (w http. Responsewriter, R *http. Request) {var v struct {Peer string ' JSON: ' Peer '} decoder: = JSON. Newdecoder (r.body) defer r.body.close () Err: = decoder. Decode (&v) If Err!= nil {w.writeheader (http. Statusgone) log. Println ("[API] Invalid peer data:", err. Error ()) W.write ([]byte ("Invalid peer data." + Err.) Error ()) return} connecttopeers ([]string{v.peer})} func wshandlep2p (ws *websocket. Conn) {var (v = &responseblockchain{} peer = ws. Localaddr (). String ()) sockets = append (sockets, WS) for {var msg []byte Err: = WebSocket. Message.receive (WS, &msg) If err = = Io. EOF {log. Printf ("Peer-to-peer peer[%s] shutdown, remove it form peers pool.\n", Peer) break} ifErr!= Nil {log. Println ("Can ' t receive Peer-to-peer msg from", Peer, err.) Error ()) Break} log. Printf ("Received[from%s]:%s.\n", Peer, msg) Err = json.
            Unmarshal (msg, v) errfatal ("Invalid Peer-to-peer msg", err) switch V.type {case querylatest: V.type = responseblockchain bs: = responselatestmsg () log. Printf ("Responselatestmsg:%s\n", BS) ws. Write (BS) Case Queryall:d, _: = json. Marshal (blockchain) V.type = Responseblockchain V.data = string (d) bs, _: = json. Marshal (v) log. Printf ("Responsechainmsg:%s\n", BS) ws. Write (BS) Case Responseblockchain:handleblockchainresponse ([]byte (V.data))}}} func Getlatestblock () (block *block) {return Blockchain[len (Blockchain)-1]} func responselatestmsg () (BS []byte) {var V = &responseblockchain{type:responseblockchain} D, _: = json. Marshal (Blockchain[len (Blockchain)-1:]) V.data = string (d) bs, _ = json. Marshal (v) return} func querylatestmsg () []byte {return] []byte (FMT. Sprintf ("{\" type\ ":%d}", Querylatest))} func queryallmsg () []byte {return] []byte (FMT. Sprintf ("{\" type\ ":%d}", Queryall))} func Calculatehashforblock (b *block) string {return FMT. Sprintf ("%x", sha256.) SUM256 ([]byte, FMT.
    Sprintf ("%d%s%d%s", B.index, B.previoushash, B.timestamp, B.data)))} Func Generatenextblock (Data string) (NB *block) { var previousblock = Getlatestblock () nb = &block{Data:data, Previoushash:previousblo Ck. Hash, Index:previousBlock.Index + 1, timestamp:time. Now (). Unix (), NB.
        Hash = Calculatehashforblock (NB) return} func Addblock (b *block) {if isvalidnewblock (b, Getlatestblock ()) { Blockchain = append (blockchain, b)}} func Isvalidnewblock (NB, PB *block) (ok bool) {if NB. Hash = = CalculateHashforblock (NB) && PB. index+1 = nb. Index && PB. Hash = nb. Previoushash {OK = true} return} func isvalidchain (BC []*block) bool {if bc[0]. String ()!= genesisblock.string () {log. Println ("No same genesisblock.", Bc[0]. String ()) return false} var temp = []*block{bc[0]} for I: = 1; i < Len (BC); i++ {if Isvalidnewblock (Bc[i], temp[i-1]) {temp = append (temp, bc[i])} else {R Eturn false} return True} func replacechain (BC []*block) {if isvalidchain (BC) && Len (BC) > Len (Blockchain) {log. Println ("Received blockchain is valid.
        Replacing current blockchain with received blockchain. ") Blockchain = BC Broadcast (RESPONSELATESTMSG ())} else {log.
    Println ("Received blockchain invalid.") } func Broadcast (msg []byte) {for n, Socket: = Range Sockets {_, Err: = socket.
     Write (msg)   If Err!= nil {log. Printf ("peer [%s] disconnected.", socket. Remoteaddr ().
        String ()) sockets = Append (Sockets[0:n], sockets[n+1:] ...) }} func Handleblockchainresponse (msg []byte) {var receivedblocks = []*block{} ERR: = JSON. Unmarshal (msg, &receivedblocks) errfatal ("Invalid Blockchain", err) sort. Sort (Byindex (receivedblocks)) latestblockreceived: = Receivedblocks[len (Receivedblocks)-1] Latestblockheld: = Get Latestblock () If Latestblockreceived.index > latestblockheld.index {log. Printf ("Blockchain possibly behind. We got:%d Peer got:%d ", Latestblockheld.index, latestblockreceived.index) If Latestblockheld.hash = Latestblock Received.previoushash {log.
            Println ("We can append the received blocks to our chain.") Blockchain = append (Blockchain, latestblockreceived)} else If Len (receivedblocks) = = 1 {log. Println ("We have to query" the chain from our PEER. ") Broadcast (QUERYALLMSG ())} else {log.
            Println ("Received blockchain is longer than current blockchain.") Replacechain (Receivedblocks)}} else {log. Println ("received blockchain isn't longer than current blockchain.

Do nothing. "}} Func main () {flag. Parse () Connecttopeers (strings. Split (*initialpeers, ",")) http. Handlefunc ("/blocks", Handleblocks) http. Handlefunc ("/mine_block", Handlemineblock) http. Handlefunc ("/peers", Handlepeers) http. Handlefunc ("/add_peer", Handleaddpeer) go func () {log. Println ("Listen http on", *httpaddr) Errfatal ("Start API Server", HTTP. Listenandserve (*httpaddr, Nil))} () http. Handle ("/", WebSocket. Handler (wshandlep2p)) log. Println ("Listen peer-to-peer on", *p2paddr) errfatal ("Start Peer-to-peer Server", HTTP. Listenandserve (*p2paddr, nil))}

Link: https://github.com/kofj/naivechain/blob/master/main.go

What is block chain block chain Principle 1. Block 2. Chain a complete code

How many people are busy ligatures blog time is not yo.

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.