当前位置: 首页 > article >正文

基于golang语言开发publicChain项目实战教程

概述:简易公链
任何公链只要涉及转账都会用到UTXO,UTXO并不是面向对象的思维,通过计算如何去打包多笔交易,各种加密算法,钱包 如何生成地址,节点A,节点B,节点C,节点分全节点,钱包节点,还有就是矿池里面的一种节点,钱包节点不需要挖矿功能,钱包节点的功能:1)创建钱包,2) 能够去进行转账,3)能够去查询余额
其他全节点:可以进行挖矿处理
节点与节点之间的区别:
节点A如何往节点B转账,转账完毕后,节点与节点之间如何去数据同步,任何让节点与节点之间实现一致性协议,包括P2P协议,如何往里面集成引擎,能够在引擎里面部署简单的合约,整个教程结束以后,实际上就是一个简易的公链项目。内容比较多,前面简单,后面很难,UTXO难度比较高。
先手动计算转账,再写代码,POW经过权益证明改造为POS以后,就不需要挖矿了。
1,区块-区块链概述
区块里面他会存储上一个区块的Hash,这样整个区块全链接在一起,就产生了区块链(整个区块在一起可以组成一个区块链) 比如block,我们会将他序列化为字节数组,序列化以后我们会把区块存储到区块链,比如有五个区块,我们会把每一个区块序列化以后将他们存储到区块链里面,接下来如果我想去遍历整个区块的话,在我们整个区块链里面除了存储区块以外,我们还要存储最后一个区块里面的Hash,为什么要存储最后一个区块的Hash,因为只有找到最后一个区块的Hash,才能通过反向遍历,去迭代,最终能够拿到创世区块,拿到我们所有区块的数据,所以区块链当中数据库里面存储的时候,他首先是把每一个区块的block的结构体序列化,将所有区块序列化,刚开始是一个block对象,这个对象里面有区块的高度,时间戳,有交易数据,还有Nonce值,有所有数据,你不能直接将block塞进数据库里面,你需要把block转换成一个字节数组,将整个字节数组把他存储到区块链里面,如果我们要去取出区块,该如何操作。以键值对(key-value)的形式存储,将Hash作为Key,将整个区块序列化,序列化以后将字节数组作为value值存储到区块链里面,我们去取数据时,只需要拿到Hash,就可以拿到block区块里面的字节数组。接下来将字节数组序列化成为对象,拿出来就可以了。
生成时间戳的方法:time.Now().Unix() 以秒为单位 的整数时间

1,part1 创建区块

创建区块
1,BLC/utils.go
package BLCimport ("bytes""encoding/binary""log"
)
// 将 int64 转换为 字节数组
func IntToHex(num int64) []byte {buff := new(bytes.Buffer)err := binary.Write(buff,binary.BigEndian,num)if err != nil {log.Panic(err)}return buff.Bytes()
}2,BLC/Block.go
package BLCimport ("bytes""crypto/sha256""strconv""time"
)// 定义区块
type Block struct { // 定义属性// 1, 区块高度 第几个区块Height int64// 2,上一个区块的HASH 父HashPrevBlockHash []byte// 3, 交易数据 DataData []byte// 4, 时间戳 创建区块时的时间Timestamp int64// 5,Hash 当前区块的Hash  动态Hash值Hash []byte
}// 哈希
func (block *Block) SetHash() {// 1, 将 Height 转换为字节数组 []byteheightBytes := IntToHex(block.Height)// fmt.Println("height", heightBytes)// 2, 将 时间戳 转换为字节数组 []byte// (1) 将 时间戳 转换为 字符串timeString := strconv.FormatInt(block.Timestamp, 2)// fmt.Println(timeString)// (2) 再将 字符串 转换为 字节数组timeBytes := []byte(timeString)// fmt.Println("time", timeBytes)// 3, 拼接所有属性blockBytes := bytes.Join([][]byte{heightBytes, block.PrevBlockHash, block.Data, timeBytes, block.Hash}, []byte{})// 4, 将 拼接的字节数组 生成 哈希  因为返回32个字节的固定大小的字节数组,所以不能直接把他赋值跟Hash,因为Hash是一个动态值 Hash表示当前哈希hash := sha256.Sum256(blockBytes)// 5, 将 hash 赋值给 Hash 属性字节 [:] 表示取哈希前后所有值 这就是区块链精髓所在点block.Hash = hash[:]
}// 创建新的区块
func NewBlock(data string, heigh int64, prevBlockHash []byte) *Block {// 创建区块block := &Block{heigh, prevBlockHash, []byte(data), time.Now().Unix(), nil}// 设置哈希block.SetHash()return block
}3, part1-Basic-Prototype/main.go
package mainimport ("fmt""project/publicChain/part1-Basic-Prototype/BLC"
)func main() {block := BLC.NewBlock("Genesis Block", 1, []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0})fmt.Println(block)
}asic   1->49 0->48
height [0 0 0 0 0 0 0 1]1100111101000101101010010000010  // 二进制的字符串 
time [49 49 48 48 49 49 49 49 48 49 48 48 48 49 48 49 49 48 49 48 49 48 48 49 48 48 48 48 48 49 48]  // 二进制字符串对应的字节数组
&{1 [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] [71 101 110 101 115 105 115 32 66 108 111 99 107] 1738724482 []}进程 已完成,退出代码为 0运行 main.go文件,返回如下参数:以下返回的参数是整个区块链的一个结构&{1 [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] [71 101 110 101 115 105 115 32 66 108 111 99 107] 1738728641 [228 126 233 225 103 67 141 157 6 42 40 162 222 227 34 211 160 221 9 9 6 137 121 191 15 164 181 178 140 242 227 221]}返回如下参数详解:以下返回的参数是整个区块链的一个结构
区块高度:1
上一个区块的Hash值: [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
Data: [71 101 110 101 115 105 115 32 66 108 111 99 107]
时间戳: 1738728641
下一个区块的Hash值: [228 126 233 225 103 67 141 157 6 42 40 162 222 227 34 211 160 221 9 9 6 137 121 191 15 164 181 178 140 242 227 221]
进程 已完成,退出代码为 0PS part1-Basic-Prototype> go run main.go
&{1 [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] [71 101 110 101 115 105 115 32 66 108 111 99 107] 1739872644 [195 72 21 223 105 114 2 93 207 22 186 125 124 246 88 161 164 2 81 221 54 111 20 63 115 101 95 217 61 78 153 101] 0}// 返回的是一个区块的结构体
&{1 [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] [71 101 110 101 115 105 115 32 66 108 111 99 107] 1739912790 [87 132 86 78 128 123 105 45 
118 242 57 12 30 52 112 117 158 121 231 191 243 218 95 37 22 219 227 126 143 103 38 186]}
区块的高度:1
创世区块hash:[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
交易数据:[71 101 110 101 115 105 115 32 66 108 111 99 107]
时间戳:1739912790
当前区块的hash:[87 132 86 78 128 123 105 45 
118 242 57 12 30 52 112 117 158 121 231 191 243 218 95 37 22 219 227 126 143 103 38 186]

2, part2 创建创世区块

创世区块
1, part2-Basic-Prototype/BLC/Block.go
package BLCimport ("bytes""crypto/sha256""strconv""time"
)// 定义区块
type Block struct { // 定义属性// 1, 区块高度 第几个区块Height int64// 2,上一个区块的HASH 父HashPrevBlockHash []byte// 3, 交易数据 DataData []byte// 4, 时间戳 创建区块时的时间Timestamp int64// 5,Hash 当前区块的Hash  动态Hash值Hash []byte
}// 哈希
func (block *Block) SetHash() {// 1, 将 Height 转换为字节数组 []byteheightBytes := IntToHex(block.Height)// fmt.Println("height", heightBytes)// 2, 将 时间戳 转换为字节数组 []byte// (1) 将 时间戳 转换为 字符串timeString := strconv.FormatInt(block.Timestamp, 2)// fmt.Println(timeString)// (2) 再将 字符串 转换为 字节数组timeBytes := []byte(timeString)// fmt.Println("time", timeBytes)// 3, 拼接所有属性blockBytes := bytes.Join([][]byte{heightBytes, block.PrevBlockHash, block.Data, timeBytes, block.Hash}, []byte{})// 4, 将 拼接的字节数组 生成 哈希  因为返回32个字节的固定大小的字节数组,所以不能直接把他赋值跟Hash,因为Hash是一个动态值 Hash表示当前哈希hash := sha256.Sum256(blockBytes)// 5, 将 hash 赋值给 Hash 属性字节 [:] 表示取哈希前后所有值 这就是区块链精髓所在点block.Hash = hash[:]
}// 创建新的区块
func NewBlock(data string, heigh int64, prevBlockHash []byte) *Block {// 创建区块block := &Block{heigh, prevBlockHash, []byte(data), time.Now().Unix(), nil}// 设置哈希block.SetHash()return block
}// 2, 单独写一个方法,生成创世区块
func CreateGenesisBlock(data string) *Block {return NewBlock(data, 1, []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0})}2, part2-Basic-Prototype/BLC/utils.go
package BLCimport ("bytes""encoding/binary""log"
)// 将 int64 转换为 字节数组
func IntToHex(num int64) []byte {buff := new(bytes.Buffer)err := binary.Write(buff, binary.BigEndian, num)if err != nil {log.Panic(err)}return buff.Bytes()
}3, part2-Basic-Prototype/main.go
package mainimport ("fmt""project/publicChain/part2-Basic-Prototype/BLC"
)func main() {genesisBlock := BLC.CreateGenesisBlock("Genesis Block......")fmt.Println(genesisBlock)
}&{1 [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] [71 101 110 101 115 105 115 32 66 108 111 99 107 46 46 46 46 46 46] 1738731049 [27 186 85 84 247 247 123 8 31 99 170 142 186 17 159 21 24 246 219 101 226 204 86 94 97 250 31 200 14 117 215 143]}进程 已完成,退出代码为 0

3, part3 创建带有创世区块的区块链

​
创建带有创世区块的区块链 
1, part3-Basic-Prototype/BLC/Block.go
package BLC// 定义区块链结构体
type Blockchain struct {// 存储有序的区块Blocks []*Block
}// 创建带有创世区块的区块链
func CreateBlockchainWithGenesisBlock() *Blockchain {// 1,创建创世区块genesisBlock := CreateGenesisBlock("Genesis Block Data......")// 2, 返回区块链对象return &Blockchain{[]*Block{genesisBlock}}
}2, part3-Basic-Prototype/main.go
package mainimport ("fmt""project/publicChain/part3-Basic-Prototype/BLC"
)func main() {genesisBlockchain := BLC.CreateBlockchainWithGenesisBlock()// 打印区块链fmt.Println(genesisBlockchain)// 打印区块fmt.Println(genesisBlockchain.Blocks)// 打印区块链中的第一个区块fmt.Println(genesisBlockchain.Blocks[0])
}3, part3-Basic-Prototype/BLC/utils.go
package BLCimport ("bytes""encoding/binary""log"
)// 将 int64 转换为 字节数组
func IntToHex(num int64) []byte {buff := new(bytes.Buffer)err := binary.Write(buff, binary.BigEndian, num)if err != nil {log.Panic(err)}return buff.Bytes()
}执行结果:返回如下参数&{[0xc00006c0c0]}
[0xc00006c0c0]返回如下参数详解:
&{[0xc00006c0c0]} // 返回一个对象,对象里面有一个数组 代表的是创世区块的地址​返回如下参数详解:
// 打印区块链
&{[0xc0000b8000]}
// 打印区块
[0xc0000b8000]
// 打印区块链中第一个区块,数据如下:创世区块的区块链信息
&{1 [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] [71 101 110 101 115 105 115 32 66 108 111 99 107 32 68 97 116 97 46 46 46 46 46 46] 1738740994 [141 16 87 52 179 89 173 191 239 97 129 217 78 134 97 224 76 202 90 248 130 18 214 63 219 95 95 121 3 68 235 10]}进程 已完成,退出代码为 0

4, part4 添加新的区块

1, part4-Basic-Prototype/BLC/Block.go
package BLCimport ("bytes""crypto/sha256""strconv""time"
)// 定义区块
type Block struct { // 定义属性// 1, 区块高度 第几个区块Height int64// 2,上一个区块的HASH 父HashPrevBlockHash []byte// 3, 交易数据 DataData []byte// 4, 时间戳 创建区块时的时间Timestamp int64// 5,Hash 当前区块的Hash  动态Hash值Hash []byte
}// 哈希
func (block *Block) SetHash() {// 1, 将 Height 转换为字节数组 []byteheightBytes := IntToHex(block.Height)// fmt.Println("height", heightBytes)// 2, 将 时间戳 转换为字节数组 []byte// (1) 将 时间戳 转换为 字符串timeString := strconv.FormatInt(block.Timestamp, 2)// fmt.Println(timeString)// (2) 再将 字符串 转换为 字节数组timeBytes := []byte(timeString)// fmt.Println("time", timeBytes)// 3, 拼接所有属性blockBytes := bytes.Join([][]byte{heightBytes, block.PrevBlockHash, block.Data, timeBytes, block.Hash}, []byte{})// 4, 将 拼接的字节数组 生成 哈希  因为返回32个字节的固定大小的字节数组,所以不能直接把他赋值跟Hash,因为Hash是一个动态值 Hash表示当前哈希hash := sha256.Sum256(blockBytes)// 5, 将 hash 赋值给 Hash 属性字节 [:] 表示取哈希前后所有值 这就是区块链精髓所在点block.Hash = hash[:]
}// 创建新的区块
func NewBlock(data string, heigh int64, prevBlockHash []byte) *Block {// 创建区块block := &Block{heigh, prevBlockHash, []byte(data), time.Now().Unix(), nil}// 设置哈希block.SetHash()return block
}// 2, 单独写一个方法,生成创世区块
func CreateGenesisBlock(data string) *Block {return NewBlock(data, 1, []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0})}2, part4-Basic-Prototype/BLC/Blockchain.go
package BLC// 定义区块链结构体
type Blockchain struct {// 存储有序的区块Blocks []*Block
}// 增加区块到区块链中
func (blockchain *Blockchain) AddBlockToBlockchain(data string, height int64, prevHash []byte) {// 创建新区块newBlock := NewBlock(data, height, prevHash)// 向区块链中添加新区块blockchain.Blocks = append(blockchain.Blocks, newBlock)
}// 创建带有创世区块的区块链
func CreateBlockchainWithGenesisBlock() *Blockchain {// 1,创建创世区块genesisBlock := CreateGenesisBlock("Genesis Block Data......")// 2, 返回区块链对象return &Blockchain{[]*Block{genesisBlock}}
}3, part4-Basic-Prototype/BLC/utils.go
package BLCimport ("bytes""encoding/binary""log"
)// 将 int64 转换为 字节数组
func IntToHex(num int64) []byte {buff := new(bytes.Buffer)err := binary.Write(buff, binary.BigEndian, num)if err != nil {log.Panic(err)}return buff.Bytes()
}4, part4-Basic-Prototype/main.go
package mainimport ("fmt""project/publicChain/part4-Basic-Prototype/BLC"
)func main() {// 1, 创建创世区块blockchain := BLC.CreateBlockchainWithGenesisBlock()// 2, 创建新区块 AddBlockToBlockchainblockchain.AddBlockToBlockchain("Send 100RMB To zhangqiang", blockchain.Blocks[len(blockchain.Blocks)-1].Height+1, blockchain.Blocks[len(blockchain.Blocks)-1].Hash)blockchain.AddBlockToBlockchain("Send 200RMB To changjingkong", blockchain.Blocks[len(blockchain.Blocks)-1].Height+1, blockchain.Blocks[len(blockchain.Blocks)-1].Hash)blockchain.AddBlockToBlockchain("Send 300RMB To zengguoqing", blockchain.Blocks[len(blockchain.Blocks)-1].Height+1, blockchain.Blocks[len(blockchain.Blocks)-1].Hash)blockchain.AddBlockToBlockchain("Send 400RMB To zengxiangbin", blockchain.Blocks[len(blockchain.Blocks)-1].Height+1, blockchain.Blocks[len(blockchain.Blocks)-1].Hash)blockchain.AddBlockToBlockchain("Send 500RMB To tangyongxiang", blockchain.Blocks[len(blockchain.Blocks)-1].Height+1, blockchain.Blocks[len(blockchain.Blocks)-1].Hash)// 打印区块链fmt.Println(blockchain)// 打印区块fmt.Println(blockchain.Blocks)// 打印区块链中的第一个区块fmt.Println(blockchain.Blocks[0])
}执行结果:返回如下参数// 增加了5个区块
&{[0xc00006c0c0 0xc00006c120 0xc00006c180 0xc00006c1e0 0xc00006c240 0xc00006c2a0]}
[0xc00006c0c0 0xc00006c120 0xc00006c180 0xc00006c1e0 0xc00006c240 0xc00006c2a0]
&{1 [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] [71 101 110 101 115 105 115 32 66 108 111 99 107 32 68 97 116 97 46 46 46 46 46 46] 1738748508 [125 59 251 230 115 205 110 78 142 202 140 230 227 38 189 87 204 81 111 95 13 203 237 128 19 210 51 206 112 46 26 116]}进程 已完成,退出代码为 0

5,part5 工作量证明

我们创建一个POW对象,我们希望这个对象去执行一个方法就可以给我们返回一个有效的Hash和一个有效的Nonce值
1, part5-proof-of-work/BLC/Block.go
package BLCimport ("time"
)// 定义区块
type Block struct { // 定义属性// 1, 区块高度 第几个区块Height int64// 2,上一个区块的HASH 父HashPrevBlockHash []byte// 3, 交易数据 DataData []byte// 4, 时间戳 创建区块时的时间Timestamp int64// 5,Hash 当前区块的Hash  动态Hash值Hash []byte// 6, Nonce 随机数 工作量证明Nonce int64
}// 创建新的区块
func NewBlock(data string, heigh int64, prevBlockHash []byte) *Block {// 创建区块block := &Block{heigh, prevBlockHash, []byte(data), time.Now().Unix(), nil, 0}// 调用工作量证明的方法并且返回有效的 Hash 和 Nonce 创建一个pow工作量对象pow := NewProofOfWork(block)// 返回满足条件的hash值hash, nonce := pow.Run()block.Hash = hash[:]block.Nonce = noncereturn block
}// 2, 单独写一个方法,生成创世区块
func CreateGenesisBlock(data string) *Block {return NewBlock(data, 1, []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0})}2, part5-proof-of-work/BLC/Blockchain.go
package BLC// 定义区块链结构体
type Blockchain struct {// 存储有序的区块Blocks []*Block
}// 增加区块到区块链中
func (blockchain *Blockchain) AddBlockToBlockchain(data string, height int64, prevHash []byte) {// 创建新区块newBlock := NewBlock(data, height, prevHash)// 向区块链中添加新区块blockchain.Blocks = append(blockchain.Blocks, newBlock)
}// 创建带有创世区块的区块链
func CreateBlockchainWithGenesisBlock() *Blockchain {// 1,创建创世区块genesisBlock := CreateGenesisBlock("Genesis Block Data......")// 2, 返回区块链对象return &Blockchain{[]*Block{genesisBlock}}
}3, part5-proof-of-work/BLC/utils.go
package BLCimport ("bytes""encoding/binary""log"
)// 将 int64 转换为 字节数组
func IntToHex(num int64) []byte {buff := new(bytes.Buffer)err := binary.Write(buff, binary.BigEndian, num)if err != nil {log.Panic(err)}return buff.Bytes()
}4, part5-proof-of-work/BLC/ProofOfWork.go
package BLCtype ProofOfWork struct {Block *Block
}func (proofOfWork *ProofOfWork) Run() ([]byte, int64) {return nil, 0
}// 创建新的工作量证明对象
func NewProofOfWork(block *Block) *ProofOfWork {return &ProofOfWork{block}
}5, part5-proof-of-work/main.go
package mainimport ("fmt""project/publicChain/part5-proof-of-work/BLC"
)func main() {// 1, 创建创世区块blockchain := BLC.CreateBlockchainWithGenesisBlock()// 2, 创建新区块 AddBlockToBlockchainblockchain.AddBlockToBlockchain("Send 100RMB To zhangqiang", blockchain.Blocks[len(blockchain.Blocks)-1].Height+1, blockchain.Blocks[len(blockchain.Blocks)-1].Hash)blockchain.AddBlockToBlockchain("Send 200RMB To changjingkong", blockchain.Blocks[len(blockchain.Blocks)-1].Height+1, blockchain.Blocks[len(blockchain.Blocks)-1].Hash)blockchain.AddBlockToBlockchain("Send 300RMB To zengguoqing", blockchain.Blocks[len(blockchain.Blocks)-1].Height+1, blockchain.Blocks[len(blockchain.Blocks)-1].Hash)blockchain.AddBlockToBlockchain("Send 400RMB To zengxiangbin", blockchain.Blocks[len(blockchain.Blocks)-1].Height+1, blockchain.Blocks[len(blockchain.Blocks)-1].Hash)blockchain.AddBlockToBlockchain("Send 500RMB To tangyongxiang", blockchain.Blocks[len(blockchain.Blocks)-1].Height+1, blockchain.Blocks[len(blockchain.Blocks)-1].Hash)// 打印区块链fmt.Println(blockchain)// 打印区块fmt.Println(blockchain.Blocks)// 打印区块链中的第一个区块fmt.Println(blockchain.Blocks[0])
}

6,part6 工作量证明分析

一个区块对应一个工作量证明
1, part6-proof-of-work/BLC/Block.go
package BLCimport ("time"
)// 定义区块
type Block struct { // 定义属性// 1, 区块高度 第几个区块Height int64// 2,上一个区块的HASH 父HashPrevBlockHash []byte// 3, 交易数据 DataData []byte// 4, 时间戳 创建区块时的时间Timestamp int64// 5,Hash 当前区块的Hash  动态Hash值Hash []byte// 6, Nonce 随机数 工作量证明Nonce int64
}// 创建新的区块
func NewBlock(data string, heigh int64, prevBlockHash []byte) *Block {// 创建区块block := &Block{heigh, prevBlockHash, []byte(data), time.Now().Unix(), nil, 0}// 调用工作量证明的方法并且返回有效的 Hash 和 Nonce 创建一个pow工作量对象pow := NewProofOfWork(block)// 返回满足条件的hash值hash, nonce := pow.Run()block.Hash = hash[:]block.Nonce = noncereturn block
}// 2, 单独写一个方法,生成创世区块
func CreateGenesisBlock(data string) *Block {return NewBlock(data, 1, []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0})}2, part6-proof-of-work/BLC/Blockchain.go
package BLC// 定义区块链结构体
type Blockchain struct {// 存储有序的区块Blocks []*Block
}// 增加区块到区块链中
func (blockchain *Blockchain) AddBlockToBlockchain(data string, height int64, prevHash []byte) {// 创建新区块newBlock := NewBlock(data, height, prevHash)// 向区块链中添加新区块blockchain.Blocks = append(blockchain.Blocks, newBlock)
}// 创建带有创世区块的区块链
func CreateBlockchainWithGenesisBlock() *Blockchain {// 1,创建创世区块genesisBlock := CreateGenesisBlock("Genesis Block Data......")// 2, 返回区块链对象return &Blockchain{[]*Block{genesisBlock}}
}3, part5-proof-of-work/BLC/ProofOfWork.go
package BLCimport "math/big"// 0000 0000 0000 0000 1001 0001 .... 0101
// Hash值为256位 以下const代表哈希值里面的最前面至少要有16个0
const targetBit = 16type ProofOfWork struct {// 当前需要验证的区块block *Block// 大数存储,区块难度target *big.Int
}func (proofOfWork *ProofOfWork) Run() ([]byte, int64) {return nil, 0
}// 创建新的工作量证明对象
func NewProofOfWork(block *Block) *ProofOfWork {// 1, big.Int 对象为 1// 2 工作难度// 0000 0001 8位// 8-2=6  表示左移6位// 0100 0000// 16 工作难度// 0000 0000 0000 0001 0000 0000 0000 0000 0000 0000 .... 0000// 先创建 big.Int对象 对象的值为1(创建一个初始值为1的target)target := big.NewInt(1)// 左移 256-targetBit//target.Lsh(target, uint(256-targetBit))target = target.Lsh(target, 256-targetBit)return &ProofOfWork{block, target}
}4, part6-proof-of-work/BLC/utils.go
package BLCimport ("bytes""encoding/binary""log"
)// 将 int64 转换为 字节数组
func IntToHex(num int64) []byte {buff := new(bytes.Buffer)err := binary.Write(buff, binary.BigEndian, num)if err != nil {log.Panic(err)}return buff.Bytes()
}5, part6-proof-of-work/main.go
package mainimport ("fmt""project/publicChain/part6-proof-of-work/BLC"
)func main() {// 1, 创建创世区块blockchain := BLC.CreateBlockchainWithGenesisBlock()// 2, 创建新区块 AddBlockToBlockchainblockchain.AddBlockToBlockchain("Send 100RMB To zhangqiang", blockchain.Blocks[len(blockchain.Blocks)-1].Height+1, blockchain.Blocks[len(blockchain.Blocks)-1].Hash)blockchain.AddBlockToBlockchain("Send 200RMB To changjingkong", blockchain.Blocks[len(blockchain.Blocks)-1].Height+1, blockchain.Blocks[len(blockchain.Blocks)-1].Hash)blockchain.AddBlockToBlockchain("Send 300RMB To zengguoqing", blockchain.Blocks[len(blockchain.Blocks)-1].Height+1, blockchain.Blocks[len(blockchain.Blocks)-1].Hash)blockchain.AddBlockToBlockchain("Send 400RMB To zengxiangbin", blockchain.Blocks[len(blockchain.Blocks)-1].Height+1, blockchain.Blocks[len(blockchain.Blocks)-1].Hash)blockchain.AddBlockToBlockchain("Send 500RMB To tangyongxiang", blockchain.Blocks[len(blockchain.Blocks)-1].Height+1, blockchain.Blocks[len(blockchain.Blocks)-1].Hash)// 打印区块链fmt.Println(blockchain)// 打印区块fmt.Println(blockchain.Blocks)// 打印区块链中的第一个区块fmt.Println(blockchain.Blocks[0])
}

7,挖矿算法完整实现

1, part6-proof-of-work/BLC/Block.go
package BLCimport ("fmt""time"
)// 定义区块
type Block struct { // 定义属性// 1, 区块高度 第几个区块Height int64// 2,上一个区块的HASH 父HashPrevBlockHash []byte// 3, 交易数据 DataData []byte// 4, 时间戳 创建区块时的时间Timestamp int64// 5,Hash 当前区块的Hash  动态Hash值Hash []byte// 6, Nonce 随机数 工作量证明Nonce int64
}// 创建新的区块
func NewBlock(data string, heigh int64, prevBlockHash []byte) *Block {// 创建区块block := &Block{heigh, prevBlockHash, []byte(data), time.Now().Unix(), nil, 0}// 调用工作量证明的方法并且返回有效的 Hash 和 Nonce 创建一个pow工作量对象pow := NewProofOfWork(block)// 返回满足条件的hash值hash, nonce := pow.Run()// 挖矿验证block.Hash = hash[:]block.Nonce = noncefmt.Println()// 换行return block
}// 2, 单独写一个方法,生成创世区块
func CreateGenesisBlock(data string) *Block {return NewBlock(data, 1, []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0})
}2, part6-proof-of-work/BLC/Blockchain.go
package BLC// 定义区块链结构体
type Blockchain struct {// 存储有序的区块Blocks []*Block
}// 增加区块到区块链中
func (blockchain *Blockchain) AddBlockToBlockchain(data string, height int64, prevHash []byte) {// 创建新区块newBlock := NewBlock(data, height, prevHash)// 向区块链中添加新区块blockchain.Blocks = append(blockchain.Blocks, newBlock)
}// 创建带有创世区块的区块链
func CreateBlockchainWithGenesisBlock() *Blockchain {// 1,创建创世区块genesisBlock := CreateGenesisBlock("Genesis Block")// 2, 返回区块链对象return &Blockchain{[]*Block{genesisBlock}}
}3, part5-proof-of-work/BLC/ProofOfWork.go
package BLCimport ("bytes""crypto/sha256""fmt""math/big"
)// 0000 0000 0000 0000 1001 0001 .... 0101
// Hash值为256位 以下const代表哈希值里面的最前面至少要有16个0
const targetBit = 24type ProofOfWork struct {// 当前需要验证的区块block *Block// 大数存储,区块难度target *big.Int
}// 数据拼接,返回字节数组
func (pow *ProofOfWork) prepareData(nonce int) []byte {data := bytes.Join([][]byte{// 上一个区块的hash值pow.block.PrevBlockHash,// 交易数据pow.block.Data,// 时间戳IntToHex(pow.block.Timestamp),// 区块高度IntToHex(pow.block.Height),// 工作难度IntToHex(int64(targetBit)),// 工作量证明 随机数值IntToHex(int64(nonce)),},[]byte{},)return data
}func (proofOfWork *ProofOfWork) Run() ([]byte, int64) {// 1,将 Block 的属性拼接成 字节数组// 2,生成 Hash// 3,判断hash有效性,如果满足条件,跳出循环nonce := 0var hashInt big.Int // 存储新生成的hash值var hash [32]bytefor {// 准备数据dataBytes := proofOfWork.prepareData(nonce)// 生成hashhash = sha256.Sum256(dataBytes)fmt.Printf("\r%x", hash)// 将 hash 存储到 hashInthashInt.SetBytes(hash[:])// fmt.Println(hashInt)// 判断 hashInt 是否小于 Block 里面的 target// Cmp compares x and y and returns:// -1 if x < y// 0 if x == y// -1 if x > yif proofOfWork.target.Cmp(&hashInt) == 1 {break}nonce = nonce + 1}return hash[:], int64(nonce)
}// 创建新的工作量证明对象
func NewProofOfWork(block *Block) *ProofOfWork {// 1, big.Int 对象为 1// 2 工作难度  假设总共有8位// 0000 0001 8位// 8-2=6  表示左移6位// 0100 0000// 16 工作难度// 0000 0000 0000 0001 0000 0000 0000 0000 0000 0000 .... 0000// 先创建 big.Int对象 对象的值为1(创建一个初始值为1的target)target := big.NewInt(1)// 左移 256-targetBit//target.Lsh(target, uint(256-targetBit))target = target.Lsh(target, 256-targetBit)return &ProofOfWork{block, target}
}4, part6-proof-of-work/BLC/utils.go
package BLCimport ("bytes""encoding/binary""log"
)// 将 int64 转换为 字节数组
func IntToHex(num int64) []byte {buff := new(bytes.Buffer)err := binary.Write(buff, binary.BigEndian, num)if err != nil {log.Panic(err)}return buff.Bytes()
}5, part6-proof-of-work/main.go
package mainimport ("fmt""project/publicChain/part7-proof-of-work/BLC"
)func main() {// 1, 创建创世区块blockchain := BLC.CreateBlockchainWithGenesisBlock()// 2, 创建新区块 AddBlockToBlockchainblockchain.AddBlockToBlockchain("Send 100RMB To zhangqiang", blockchain.Blocks[len(blockchain.Blocks)-1].Height+1, blockchain.Blocks[len(blockchain.Blocks)-1].Hash)blockchain.AddBlockToBlockchain("Send 200RMB To changjingkong", blockchain.Blocks[len(blockchain.Blocks)-1].Height+1, blockchain.Blocks[len(blockchain.Blocks)-1].Hash)blockchain.AddBlockToBlockchain("Send 300RMB To zengguoqing", blockchain.Blocks[len(blockchain.Blocks)-1].Height+1, blockchain.Blocks[len(blockchain.Blocks)-1].Hash)blockchain.AddBlockToBlockchain("Send 400RMB To zengxiangbin", blockchain.Blocks[len(blockchain.Blocks)-1].Height+1, blockchain.Blocks[len(blockchain.Blocks)-1].Hash)blockchain.AddBlockToBlockchain("Send 500RMB To tangyongxiang", blockchain.Blocks[len(blockchain.Blocks)-1].Height+1, blockchain.Blocks[len(blockchain.Blocks)-1].Hash)// 打印区块链fmt.Println(blockchain)// 打印区块fmt.Println(blockchain.Blocks)// 打印区块链中的第一个区块fmt.Println(blockchain.Blocks[0])
}挖矿成功
----00000a311d633b0a4ea696550a4463571560b2abbf3382d9785d2c158b9066f2
00009e8ff13ba2bab7928ee0de407da6c495e8f390a87ca0c08423ab40b2fbba
0000750804d9b09ccb432cde40a69fa60dd6f132595217dc7840cf92eb3e5c33
000090c2b9133d472c92ee388c86f72ab8441c8ff6577ddbdc1fee0f74e2eec8
000093105803d54c5be22f730b6bfa05494eb387a42ef289196cbe50dea1a93c
00001162ea0a0a58c3cdaeb3564fc3c673bd55e925c62204a0f295bf8e47532a
&{[0xc00006c0c0 0xc000508120 0xc000508180 0xc000508360 0xc0005083c0 0xc000508480]}
[0xc00006c0c0 0xc000508120 0xc000508180 0xc000508360 0xc0005083c0 0xc000508480]
&{1 [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] [71 101 110 101 115 105 115 32 66 108 111 99 107] 1738807189 [0 0 10 49 29 99 59 10 78 166 150 85 10 68 99 87 21 96 178 171 191 51 130 217 120 93 44 21 139 144 102 242] 195050}进程 已完成,退出代码为 0

8,判断hash区块的有效性

1, part8-proof-of-work/BLC/Block.go
package BLCimport ("fmt""time"
)// 定义区块
type Block struct { // 定义属性// 1, 区块高度 第几个区块Height int64// 2,上一个区块的HASH 父HashPrevBlockHash []byte// 3, 交易数据 DataData []byte// 4, 时间戳 创建区块时的时间Timestamp int64// 5,Hash 当前区块的Hash  动态Hash值Hash []byte// 6, Nonce 随机数 工作量证明Nonce int64
}// 创建新的区块
func NewBlock(data string, heigh int64, prevBlockHash []byte) *Block {// 创建区块block := &Block{heigh, prevBlockHash, []byte(data), time.Now().Unix(), nil, 0}// 调用工作量证明的方法并且返回有效的 Hash 和 Nonce 创建一个pow工作量对象pow := NewProofOfWork(block)// 返回满足条件的hash值hash, nonce := pow.Run()// 挖矿验证block.Hash = hash[:]block.Nonce = noncefmt.Println() // 换行return block
}// 2, 单独写一个方法,生成创世区块
func CreateGenesisBlock(data string) *Block {return NewBlock(data, 1, []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0})
}2, part8-proof-of-work/BLC/Blockchain.go
package BLC// 定义区块链结构体
type Blockchain struct {// 存储有序的区块Blocks []*Block
}// 增加区块到区块链中
func (blockchain *Blockchain) AddBlockToBlockchain(data string, height int64, prevHash []byte) {// 创建新区块newBlock := NewBlock(data, height, prevHash)// 向区块链中添加新区块blockchain.Blocks = append(blockchain.Blocks, newBlock)
}// 创建带有创世区块的区块链
func CreateBlockchainWithGenesisBlock() *Blockchain {// 1,创建创世区块genesisBlock := CreateGenesisBlock("Genesis Block")// 2, 返回区块链对象return &Blockchain{[]*Block{genesisBlock}}
}3, part8-proof-of-work/BLC/ProofOfWork.go
package BLCimport ("bytes""crypto/sha256""fmt""math/big"
)// 0000 0000 0000 0000 1001 0001 .... 0101
// Hash值为256位 以下const代表哈希值里面的最前面至少要有16个0
const targetBit = 20type ProofOfWork struct {// 当前需要验证的区块block *Block// 大数存储,区块难度target *big.Int
}// 数据拼接,返回字节数组
func (pow *ProofOfWork) prepareData(nonce int) []byte {data := bytes.Join([][]byte{// 上一个区块的hash值pow.block.PrevBlockHash,// 交易数据pow.block.Data,// 时间戳IntToHex(pow.block.Timestamp),// 区块高度IntToHex(pow.block.Height),// 工作难度IntToHex(int64(targetBit)),// 工作量证明 随机数值IntToHex(int64(nonce)),},[]byte{},)return data
}// 判断hash区块的有效性
func (proofOfWork *ProofOfWork) IsValid() bool {// 1, proofOfWork.block.Hash// 2, proofOfWork.targetvar hashInt big.Int// 将hash值存储到hashInt里面hashInt.SetBytes(proofOfWork.block.Hash)// 开始判断// Cmp compares x and y and returns:// -1 if x < y// 0 if x == y// -1 if x > yif proofOfWork.target.Cmp(&hashInt) == 1 {return true}return false
}func (proofOfWork *ProofOfWork) Run() ([]byte, int64) {// 1,将 Block 的属性拼接成 字节数组// 2,生成 Hash// 3,判断hash有效性,如果满足条件,跳出循环nonce := 0var hashInt big.Int // 存储新生成的hash值var hash [32]bytefor {// 准备数据dataBytes := proofOfWork.prepareData(nonce)// 生成hashhash = sha256.Sum256(dataBytes)fmt.Printf("\r%x", hash)// 将 hash 存储到 hashInthashInt.SetBytes(hash[:])// fmt.Println(hashInt)// 判断 hashInt 是否小于 Block 里面的 target// Cmp compares x and y and returns:// -1 if x < y// 0 if x == y// -1 if x > yif proofOfWork.target.Cmp(&hashInt) == 1 {break}nonce = nonce + 1}return hash[:], int64(nonce)
}// 创建新的工作量证明对象
func NewProofOfWork(block *Block) *ProofOfWork {// 1, big.Int 对象为 1// 2 工作难度  假设总共有8位// 0000 0001 8位// 8-2=6  表示左移6位// 0100 0000// 16 工作难度// 0000 0000 0000 0001 0000 0000 0000 0000 0000 0000 .... 0000// 先创建 big.Int对象 对象的值为1(创建一个初始值为1的target)target := big.NewInt(1)// 左移 256-targetBit//target.Lsh(target, uint(256-targetBit))target = target.Lsh(target, 256-targetBit)return &ProofOfWork{block, target}
}4, part8-proof-of-work/BLC/utils.go
package BLCimport ("bytes""encoding/binary""log"
)// 将 int64 转换为 字节数组
func IntToHex(num int64) []byte {buff := new(bytes.Buffer)err := binary.Write(buff, binary.BigEndian, num)if err != nil {log.Panic(err)}return buff.Bytes()
}5, part8-proof-of-work/main.go
package mainimport ("fmt""project/publicChain/part8-proof-of-work/BLC"
)func main() {1, 创建创世区块//blockchain := BLC.CreateBlockchainWithGenesisBlock()//2, 创建新区块 AddBlockToBlockchain//blockchain.AddBlockToBlockchain("Send 100RMB To zhangqiang", blockchain.Blocks[len(blockchain.Blocks)-1].Height+1, blockchain.Blocks[len(blockchain.Blocks)-1].Hash)//blockchain.AddBlockToBlockchain("Send 200RMB To changjingkong", blockchain.Blocks[len(blockchain.Blocks)-1].Height+1, blockchain.Blocks[len(blockchain.Blocks)-1].Hash)//blockchain.AddBlockToBlockchain("Send 300RMB To zengguoqing", blockchain.Blocks[len(blockchain.Blocks)-1].Height+1, blockchain.Blocks[len(blockchain.Blocks)-1].Hash)//blockchain.AddBlockToBlockchain("Send 400RMB To zengxiangbin", blockchain.Blocks[len(blockchain.Blocks)-1].Height+1, blockchain.Blocks[len(blockchain.Blocks)-1].Hash)//blockchain.AddBlockToBlockchain("Send 500RMB To tangyongxiang", blockchain.Blocks[len(blockchain.Blocks)-1].Height+1, blockchain.Blocks[len(blockchain.Blocks)-1].Hash)//打印区块链//fmt.Println(blockchain)打印区块//fmt.Println(blockchain.Blocks)打印区块链中的第一个区块//fmt.Println(blockchain.Blocks[0])// data string,height int64,prevBlockHash []byteBlock := BLC.NewBlock("Test", 1, []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0})fmt.Printf("%d\n", Block.Nonce)fmt.Printf("%x\n", Block.Hash)// 创建工作量证明对象proofOfWork := BLC.NewProofOfWork(Block)// 判断hash区块的有效性 返回 true 表示有效fmt.Printf("%v\n", proofOfWork.IsValid())
}运行 判断hash区块的有效性 代码 返回如下参数:// hash
0000030382e1ab4d24830770e6856acad8d942368e9bcdc00df1ffdd4686afb4
// nonce 
701677
// hash
0000030382e1ab4d24830770e6856acad8d942368e9bcdc00df1ffdd4686afb4
// 表示hash区块是有效性的
true进程 已完成,退出代码为 0

9, 区块的序列化和反序列化

相关文章:

基于golang语言开发publicChain项目实战教程

概述&#xff1a;简易公链 任何公链只要涉及转账都会用到UTXO,UTXO并不是面向对象的思维&#xff0c;通过计算如何去打包多笔交易&#xff0c;各种加密算法&#xff0c;钱包 如何生成地址&#xff0c;节点A,节点B,节点C&#xff0c;节点分全节点&#xff0c;钱包节点&#xff…...

Jtti.cc:CentOS下PyTorch运行出错怎么办

在CentOS上运行PyTorch时遇到错误&#xff0c;可以按照以下步骤进行排查和解决&#xff1a; 1. 检查Python版本 Python版本&#xff1a;确保Python版本符合PyTorch要求(如3.6-3.9)。 虚拟环境&#xff1a;建议使用虚拟环境隔离依赖。 python3 -m venv myenv source myenv/bin/a…...

基于微信小程序的电影院订票选座系统的设计与实现,SSM+Vue+毕业论文+开题报告+任务书+指导搭建视频

本系统包含用户、管理员两个角色。 用户角色&#xff1a;注册登录、查看首页电影信息推荐、查看电影详情并进行收藏预定、查看电影资讯、在线客服、管理个人订单等。 管理员角色&#xff1a;登录后台、管理电影类型、管理放映厅信息、管理电影信息、管理用户信息、管理订单等。…...

自然语言处理NLP 02统计语言模型

目录 jieba中文分词 TF-IDF TF&#xff08;词频&#xff0c;Term Frequency&#xff09; IDF&#xff08;逆文档频率&#xff0c;Inverse Document Frequency&#xff09; 总结 案例&#xff1a;从文本数据中提取并分析关键词的重要性 jieba中文分词 jieba 是一个强大的…...

【环降噪实验】详细介绍

环降噪实验&#xff08;Circumferential Noise Cancellation Experiment&#xff09;通常指在工程领域中&#xff0c;特别是在噪声控制领域&#xff0c;通过模拟或实际环形噪声传播的环境来验证和测试不同噪声消除技术的效果。其主要目标是在特定区域或环境中&#xff0c;利用主…...

Qt开发④Qt常用控件_上_QWdget属性+按钮类控件

目录 1. 控件概述和发展 2. QWidget 核心属性 2.1 核心属性概览 2.2 enabled 是否可用 2.3 geometry 位置尺寸 2.4 windowTitle 标题 2.5 windowIcon 图标 2.6 windowOpacity 不透明度 2.7 cursor 光标 2.8 font 字体 2.9 toolTip 鼠标悬停提示 2.10 focusPolicy 焦…...

FreeSwitch之mod_cidlookup 和 mod_blacklist和mod_curl的抉择

FreeSWITCH 的 mod_curl 模块是一个用于通过 HTTP/HTTPS 协议与外部服务进行交互的核心模块。它允许 FreeSWITCH 在呼叫处理过程中发起 HTTP 请求&#xff08;如 GET、POST 等&#xff09;&#xff0c;并将响应结果集成到呼叫流程中。以下是关于 mod_curl 的详细介绍&#xff1…...

强化学习-价值学习算法

Sarsa 理论解释 Sarsa是基于时序差分算法的&#xff0c;它的公式非常简单且易理解&#xff0c;不像策略梯度算法那样需要复杂的推导过程。 Sarsa的核心函数是 Q ( s , a ) Q(s, a) Q(s,a)&#xff0c;它的含义是在状态 s s s下执行 a a a&#xff0c;在后续轨迹中获取的期望…...

Apache Struts RCE (CVE-2024-53677)

前言 对目前的Apache Struts RCE (CVE-2024-53677)的poc进行总结&#xff0c;由于只能单个ip验证&#xff0c;所以自己更改一下代码&#xff0c;实现&#xff1a;多线程读取url验证并保存&#xff0c;更改为中文解释 免责声明 请勿利用文章内的相关技术从事非法测试&#xf…...

23. AI-大语言模型-DeepSeek

文章目录 前言一、DeepSeek是什么1. 简介2. 产品版本3. 特征4. 地址链接5. 三种访问方式1. 网页端和APP2. DeepSeek API 二、DeepSeek可以做什么1. 应用场景2. 文本生成1. 文本创作2. 摘要与改写3. 结构化生成 3. 自然语言理解与分析1. 语义分析2. 文本分类3. 知识推理 4. 编程…...

verilog基础知识

一,Verilog和VHDL区别 全世界高层次数字系统设计领域中,应用Verilog和VHDL的比率是80%和20%;这两种语言都是用于数字电路系统设计的硬件描述语言, 而且都已经是 IEEE 的标准。 VHDL 是美国军方组织开发的,VHDL1987年成为标准;Verilog 是由一个公司的私有财产转化而来,…...

负载测试工具有哪些?

Apache JMeter Apache JMeter 是一款开源的性能测试工具&#xff0c;主要用于对 Web 应用程序进行功能、负载和压力测试。JMeter 支持多种协议和技术&#xff0c;包括 HTTP, HTTPS, FTP 和 WebSocket 等。通过模拟大量并发用户访问来评估应用程序的表现1。 jmeter -n -t testp…...

项目中分库分表的分布式ID如何生成

分库分表与分布式ID生成在Java项目中的应用 在大规模的分布式系统中&#xff0c;数据库表和数据量的增大可能会导致单个数据库或单个表的性能瓶颈。为了解决这个问题&#xff0c;我们通常使用分库分表来进行数据的水平切分和垂直切分。同时&#xff0c;在分布式环境中&#xf…...

用xarray解析高程数据时,Python报错:FileNotFoundError: [Errno 2] No such file or directory

问题&#xff1a; 用xarray解析高程数据时&#xff0c;Python报错:FileNotFoundError: [Errno 2] No such file or directory。 但是该文件时存在的&#xff0c;用panoply工具也是可以正常打开查看。 产生原因&#xff1a; 文件路径中存在中文&#xff0c;导致出现此问题。 …...

标准SαS分布的模拟脉冲噪声

标准SαS分布&#xff08;Standard SαS Distribution&#xff09;是一种用于描述脉冲噪声的统计分布&#xff0c;常用于模拟具有重尾特性的脉冲噪声信号。SαS分布是从稳定分布&#xff08;Stable Distribution&#xff09;中派生出来的一类分布&#xff0c;具有灵活的形状&am…...

基于STM32设计的自动追光系统(系统资料)

基于STM32设计的自动追光系统 摘要:基于STM32设计的自动追光系统主要由光敏采集电路、单片机核心板电路和步进电机控制电路构成。通过光敏电阻采集环境光强信息,经 STM32 单片机处理后,控制步进电机转动,实现对光源的自动追踪。该系统具有响应速度快、追踪精度较高等优点,…...

成人床垫更新关于 SOR/2016-183 和《纺织品贴标和广告法规》的合规

成人床垫更新关于 SOR/2016-183 和《纺织品贴标和广告法规》的合规性声明 加拿大站成人床垫法规SOR/2016-183是强制性的 。为确保买家安全并遵守相关法规&#xff0c;亚马逊要求所有在加拿大销售的成人床垫必须符合《床垫法规》规定的安全标准&#xff0c;包括SOR/2016-183。此…...

11.编写前端内容|vscode链接Linux|html|css|js(C++)

vscode链接服务器 安装VScode插件 Chinese (Simplified) (简体中⽂) Language Pack for Visual Studio CodeOpen in BrowserRemote SSH 在命令行输入 remote-ssh接着输入 打开配置文件&#xff0c;已经配置好主机 点击远程资源管理器可以找到 右键链接 输入密码 …...

Unity3D 基于 GPU 动画和 Compute Shader 的大批量动画渲染详解

引言 在现代游戏开发中&#xff0c;渲染大量动画角色是一个常见的需求&#xff0c;尤其是在大规模战斗场景、开放世界游戏或 VR/AR 应用中。传统的 CPU 动画计算和渲染方式在面对大批量角色时&#xff0c;往往会遇到性能瓶颈。为了优化性能&#xff0c;开发者可以利用 GPU 的强…...

网工项目实践2.6 广域网需求分析及方案制定

本专栏持续更新&#xff0c;整一个专栏为一个大型复杂网络工程项目。阅读本文章之前务必先看《本专栏必读》。 全网拓扑展示 一.广域网互联方式 1.专线 优点 稳定 独享。绝对安全。可靠性高&#xff0c;带宽高&#xff0c;完全取决于终端接口。 缺点: 费用高。建设时间长。难…...

大模型相关学习

知识科普 为什么不直接使用网页版 DeepSeek? 我们的需求&#xff1a;绝对的隐私保护和个性化知识库构建。场景&#xff1a;若希望大模型能根据企业规章制度来回答问题&#xff0c;一般需上传企业规章制度的附件&#xff0c;但仍可能面临问题。 数据隐私问题&#xff1a;联网使…...

vue2自定义useVModel函数

父组件&#xff1a; <template> <div>父组件数据名字&#xff1a;<input v-model"person.name">父组件数据年龄&#xff1a;<input v-model"person.age"><son v-model"person"></son> </div> </t…...

基于Java(JSP)+MySQL设计与实现的 MVC 鲜花订购系统

基于MVC的鲜花订购系统的设计与实现 摘 要 摘 要&#xff1a;鲜花订购系统与网络相结合&#xff0c;给用户提供更加周到和人性化的服务。网站模式为MVC模式&#xff0c;基于MySql数据库,采用Jsp&#xff0c;Session绘画跟踪、JavaScript等技术,实现了普通用户可以浏览、查看鲜…...

YOLOv11-ultralytics-8.3.67部分代码阅读笔记-dataset.py

dataset.py ultralytics\data\dataset.py 目录 dataset.py 1.所需的库和模块 2.class YOLODataset(BaseDataset): 3.class YOLOMultiModalDataset(YOLODataset): 4.class GroundingDataset(YOLODataset): 5.class YOLOConcatDataset(ConcatDataset): 6.class Sema…...

网络原理-

文章目录 协议应用层传输层网络层 数据链路层 协议 在网络通信中,协议是非常重要的概念.协议就是一种约定. 在网络通信过程中,对协议进行了分层 接下来就按照顺序向大家介绍每一种核心的协议. 应用层 应用层是咱们程序员打交道最多的一层协议.应用层里有很多现成的协议,但…...

解码 NLP:从萌芽到蓬勃的技术蜕变之旅

内容概况&#xff1a; 主要讲述NLP专栏的内容和NLP的发展及其在现代生活中的广泛应用。课程强调实践为主、理论为辅的学习方法&#xff0c;并通过多个生活场景展示了NLP技术的实际应用&#xff0c;如对话机器人、搜索引擎、翻译软件、电商推荐和智能客服等。 这边我就不多做自我…...

Word中的文档信息域

Word中的文档信息域 DocProperty包含文档信息的多个属性, 也可以自定义属性. 查看文档预定义的自定义属性 【文件】→【信息】→【属性】→【高级属性】 参考链接 WORD中文档属性域DocProperty的应用-CSDN博客 第06套 Word_哔哩哔哩_bilibili...

.NET周刊【2月第2期 2025-02-09】

国内文章 开箱即用的.NET MAUI组件库 V-Control 发布了! https://www.cnblogs.com/jevonsflash/p/18701494 文章介绍了V-Control&#xff0c;一个适用于.NET MAUI的组件库。作者计划将其开源&#xff0c;强调.NET MAUI是生产力强的跨平台移动开发工具。V-Control提供多种组件…...

MySQL六大日志的功能介绍。

前言 首先&#xff0c;MySQL的日志应该包括二进制日志&#xff08;Binary Log&#xff09;、错误日志&#xff08;Error Log&#xff09;、查询日志&#xff08;General Query Log&#xff09;、慢查询日志&#xff08;Slow Query Log&#xff09;、重做日志&#xff08;Redo …...

java机器学习计算指标动态阈值

java机器学习计算指标动态阈值 最近听到有的人说要做机器学习就一定要学Python&#xff0c;我想他们掌握的知道还不够系统全面。本文作者以动态阈值需求场景给大家介绍几种常用Java实现的机器学习库&#xff0c;包括使用开源库如Weka或Deeplearning4j&#xff08;DL4J&#xf…...