当前位置:首页 » 《关注互联网》 » 正文

基于指针数组实现简单的区块链 day(1)_初心魏的博客

20 人参与  2022年01月20日 11:43  分类 : 《关注互联网》  评论

点击全文阅读


基于指针数组实现简单的区块链 day(1)

  • 一、比特币的基础知识
    • 1.1 比特币
    • 1.2 区块
    • 1.3 区块链
    • 1.4 记账
    • 1. 5 钱包
    • 1.6 节点
    • 1.7 挖矿
    • 1.8出块时间
    • 1.9 出块奖励
    • 1.10 比特币总量
    • 1.11 区块容量
    • 1.12 每秒成交量
    • 1.13 单位
  • 二、其他基础知识
    • 2.1 挖矿(工作量证明)
    • 2.2 go演示挖矿
    • 2.3 地址生成规则
    • 2.4 base64
    • 2.5 交易
  • 三、模拟简单的区块链
    • 3.1 创建简单的区块
    • 3.2 创建简单的区块链
    • 3.3 创建创世块
    • 3.4 向区块链中添加区块
  • 四、模拟复杂的区块链
    • 4.1 将unit64转换成byte类型
    • 4.2 bytes.Join()
    • 4.3 挖矿演示
  • 五、git命令
    • 5.1 git pull
    • 5.2 git push
    • 5.3 git push --set-upstream origin v2

一、比特币的基础知识

1.1 比特币

一个软件系统,每个人都可以下载使用,使用者之间不断进行交易,产生数据

1.2 区块

比特币系统使用者之间交易的数据以数据块的形式存储,最终存储在数据库中,这个包含交易数据的数据块我们称之为区块。

1.3 区块链

保存上述所有区块的数据库我们称之为区块链。

1.4 记账

将系统中的交易数据写到数据库中我们称之为记账

1. 5 钱包

  • 创建私钥公钥,保存公钥,相当于钱包,可以存放多个地址
  • 地址类似银行卡,私钥类似银行卡密码
  • 钱包会便利账本的交易信息,来得知有没有钱
  • 一个地址对应一个私钥

1.6 节点

每一个运行区块链挖矿软件的人都会便成为一个区块链网络的节点。

1.7 挖矿

节点之间竞争记账的权利就称之为挖矿。

1.8出块时间

大约10分钟出一个比特币

1.9 出块奖励

1.10 比特币总量

1.11 区块容量

1M大约容纳4000笔交易

1.12 每秒成交量

1.13 单位

sat(聪)

二、其他基础知识

2.1 挖矿(工作量证明)

sha256(区块数据+随机数据)<目标的哈希值

2.2 go演示挖矿

import (
	"crypto/sha256"
	"fmt"
)

func main(){
	data := "helloWord"
	for i:=0; i < 100; i++{
		res := sha256.Sum256([]byte(data + string(i)))
		fmt.Printf("%x", res[:])
		fmt.Println()
	}
}

2.3 地址生成规则

私钥经过椭圆曲线相乘生成公钥,在通过哈希算法得到比特币地址。

2.4 base64

0-9,a-z,A-Z,+,-

2.5 交易

  • 挖矿交易
  • 普通交易

三、模拟简单的区块链

3.1 创建简单的区块


type Block struct{
	PreBlockHash []byte
	Hash []byte
	Data []byte
}
//创建block
func createBlock(preBlockHash []byte, data string) *Block{
	block := Block{
		PreBlockHash: preBlockHash,
		Data: []byte(data),
		Hash: []byte{},
	}
	block.SetHash()
	return &block
}

// SetHash 计算当前区块的hash
func (block *Block)SetHash(){
	//...的作用是把data数组打散,一个个装进preBlockHash切片中
     blockInfo := append(block.PreBlockHash,block.Data...)
	 //hash是一个字节数组
	 Hash := sha256.Sum256(blockInfo)
	 //block.Hash作为Hash的切片
	 block.Hash = Hash[:]
}
func main() {
	//创建一个区块
	var block *Block = createBlock([]byte{}, "第一个区块")
	fmt.Printf("上一区块的hash值%x:",block.PreBlockHash)
	fmt.Println()
	fmt.Printf("当前区块的hash值%x:",block.Hash)
	fmt.Println()
	fmt.Println("当前区块的数据",string(block.Data))

}

结果:
前面区块的hash值 []
当前区块的hash值328fffe02f9e57c15508352cb145aa68abcf83da69a059e975d2171b1e7f8f92
当前区块的数据 第一个区块

3.2 创建简单的区块链

  • 本质上是用一个区块指针类型的数组构成的区块链
// BlockChain 区块链结构体
//本质上是区块指针类型的数组
type BlockChain struct {
	blockChain []*Block
}
// CreateBlockChain 创建带有一个创世块的区块链
func CreateBlockChain() *BlockChain{
	blockChain := BlockChain{
		blockChain: []*Block{GenesisBlock()},
	}
	return &blockChain
}

3.3 创建创世块

// GenesisBlock 创建创世块,即第一个区块
func GenesisBlock() *Block{
	genesisBlock := CreateBlock([]byte{},"第一个创世块,牛逼")
	return genesisBlock
}

3.4 向区块链中添加区块

// AddBlock 当前区块的前一区块哈希值字段从区块链中获取
func (bc *BlockChain)AddBlock(data string){
	preHash := bc.blockChain[len(bc.blockChain)-1].Hash
	block := CreateBlock(preHash, data)
	bc.blockChain = append(bc.blockChain, block)
}

四、模拟复杂的区块链

4.1 将unit64转换成byte类型

// Uint64ConvertByte 将uint64类型转换为[]byte{}类型
func Uint64ConvertByte(data uint64)[]byte{
	var buffer bytes.Buffer
	err := binary.Write(&buffer, binary.BigEndian,data)
	if err != nil {
		log.Panicln(err)
	}
	return buffer.Bytes()
}

4.2 bytes.Join()

  • 将二维byte数组连接成一个一维byte数组
func (block *Block)SetHash(){
	var blockInfo []byte
	//...的作用是把data数组打散,一个个装进preBlockHash切片中
	//blockInfo = append(blockInfo, Uint64ConvertByte(block.Version)...)
	//blockInfo = append(blockInfo, block.PreBlockHash...)
	//blockInfo = append(blockInfo, block.MerkelRoot...)
	//blockInfo = append(blockInfo, Uint64ConvertByte(block.TimeStamp)...)
	//blockInfo = append(blockInfo, Uint64ConvertByte(block.Difficulty)...)
	//blockInfo = append(blockInfo, Uint64ConvertByte(block.Nonce)...)
	//blockInfo = append(blockInfo, block.Data...)
	// 创建一个二维数组
	tem := [][]byte{
		Uint64ConvertByte(block.Version),
		block.PreBlockHash,
		block.MerkelRoot,
		Uint64ConvertByte(block.TimeStamp),
		Uint64ConvertByte(block.Difficulty),
		Uint64ConvertByte(block.Nonce),
		block.Data,
	}
	//将二维byte数组连接成一维byte数组
	bytes.Join(tem, []byte{})
	//hash是一个字节数组
	Hash := sha256.Sum256(blockInfo)
	//block.Hash作为Hash的切片
	block.Hash = Hash[:]
}

4.3 挖矿演示

type ProofOfWork struct {
	block *Block
	target *big.Int
}
//CreatePOW 创建ProofOfWork
func CreatePOW(block *Block) *ProofOfWork{
	pow := ProofOfWork{
		block: block,
	}
	target :=  "0000100000000000000000000000000000000000000000000000000000000000"
	bigNum := big.Int{}
	//res是指针类型的
	res, _ := bigNum.SetString(target, 16)
	pow.target = res
    return &pow
}
//Run 返回一个Hash值和随机数
func (pow *ProofOfWork) Run()([]byte, uint64){
	tmpBigInt := &big.Int{}
	//与给定的目标哈希值进行比较,小于则挖矿成功
	var nonce uint64 = 0
	var hash [32]byte
	for{
		block := pow.block
		tem := [][]byte{
			Uint64ConvertByte(block.Version),
			block.PreBlockHash,
			block.MerkelRoot,
			Uint64ConvertByte(block.TimeStamp),
			Uint64ConvertByte(block.Difficulty),
			Uint64ConvertByte(nonce),
			block.Data,
		}
		// blockInfo 拼装好的数据
		blockInfo := bytes.Join(tem, []byte(""))
		hash = sha256.Sum256(blockInfo)
		tmpBigInt.SetBytes(hash[:])
		res := tmpBigInt.Cmp(pow.target)
		if res == -1{
			break
		}
		nonce ++
	}
   return hash[:],nonce
}

五、git命令

5.1 git pull

将远程主机 origin 的 master 分支拉取过来,与本地的 brantest 分支合并。

git pull origin master:brantest

5.2 git push

git push 命用于从将本地的分支版本上传到远程并合并。

命令格式如下:

git push <远程主机名> <本地分支名>:<远程分支名>

如果本地分支名与远程分支名相同,则可以省略冒号:

git push <远程主机名> <本地分支名>

5.3 git push --set-upstream origin v2

  • 设置本地分支追踪远程分支

点击全文阅读


本文链接:http://m.zhangshiyu.com/post/33600.html

区块  数组  挖矿  
<< 上一篇 下一篇 >>

  • 评论(0)
  • 赞助本站

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

关于我们 | 我要投稿 | 免责申明

Copyright © 2020-2022 ZhangShiYu.com Rights Reserved.豫ICP备2022013469号-1