hash函数
- 一种算法
- 任意长度的二进制数据映射为固定长度的二进制数据
hash函数的特点
- 确定性——对同一个输入数据每次都能得到相同的结果
- 单向性——对一个数据可以很容易计算出hash值,但是对于一个hash值非常难反推出数据
- 隐秘性——没有可行的方法算出hash函数的输入值
- 抗篡改——对于数据一个bit位的改动,对hash值的改动也是非常大
- 抗碰撞——对于两个不同的数据,hash值相同的可能性很小
hash值的实现
- MD系列
- SHA系列,推荐SHA256,SHA3
代码实现
package mainimport "fmt"import ("crypto/sha256""encoding/hex""log")func calculateHash(toBeHashed string) string { hashInBytes :=sha256.Sum256([]byte(toBeHashed)) hashInStr:=hex.EncodeToString(hashInBytes[:]) log.Printf(toBeHashed,hashInStr) return hashInStr}func main() { fmt.Println("Hello, World!") calculateHash("test1") calculateHash("test1") calculateHash("testl")}
运行结果
连式结构
如果区块1的数据发生改变,区块2不发生相应的改变,则指向区块2的hash指针不在有效。如果要使得引用有效,则就要改变区块2的hash值,后面的区块都要发生改变。
构建自己的区块链
- 实现链式结构
- 实现一个简单的http server,对外暴露读写接口
步骤
- 创建block
- 创建blockchain
- 创建http server
创建Block
- 新建工程demochain
- 创建Block文件
- 创建Block结构体与相关函数
package demochainimport ("crypto/sha256""encoding/hex""time")//区块结构体type Block struct{ Index int64 //区块编号 Timestamp int64 //区块时间戳 PrevBlockHash string //上一个区块的哈希值 Hash string //当前区块哈希值 Data string //区块数据}//计算hsah值func calculateHash(b Block) string { //计算hash值包含除了当前区块哈希值的其他数据 blockData:=string(b.Index)+string(b.Timestamp)+b.PrevBlockHash+b.Data hashInBytes:=sha256.Sum256([]byte(blockData)) return hex.EncodeToString(hashInBytes[:])}//生成新区块func GenerateNewBlock(preBlock Block,data string) Block { newBlock:=Block{} newBlock.Index=preBlock.Index+1 newBlock.PrevBlockHash=preBlock.Hash newBlock.Timestamp=time.Now().Unix() newBlock.Data=data newBlock.Hash=calculateHash(newBlock) return newBlock}//创始区块func GenerateGenesisBlock(){ preBlock :=Block{} preBlock.Index=-1 preBlock.Hash="" GenerateNewBlock(preBlock,"Genesis Block")}
创建Blockchain
- 创建Blockchain文件
- 创建Blockchain结构体及相关方法
package demochainimport ("fmt""log")type Blockchain struct {Blocks []*Block}//创建新的区块链func NewBlockchain() *Blockchain { //创始区块genesisBlock := GenerateGenesisBlock()blockchain := Blockchain{}blockchain.AppendBlock(&genesisBlock)return &blockchain}//在区块上增加数据func (bc *Blockchain) SendData(data string) {preBlock := bc.Blocks[len(bc.Blocks)-1]newBlock := GenerateNewBlock(*preBlock, data)bc.AppendBlock(&newBlock)}//添加区块func (bc *Blockchain) AppendBlock(newBlock *Block) {if len(bc.Blocks) == 0 {bc.Blocks = append(bc.Blocks, newBlock)return}if isValid(*newBlock, *bc.Blocks[len(bc.Blocks)-1]) {bc.Blocks = append(bc.Blocks, newBlock)} else {log.Fatal("invalid block")}}//打印区块链里面的数据func (bc *Blockchain) Print() {for _, block := range bc.Blocks {fmt.Printf("Index: %d\n", block.Index)fmt.Printf("PrevHash: %s\n", block.PrevBlockHash)fmt.Printf("CurrHash: %s\n", block.Hash)fmt.Printf("Data: %s\n", block.Data)fmt.Printf("Timestamp: %d\n", block.Timestamp)fmt.Println()}}//添加区块前校验func isValid(newBlock Block, oldBlock Block) bool {if newBlock.Index-1 != oldBlock.Index {return false}if newBlock.PrevBlockHash != oldBlock.Hash {return false}if calculateHash(newBlock) != newBlock.Hash {return false}return true}
创建区块链
package mainimport "go-blockchain/core"func main() {bc := core.NewBlockchain()bc.SendData("Send 1 BTC to Alice")bc.SendData("Send 1 EOS to Bob")bc.Print()}
结果
创建Http Server
步骤
- 创建http server
- 提供API访问接口
package mainimport ("encoding/json""go-blockchain/core""io""net/http")//全局的blockchain变量var blockchain *core.Blockchain//提供http服务func run() {http.HandleFunc("/blockchain/get", blockchainGetHandler)http.HandleFunc("/blockchain/write", blockchainWriteHandler)//监听端口http.ListenAndServe("localhost:8888", nil)}//get请求的方法func blockchainGetHandler(w http.ResponseWriter, r *http.Request) { //把任意对象转换为json格式bytes, error := json.Marshal(blockchain)if error != nil {http.Error(w, error.Error(), http.StatusInternalServerError)return}//转换成stringio.WriteString(w, string(bytes))}//write请求的方法func blockchainWriteHandler(w http.ResponseWriter, r *http.Request) {blockData := r.URL.Query().Get("data")blockchain.SendData(blockData)blockchainGetHandler(w, r)}func main() {blockchain = core.NewBlockchain()run()}