主页 > 苹果imtoken钱包安装 > 从头开始用 golang 创建一个简单的区块链

从头开始用 golang 创建一个简单的区块链

苹果imtoken钱包安装 2023-02-16 07:27:43

区块链(Blockchain)是比特币的一个重要概念。 它本质上是一个去中心化的数据库。 同时,作为比特币的底层技术,它是一系列与密码学方法相关联的数据块。 每个数据块包含一批比特币网络交易信息,用于验证信息的有效性(防伪)和生成下一个块。 (百度百科)

区块链本身的结构非常简单,其复杂的部分在于其共识机制、加密等部分。 我们可以把区块链看成一种数据结构。 顾名思义,区块链就是把很多块(Block)链接在一起,形成一个链式结构(Chain)。 那么我们要做的也很简单一条比特币交易中可能包括的信息,就是先创建块,然后把它们连接起来。

1、分块建设

首先,需要确定要在块中存储什么。 由于我们只是想搭建一个基础的区块链,所以区块中的信息也比较简单。 我们在里面只存储了两个属性,前一个节点的哈希值(reviousHash)和交易信息(transaction)

type Block struct {
    previousHash string
    transaction  []string
}

为了计算哈希值,我们需要对Block结构进行序列化。 这里我选择使用protobuf,当然你也可以选择使用json或者直接转成[]byte。

在block包下新建一个pb包,然后新建一个block.proto文件。 里面要写的内容很简单,只有一个消息定义。

syntax="proto3";
package blockpb;
message Block{
    string previousHash = 1;
    repeated string transaction = 2;
}

然后接下来编译proto文件,会自动生成block.pb.go文件(不要忘记在等号后面打点)

protoc --go_out=. block.proto

通过block.pb.go,我们可以轻松计算出每个区块的哈希值。 首先一条比特币交易中可能包括的信息,编写一个将block转换为blockpb的方法。

//把block转化为blockpb
func ToProto(block *Block) proto.Message {
    return &blockpb.Block{
        PreviousHash: block.previousHash,
        Transaction:  block.transaction,
    }
}

接下来就是获取区块的哈希值,这部分也很简单

func GetHash(block *Block) string{
    serialBlock := ToProto(block)
    byteBlock, _ := proto.Marshal(serialBlock)

可能比特币_火币网如何交易比特币_一条比特币交易中可能包括的信息

hash := sha1.Sum(byteBlock) return hex.EncodeToString(hash[:]) }

至此,所有关于blocks的部分都结束了。 下一步就是如何将这些块串起来形成链式结构。

2.块的链接

我们创建的是一个非常简单的基础链,所以下面的操作都在main.go的main方法中进行。 显然,由于我们可以为每个节点计算一个哈希值,而且这个哈希值是唯一的。 那么我们就可以通过区块的哈希值来定位谁是这个区块的下一个节点,因为我们的每一个区块不仅包含交易信息,还保存了前一个区块的哈希值。

genesisBlock := block.CreateBlock("",[]string{"Hello","BlockChain","World"})

这个区块包含的交易信息是Hello Blockchain World。 当然,在实际的区块中,这里会存储一些有意义的信息,而不仅仅是一个随意的Hello World。

block1 := block.CreateBlock(block.GetHash(&genesisBlock),[]string{"first block"})
block2 := block.CreateBlock(block.GetHash(&block1),[]string{"second block"})
block3 := block.CreateBlock(block.GetHash(&block2),[]string{"third block"})

接下来我们把整个区块链的信息打印出来看看:

一条比特币交易中可能包括的信息_火币网如何交易比特币_可能比特币

如果我们修改创世块的信息,就变成了

genesisBlock := block.CreateBlock("",[]string{"Hello","Block","World"})

那么所有区块的哈希值都会发生很大的变化,这就是为什么很难在区块上作弊的原因。

火币网如何交易比特币_一条比特币交易中可能包括的信息_可能比特币

最后附上全部源码

package main
import (
    "block"
    "fmt"
)
func main(){
    genesisBlock := block.CreateBlock("",[]string{"Hello","Block","World"})
    block1 := block.CreateBlock(block.GetHash(&genesisBlock),[]string{"first block"})
    block2 := block.CreateBlock(block.GetHash(&block1),[]string{"second block"})

一条比特币交易中可能包括的信息_火币网如何交易比特币_可能比特币

block3 := block.CreateBlock(block.GetHash(&block2),[]string{"third block"}) fmt.Println("genesisBlock:",block.GetHash(&genesisBlock)) fmt.Println("block1 :",block.GetHash(&block1)) fmt.Println("block2 :",block.GetHash(&block2)) fmt.Println("block3 :",block.GetHash(&block3)) }

package block
import (
    "block/pb"
    "crypto/sha1"
    "encoding/hex"
    "github.com/gogo/protobuf/proto"
)
type Block struct {
    previousHash string
    transaction  []string
}
func CreateBlock(preHash string, trans []string) Block{
    b := Block{
        preHash,trans,
    }
    return b
}
func ToProto(block *Block) proto.Message {
    return &blockpb.Block{
        PreviousHash: block.previousHash,
        Transaction:  block.transaction,
    }

一条比特币交易中可能包括的信息_可能比特币_火币网如何交易比特币

} func GetHash(block *Block) string{ serialBlock := ToProto(block) byteBlock, _ := proto.Marshal(serialBlock) hash := sha1.Sum(byteBlock) return hex.EncodeToString(hash[:]) }

// Code generated by protoc-gen-go. DO NOT EDIT.
// source: block.proto
package blockpb
import (
    fmt "fmt"
    proto "github.com/golang/protobuf/proto"
    math "math"
)
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
type Block struct {
    PreviousHash         string   `protobuf:"bytes,1,opt,name=previousHash,proto3" json:"previousHash,omitempty"`
    Transaction          []string `protobuf:"bytes,2,rep,name=transaction,proto3" json:"transaction,omitempty"`

火币网如何交易比特币_一条比特币交易中可能包括的信息_可能比特币

XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` } func (m *Block) Reset() { *m = Block{} } func (m *Block) String() string { return proto.CompactTextString(m) } func (*Block) ProtoMessage() {} func (*Block) Descriptor() ([]byte, []int) { return fileDescriptor_8e550b1f5926e92d, []int{0} } func (m *Block) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_Block.Unmarshal(m, b) } func (m *Block) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return xxx_messageInfo_Block.Marshal(b, m, deterministic) } func (m *Block) XXX_Merge(src proto.Message) { xxx_messageInfo_Block.Merge(m, src) } func (m *Block) XXX_Size() int { return xxx_messageInfo_Block.Size(m) } func (m *Block) XXX_DiscardUnknown() { xxx_messageInfo_Block.DiscardUnknown(m) } var xxx_messageInfo_Block proto.InternalMessageInfo func (m *Block) GetPreviousHash() string { if m != nil { return m.PreviousHash }

可能比特币_一条比特币交易中可能包括的信息_火币网如何交易比特币

return "" } func (m *Block) GetTransaction() []string { if m != nil { return m.Transaction } return nil } func init() { proto.RegisterType((*Block)(nil), "blockpb.Block") } func init() { proto.RegisterFile("block.proto", fileDescriptor_8e550b1f5926e92d) } var fileDescriptor_8e550b1f5926e92d = []byte{ // 104 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0x4e, 0xca, 0xc9, 0x4f, 0xce, 0xd6, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x62, 0x07, 0x73, 0x0a, 0x92, 0x94, 0x7c, 0xb9, 0x58, 0x9d, 0x40, 0x4c, 0x21, 0x25, 0x2e, 0x9e, 0x82, 0xa2, 0xd4, 0xb2, 0xcc, 0xfc, 0xd2, 0x62, 0x8f, 0xc4, 0xe2, 0x0c, 0x09, 0x46, 0x05, 0x46, 0x0d, 0xce, 0x20, 0x14, 0x31, 0x21, 0x05, 0x2e, 0xee, 0x92, 0xa2, 0xc4, 0xbc, 0xe2, 0xc4, 0xe4, 0x92, 0xcc, 0xfc, 0x3c, 0x09, 0x26, 0x05, 0x66, 0x0d, 0xce, 0x20, 0x64, 0xa1, 0x24, 0x36, 0xb0, 0xf1, 0xc6, 0x80, 0x00, 0x00, 0x00, 0xff, 0xff, 0x68, 0x7e, 0xfd, 0x82, 0x6d, 0x00, 0x00, 0x00, }

syntax="proto3";
package blockpb;
message Block{
    string previousHash = 1;
    repeated string transaction = 2;
}