首页 > 编程语言 >区块链编程-golang(三)

区块链编程-golang(三)

时间:2024-08-16 15:27:35浏览次数:10  
标签:err 编程 blockchain golang func go byte 区块 block

文件目录

主文件下有 文件blockchain、go.mod、gosum、文件tmp、main.go

文件blockhain下面有block.go、blockchain.go、proof.go

 

part1:block.go

package blockchain

import (
    "bytes"
    "encoding/gob"
    "log"
)

type Block struct {
    Hash     []byte
    Data     []byte
    PrevHash []byte
    Nonce    int
}

func CreateBlock(data string, prevHash []byte) *Block {
    block := &Block{[]byte{}, []byte(data), prevHash, 0}
    pow := NewProof(block)
    nonce, hash := pow.Run()
    block.Hash = hash[:]
    block.Nonce = nonce
    return block
}

func Genesis() *Block {
    return CreateBlock("Genesis", []byte{})
}

func (b *Block) Serialize() []byte {
    var res bytes.Buffer
    encoder := gob.NewEncoder(&res)
    err := encoder.Encode(b)
    Handle(err)
    return res.Bytes()
}

func Deserialize(data []byte) *Block {
    var block Block
    decoder := gob.NewDecoder(bytes.NewReader(data))
    err := decoder.Decode(&block)
    Handle(err)
    return &block
}

func Handle(err error) {
    if err != nil {
        log.Panic(err)
    }
}

 

part2 : blockchain.go

package blockchain

import (
    "fmt"

    "github.com/dgraph-io/badger"
)

const (
    dbPath = "./tmp/blocks"
)

type BlockChain struct {
    LastHash []byte
    Database *badger.DB
}

type BlockChainIterator struct {
    CurrentHash []byte
    Database    *badger.DB
}

func InitBlockChain() *BlockChain {

    // 存储最新的区块哈希
    var lastHash []byte

    opts := badger.DefaultOptions
    opts.Dir = dbPath
    opts.ValueDir = dbPath

    db, err := badger.Open(opts)
    Handle(err)

    err = db.Update(func(txn *badger.Txn) error {
        if _, err := txn.Get([]byte("lh")); err == badger.ErrKeyNotFound {
            fmt.Println("No existing blockchain found")
            genesis := Genesis()
            fmt.Println("Genesis proved")
            //存储创世区块
            err = txn.Set(genesis.Hash, genesis.Serialize())
            Handle(err)
            //存储创世区块链哈希
            err = txn.Set([]byte("lh"), genesis.Hash)

            lastHash = genesis.Hash

            return err
        } else {
            item, err := txn.Get([]byte("lh"))
            Handle(err)
            lastHash, err = item.Value()
            return err
        }
    })

    Handle(err)

    blockchain := BlockChain{lastHash, db}
    return &blockchain
}

func (chain *BlockChain) AddBlock(data string) {
    var lastHash []byte

    err := chain.Database.View(func(txn *badger.Txn) error {
        // 获取最新哈希信息
        item, err := txn.Get([]byte("lh"))
        Handle(err)
        lastHash, err = item.Value()

        return err
    })
    Handle(err)

    // 将最新data和哈希信息获取新的区块
    newBlock := CreateBlock(data, lastHash)

    err = chain.Database.Update(func(txn *badger.Txn) error {
        // 保存序列化信息
        err := txn.Set(newBlock.Hash, newBlock.Serialize())
        Handle(err)
        err = txn.Set([]byte("lh"), newBlock.Hash)

        chain.LastHash = newBlock.Hash

        return err
    })
    Handle(err)
}

func (chain *BlockChain) Iterator() *BlockChainIterator {
    iter := &BlockChainIterator{chain.LastHash, chain.Database}

    return iter
}

func (iter *BlockChainIterator) Next() *Block {
    var block *Block

    err := iter.Database.View(func(txn *badger.Txn) error {
        item, err := txn.Get(iter.CurrentHash)
        Handle(err)
        encodedBlock, err := item.Value()
        block = Deserialize(encodedBlock)

        return err
    })
    Handle(err)

    iter.CurrentHash = block.PrevHash

    return block
}

proof.go

package blockchain

import (
    "bytes"
    "crypto/sha256"
    "encoding/binary"
    "fmt"
    "log"
    "math"
    "math/big"
)

// Take the data from the block

// create a counter (nonce) which starts at 0

// create a hash of the data plus the counter

// check the hash to see if it meets a set of requirements

// Requirements:
// The First few bytes must contain 0s

const Difficulty = 18

type ProofOfWork struct {
    Block  *Block
    Target *big.Int
}

func NewProof(b *Block) *ProofOfWork {
    target := big.NewInt(1)
    target.Lsh(target, uint(256-Difficulty))

    pow := &ProofOfWork{b, target}

    return pow
}

func (pow *ProofOfWork) InitData(nonce int) []byte {
    data := bytes.Join(
        [][]byte{
            pow.Block.PrevHash,
            pow.Block.Data,
            ToHex(int64(nonce)),
            ToHex(int64(Difficulty)),
        },
        []byte{},
    )

    return data
}

func (pow *ProofOfWork) Run() (int, []byte) {
    var intHash big.Int
    var hash [32]byte

    nonce := 0

    for nonce < math.MaxInt64 {
        data := pow.InitData(nonce)
        hash = sha256.Sum256(data)

        fmt.Printf("\r%x", hash)
        intHash.SetBytes(hash[:])

        if intHash.Cmp(pow.Target) == -1 {
            break
        } else {
            nonce++
        }

    }
    fmt.Println()

    return nonce, hash[:]
}

func (pow *ProofOfWork) Validate() bool {
    var intHash big.Int

    data := pow.InitData(pow.Block.Nonce)

    hash := sha256.Sum256(data)
    intHash.SetBytes(hash[:])

    return intHash.Cmp(pow.Target) == -1
}

func ToHex(num int64) []byte {
    buff := new(bytes.Buffer)
    err := binary.Write(buff, binary.BigEndian, num)
    if err != nil {
        log.Panic(err)

    }

    return buff.Bytes()
}

 

 

part4: go.mod

module github.com/tensor-programming/golang-blockchain

require (
    github.com/AndreasBriese/bbloom v0.0.0-20180913140656-343706a395b7 // indirect
    github.com/dgraph-io/badger v1.5.4
    github.com/dgryski/go-farm v0.0.0-20180109070241-2de33835d102 // indirect
    github.com/golang/protobuf v1.2.0 // indirect
    github.com/pkg/errors v0.8.0 // indirect
    golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519 // indirect
)

 

part5: go.sum

github.com/AndreasBriese/bbloom v0.0.0-20180913140656-343706a395b7 h1:PqzgE6kAMi81xWQA2QIVxjWkFHptGgC547vchpUbtFo=
github.com/AndreasBriese/bbloom v0.0.0-20180913140656-343706a395b7/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8=
github.com/dgraph-io/badger v1.5.4 h1:gVTrpUTbbr/T24uvoCaqY2KSHfNLVGm0w+hbee2HMeg=
github.com/dgraph-io/badger v1.5.4/go.mod h1:VZxzAIRPHRVNRKRo6AXrX9BJegn6il06VMTZVJYCIjQ=
github.com/dgryski/go-farm v0.0.0-20180109070241-2de33835d102 h1:afESQBXJEnj3fu+34X//E8Wg3nEbMJxJkwSc0tPePK0=
github.com/dgryski/go-farm v0.0.0-20180109070241-2de33835d102/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519 h1:x6rhz8Y9CjbgQkccRGmELH6K+LJj7tOoh3XWeC1yaQM=
golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=

 

part6 : main.go

package main

import (
    "flag"
    "fmt"
    "os"
    "runtime"
    "strconv"

    "github.com/tensor-programming/golang-blockchain/blockchain"
)

type CommandLine struct {
    blockchain *blockchain.BlockChain
}

func (cli *CommandLine) printUsage() {
    fmt.Println("Usage:")
    fmt.Println(" add -block BLOCK_DATA - add a block to the chain")
    fmt.Println(" print - Prints the blocks in the chain")
}

func (cli *CommandLine) validateArgs() {
    if len(os.Args) < 2 {
        cli.printUsage()
        runtime.Goexit()
    }
}

func (cli *CommandLine) addBlock(data string) {
    cli.blockchain.AddBlock(data)
    fmt.Println("Added Block!")
}

func (cli *CommandLine) printChain() {
    iter := cli.blockchain.Iterator()

    for {
        block := iter.Next()

        fmt.Printf("Prev. hash: %x\n", block.PrevHash)
        fmt.Printf("Data: %s\n", block.Data)
        fmt.Printf("Hash: %x\n", block.Hash)
        pow := blockchain.NewProof(block)
        fmt.Printf("PoW: %s\n", strconv.FormatBool(pow.Validate()))
        fmt.Println()

        if len(block.PrevHash) == 0 {
            break
        }
    }
}

func (cli *CommandLine) run() {
    cli.validateArgs()

    addBlockCmd := flag.NewFlagSet("add", flag.ExitOnError)
    printChainCmd := flag.NewFlagSet("print", flag.ExitOnError)
    addBlockData := addBlockCmd.String("block", "", "Block data")

    switch os.Args[1] {
    case "add":
        err := addBlockCmd.Parse(os.Args[2:])
        blockchain.Handle(err)

    case "print":
        err := printChainCmd.Parse(os.Args[2:])
        blockchain.Handle(err)

    default:
        cli.printUsage()
        runtime.Goexit()
    }

    if addBlockCmd.Parsed() {
        if *addBlockData == "" {
            addBlockCmd.Usage()
            runtime.Goexit()
        }
        cli.addBlock(*addBlockData)
    }

    if printChainCmd.Parsed() {
        cli.printChain()
    }
}

func main() {
    //运行数据库
    defer os.Exit(0)

    // 获取最新的块信息
    chain := blockchain.InitBlockChain()

    //关闭数据库
    defer chain.Database.Close()

    cli := CommandLine{chain}
    cli.run()
}

 

运行创世块 go run main.go

2024/08/16 10:28:55 Replaying from value pointer: {Fid:0 Len:0 Offset:0}
2024/08/16 10:28:55 Iterating file id: 0
2024/08/16 10:28:55 Iteration took: 0s
No existing blockchain found
0000342dc11a9fd1833ed9fe18ca5627cedc56507de6698acfcafd301398cb35
Genesis proved

 

 

运行 添加第一个块 : go run main.go add -block "first block"   

2024/08/16 11:53:01 Replaying from value pointer: {Fid:0 Len:42 Offset:238}
2024/08/16 11:53:01 Iterating file id: 0
2024/08/16 11:53:01 Iteration took: 202.3µs
Added Block!

 

运行 添加第二个块 : go run main.go add -block "second block"   

2024/08/16 13:55:43 Replaying from value pointer: {Fid:0 Len:42 Offset:556}
2024/08/16 13:55:43 Iterating file id: 0
2024/08/16 13:55:43 Iteration took: 0s
000021de42633e4a04f12b135d0f96e5682e27f5f317439de74c6690adf04d92
Added Block!

 

运行 添加第三个块(fourth 是 第四个这里写错了) :go run main.go add -block "fourth block"

2024/08/16 15:15:21 Replaying from value pointer: {Fid:0 Len:42 Offset:875}
2024/08/16 15:15:21 Iterating file id: 0
2024/08/16 15:15:21 Iteration took: 0s
00000336d28b79a0fb309843141896107346f78165635b6e64c84efe3a670b0d
Added Block!

 

 

打印所有块 go run main.go print

2024/08/16 15:25:26 Replaying from value pointer: {Fid:0 Len:42 Offset:1194}
2024/08/16 15:25:26 Iterating file id: 0
2024/08/16 15:25:26 Iteration took: 0s
Prev. hash: 000021de42633e4a04f12b135d0f96e5682e27f5f317439de74c6690adf04d92
Data: fourth block
Hash: 00000336d28b79a0fb309843141896107346f78165635b6e64c84efe3a670b0d
PoW: true

Prev. hash: 00002c3afdd8f7ee21f4dc366c79e3408da23f583847e19bbdc5a25b7e151560
Data: second block
Hash: 000021de42633e4a04f12b135d0f96e5682e27f5f317439de74c6690adf04d92
PoW: true

Prev. hash: 0000342dc11a9fd1833ed9fe18ca5627cedc56507de6698acfcafd301398cb35
Data: first block
Hash: 00002c3afdd8f7ee21f4dc366c79e3408da23f583847e19bbdc5a25b7e151560
PoW: true

Prev. hash:
Data: Genesis
Hash: 0000342dc11a9fd1833ed9fe18ca5627cedc56507de6698acfcafd301398cb35
PoW: true

 

标签:err,编程,blockchain,golang,func,go,byte,区块,block
From: https://www.cnblogs.com/apenote/p/18362950

相关文章

  • 区块链技术的基本理论
    本文分享自天翼云开发者社区《区块链技术的基本理论》,作者:z****n2008年10月31日,“中本聪”首次提出数字加密货币的概念。2009年,第一枚加密数字货币——比特币诞生。区块链技术作为比特币的核心技术,凭借去中心化、公开透明、不可篡改的特点受到国内外各界人士的高度关注,将其应用于......
  • NVIDIA CUDA 编程模型之Grid和Block
    NVIDIACUDA编程模型允许灵活地配置grid和block,使程序能够在不同规模和结构上运行。CUDA中的grid可以是1、2或3维的,block也可以是1、2或3维的。这意味着存在多种可能的组合,每种组合都会影响最终线程的编号计算。下表展示了所有可能的grid和block组合,并描述了......
  • 小学生教你微积分,用编程理解高数(python,C,C++)
    一、代码实现微分(实际上是导数,微分不用除dx):python代码:x=0dx=0.00001deff(x):y=2*xreturnyprint((f(x+dx)-f(x))/dx)C语言代码:#include<stdio.h>doublex=1;doubledx=0.00001;doublef(doublearg){doubley=2*arg;returny;}......
  • 掌握Golang的html/template:打造动态网页的秘籍
    掌握Golang的html/template:打造动态网页的秘籍在Web开发的世界中,动态内容的生成是至关重要的。Golang以其简洁高效的特性,成为了后端开发的热门选择。而html/template包,则是Golang中用于创建HTML模板的官方工具,它不仅安全,而且功能强大。本文将带领你深入了解如何使用html/te......
  • 编程基础题:开关灯(C语言方式代码,C++方式代码,Python3方式编写)三种语言编写代码
    1.题目描述:假设有N蓋灯(N为不大于5000的正整数),从1到N按顺序依次编号,初始时全部处于开启状态;第一个人(1号)将灯全部关闭,第二个人(2号)将编号为2的倍数的灯打开,第三个人(3号)将编号为3的倍数的灯做相反处理(即,将打开的灯关闭,将关闭的灯打开)。依照编号递增顺序,以......
  • Python编程 - 基础知识
    前言一、常量与变量二、数据类型 三、标识符与关键字四、输出五、输入六、运算符总结前言本文正式开始介绍Python相关知识,主要有常量和变量、数据类型等,接下来咱们往下看一、常量与变量常量通俗的说就是固定不变的值,而变量就是可以变化的值,是一个用于存储......
  • libarchive库笔记:tar.gz格式压缩文件编程
    libarchive,一个支持多种格式的压缩和归档的C语言库,包含常见的tar、cpio和zcat命令行工具的实现。本文展示一个libarchive库C语言编程的tar.gz格式压缩文件示例。简单代码示例:#include<stdlib.h>#include<stdio.h>#include<string.h>#include<fcntl.h>#include"arch......
  • Python编程 - 判断语句与循环语句
    目录前言一、运算符二、判断语句三、循环语句总结前言第一篇主要讲的是较为基础的知识,如变量,关键字和输入输出等,接下来主要讲判断语句,将判断语句之前需要先扩展上篇文章中的运算符,运算符搭配判断语句使用,让我们拭目以待!!一、运算符这里拓展的运算符有比较运......
  • 高效记录并整理编程学习笔记:打造你的“知识宝库”
           ......
  • PHP 这么拉?长连接都搞不了?说说 PHP 的 socket 编程
    对PHP的误解颇深网络上似乎存在一种现象,一提到PHP人们的第一反应是简单且慢,这种简单甚至已经到了简陋的地步,比如不少人认为PHP无法独立创建一个服务,只能配合Apache或Nginx一起使用,而且PHP只能在处理完请求后销毁资源关闭进程,所以也无法处理长连接业务,这些都是对PHP......