主页 > imtoken转账需要验证码 > 比特币原理第一讲——区块结构

比特币原理第一讲——区块结构

imtoken转账需要验证码 2023-08-03 05:07:03

## 介绍

区块链是 21 世纪最具革命性的技术之一,仍处于成长阶段,还有很多潜力有待实现。 本质上,区块链只是一个分布式数据库。 不过,它的独特之处在于,区块链是一个公共数据库而不是私有数据库,也就是说,每个使用它的人都有一份完整或部分的副本。 只有在其他“数据库管理员”同意的情况下,才能将新记录添加到数据库中。 此外,也正是由于区块链,加密货币和智能合约才成为现实。

在本系列文章中,我们将实现一个简化版的区块链,并以此为基础构建一个简化版的加密货币。

##块

先说“块”。 在区块链中,真正存储有效信息的是区块。 在比特币中,真正有价值的信息是交易。 事实上,交易信息是所有加密货币的价值。 除此之外,区块还包含一些与技术实现相关的信息,例如版本、当前时间戳和前一个区块的哈希值。

但是,我们要实现的是一个简化版的区块链,而不是比特币技术规范中描述的成熟完整的区块链。 所以在我们目前的实现中,block只包含了一些关键信息,其数据结构如下:


type Block struct {
Timestamp  int64
Data []byte
PrevBlockHash []byte
Hash []byte
}

领域 | 解释

:----: | :----

时间戳 | 当前时间戳,也就是区块创建的时间

上一个区块哈希 | 前一个块的哈希,即父哈希

散列 | 当前区块的哈希

资料 | 区块中存储的实际有效信息,即交易

这里的Timestamp、PrevBlockHash、Hash在比特币技术规范中属于区块头,区块头是一个单独的数据结构。

完整的比特币区块头(block header)结构如下:

领域 | 目的 | 更新时... | 大小(字节)

:---- | :---- | :---- | :----

版本 | 块版本号 | 您升级软件,它指定了一个新版本 | 4个

hashPrevBlock | 前一个区块头的 256 位哈希 | 一个新区块进来了 | 32

哈希MerkleRoot | 基于区块中所有交易的 256 位哈希 | 交易被接受 | 32

时间 | 当前时间戳,自 1970-01-01T00:00 UTC 以来的秒数 | 每隔几秒 | 4个

位| 紧凑格式的当前目标 | 难度调整 | 4个

随机数 | 32 位数字(从 0 开始) | 尝试哈希(增量)| 4个

下面是比特币的golang实现btcd的定义:


// BlockHeader defines information about a block and is used in the bitcoin
// block (MsgBlock) and headers (MsgHeaders) messages.

比特币历史价格非小号_比特币价框结构_比特币分叉会影响比特币价格吗

type BlockHeader struct { // Version of the block. This is not the same as the protocol version. Version int32 // Hash of the previous block in the block chain. PrevBlock chainhash.Hash // Merkle tree reference to hash of all transactions for the block. MerkleRoot chainhash.Hash // Time the block was created. This is, unfortunately, encoded as a // uint32 on the wire and therefore is limited to 2106. Timestamp time.Time // Difficulty target for the block. Bits uint32 // Nonce used to generate the block. Nonce uint32 }

而我们的数据,对应于比特币的交易,是另一个独立的数据结构。 为简洁起见比特币价框结构,现在将这两个数据结构组合在一起。 在真实的比特币中,其数据结构如下:

领域 | 说明 |

:---- | :---- | :----

魔术没有 | 值始终为 0xD9B4BEF9 | 4字节

块大小 | 块结束后的字节数 | 4字节

区块头 | 由 6 项组成 | 80字节

交易柜台 | 正整数 VI = VarInt | 1 - 9 字节

交易 | 交易列表(非空)| -许多交易

在我们简化版的区块中,也有一个Hash字段,那么如何计算hash呢? 哈希计算是区块链中非常重要的一环。 正因为如此,区块链的安全性才有了保障。 计算散列是计算上非常困难的操作。 即使在高速计算机上,也需要花费大量时间(这就是人们购买 GPU、FPGA、ASIC 来挖掘比特币的原因)。 这是一种架构设计,故意让添加新块变得困难,然后确保一旦添加了一个块,就很难修改它。 在接下来的内容中,我们将讨论并实现这一机制。

目前我们只是取Block结构的一些字段(Timestamp、Data和PrevBlockHash)比特币价框结构,将它们拼接在一起,然后在拼接的结果上计算一个SHA-256,然后得到hash。

比特币价框结构_比特币分叉会影响比特币价格吗_比特币历史价格非小号


Hash = SHA256(PrevBlockHash + Timestamp + Data)

在 SetHash 方法中执行此操作:


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[:]
}

接下来,按照Golang的约定,我们将实现一个函数NewBlock来简化出块过程:


func NewBlock(data string, prevBlockHash []byte) *Block {
block := &Block{time.Now().Unix(), []byte(data), prevBlockHash, []byte{}}
block.SetHash()
return block
}

## 区块链

有了区块,我们来实现区块***********chain********。 本质上,区块链是一个具有特定结构的数据库,一个有序的链表,其中每个块都连接到前一个块。 也就是说,块按插入顺序存储,每个块都连接到前一个块。 这样的结构可以让我们快速获取链上的最新区块,通过哈希高效的检索出一个区块。

在Golang中,这个结构可以通过一个array和map来实现:array存储有序的hash(在Golang中array是有序的),map存储****hash -> block****对(在Golang中,map是无序的) . 但是在基本的原型阶段,我们只使用数组,因为还没有必要通过哈希得到块。


type Blockchain struct {
blocks []*Block
}

比特币价框结构_比特币历史价格非小号_比特币分叉会影响比特币价格吗

这就是我们的第一个区块链! 是不是出奇的简单? 它只是一组块。

现在,让我们给它添加一个块:


func (bc *Blockchain) AddBlock(data string) {
prevBlock := bc.blocks[len(bc.blocks)-1]
newBlock := NewBlock(data, prevBlock.Hash)
bc.blocks = append(bc.blocks, newBlock)
}

结束! 但这就是全部吗?

为了添加一个新块,我们必须有一个现有块,但是,在初始状态下,我们的链是空的,没有块! 因此,在任何区块链中,都必须至少有一个区块。 这个块,链中的第一个块,通常被称为创世块(**genesis block****)。 让我们实现一个创建创世块的方法:


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

现在,我们可以实现一个函数来创建带有创世块的区块链:


func NewBlockchain() *Blockchain {
return &Blockchain{[]*Block{NewGenesisBlock()}}
}

检查我们的区块链之一是否按预期工作:


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() } }

输出:


Prev. hash:
Data: Genesis Block
Hash: aff955a50dc6cd2abfe81b8849eab15f99ed1dc333d38487024223b5fe0f1168
Prev. hash: aff955a50dc6cd2abfe81b8849eab15f99ed1dc333d38487024223b5fe0f1168
Data: Send 1 BTC to Ivan
Hash: d75ce22a840abb9b4e8fc3b60767c4ba3f46a0432d3ea15b71aef9fde6a314e1
Prev. hash: d75ce22a840abb9b4e8fc3b60767c4ba3f46a0432d3ea15b71aef9fde6a314e1
Data: Send 2 more BTC to Ivan
Hash: 561237522bb7fcfbccbc6fe0e98bbbde7427ffe01c6fb223f7562288ca2295d1

##总结

比特币历史价格非小号_比特币价框结构_比特币分叉会影响比特币价格吗

我们创建了一个非常简单的区块链原型:它只是一个区块数组,每个区块都链接到前一个区块。 真正的区块链比这复杂得多。 在我们的区块链中,添加新区块非常简单快速,但在真正的区块链中,添加新区块需要大量的工作:你必须经过非常繁重的计算(这种机制称为工作量证明),才能获得权利添加一个新块。 此外,区块链是一个分布式数据库,没有单一的决策者。 因此,要添加一个新区块,必须得到网络中其他参与者的确认和同意(这种机制称为共识)。 还有一件事,我们的区块链还没有任何交易!

进入src目录查看代码,执行make运行:


$ cd src
$ make
==> Go build
==> Running
Prev. hash:
Data: Genesis Block
Hash: 4693b71eee96760de4b0f051083376dcbed2f0711a44294ee5fd42fbeacc9579
Prev. hash: 4693b71eee96760de4b0f051083376dcbed2f0711a44294ee5fd42fbeacc9579
Data: Send 1 BTC to Ivan
Hash: 839380a2d0af1dc4686f16ade5423fecdc5f287db9322d9e18adcb4071e7c8ff
Prev. hash: 839380a2d0af1dc4686f16ade5423fecdc5f287db9322d9e18adcb4071e7c8ff
Data: Send 2 more BTC to Ivan
Hash: b38052a029bd2b1b9d4bb478af45b4c88605e99bc64e49031ba06d21ad4b0b38

参考:

[1] 区块哈希算法

[2] 在 Go 中构建区块链。 第 1 部分:基本原型

比特币维基的区块结构:

领域 | 说明 |

:----: | :----: | :----:

魔术没有 | 值始终为 0xD9B4BEF9 | 4字节

块大小 | 块结束后的字节数 | 4字节

区块头 | 由 6 项组成 | 80字节

交易 | 计数器正整数 VI = VarInt | 1 - 9 字节

交易 | 交易列表(非空)| -许多交易

配套项目地址: