├── README.md ├── day01_01_Base_Prototype ├── BLC │ ├── Block.go │ ├── BlockChain.go │ └── utils.go └── main.go ├── day01_02_Proof_Of_Work ├── BLC │ ├── Block.go │ ├── BlockChain.go │ ├── ProofOfWork.go │ └── utils.go ├── main.go └── 课堂笔记01.txt ├── day02_03_Persistence ├── BLC │ ├── Block.go │ ├── BlockChain.go │ ├── BlockChainIterator.go │ ├── Constant.go │ ├── ProofOfWork.go │ └── utils.go ├── bc ├── blockchain.db └── main.go ├── day02_04_CLI ├── BLC │ ├── Block.go │ ├── BlockChain.go │ ├── BlockChainIterator.go │ ├── CLI.go │ ├── Constant.go │ ├── ProofOfWork.go │ └── utils.go ├── bc ├── blockchain.db └── main.go ├── day03_05_Transaction ├── BLC │ ├── Block.go │ ├── BlockChain.go │ ├── BlockChainIterator.go │ ├── CLI.go │ ├── CLI_createBlockChain.go │ ├── CLI_getBalance.go │ ├── CLI_printChains.go │ ├── CLI_send.go │ ├── Constant.go │ ├── ProofOfWork.go │ ├── Transaction.go │ ├── Transaction_TxInput.go │ ├── Transaction_TxOutput.go │ ├── Transaction_UTXO.go │ └── utils.go ├── bc ├── blockchain.db └── main.go ├── day04_06_Address ├── BLC │ ├── Block.go │ ├── BlockChain.go │ ├── BlockChainIterator.go │ ├── CLI.go │ ├── CLI_addresslists.go │ ├── CLI_createBlockChain.go │ ├── CLI_createwallet.go │ ├── CLI_getBalance.go │ ├── CLI_printChains.go │ ├── CLI_send.go │ ├── Constant.go │ ├── ProofOfWork.go │ ├── Transaction.go │ ├── Transaction_TxInput.go │ ├── Transaction_TxOutput.go │ ├── Transaction_UTXO.go │ ├── Wallet.go │ ├── Wallets.go │ ├── base58.go │ └── utils.go ├── Wallets.dat ├── bc ├── blockchain.db └── main.go ├── day05_07_signature ├── BLC │ ├── Block.go │ ├── BlockChain.go │ ├── BlockChainIterator.go │ ├── CLI.go │ ├── CLI_addresslists.go │ ├── CLI_createBlockChain.go │ ├── CLI_createwallet.go │ ├── CLI_getBalance.go │ ├── CLI_printChains.go │ ├── CLI_send.go │ ├── Constant.go │ ├── ProofOfWork.go │ ├── Transaction.go │ ├── Transaction_TxInput.go │ ├── Transaction_TxOutput.go │ ├── Transaction_UTXO.go │ ├── Wallet.go │ ├── Wallets.go │ ├── base58.go │ └── utils.go ├── Wallets.dat ├── bc ├── blockchain.db └── main.go ├── day06_08_Update ├── BLC │ ├── Block.go │ ├── BlockChain.go │ ├── BlockChainIterator.go │ ├── CLI.go │ ├── CLI_addresslists.go │ ├── CLI_createBlockChain.go │ ├── CLI_createwallet.go │ ├── CLI_getBalance.go │ ├── CLI_printChains.go │ ├── CLI_send.go │ ├── CLI_testmethod.go │ ├── Constant.go │ ├── ProofOfWork.go │ ├── Transaction.go │ ├── Transaction_TxInput.go │ ├── Transaction_TxOutput.go │ ├── Transaction_UTXO.go │ ├── TxOutputs.go │ ├── UTXO_Set.go │ ├── Wallet.go │ ├── Wallets.go │ ├── base58.go │ └── utils.go ├── Wallets.dat ├── bc ├── blockchain.db └── main.go ├── day07_09_Merkle ├── BLC │ ├── Block.go │ ├── BlockChain.go │ ├── BlockChainIterator.go │ ├── CLI.go │ ├── CLI_addresslists.go │ ├── CLI_createBlockChain.go │ ├── CLI_createwallet.go │ ├── CLI_getBalance.go │ ├── CLI_printChains.go │ ├── CLI_send.go │ ├── CLI_testmethod.go │ ├── Constant.go │ ├── MerkleTree.go │ ├── ProofOfWork.go │ ├── Transaction.go │ ├── Transaction_TxInput.go │ ├── Transaction_TxOutput.go │ ├── Transaction_UTXO.go │ ├── TxOutputs.go │ ├── UTXO_Set.go │ ├── Wallet.go │ ├── Wallets.go │ ├── base58.go │ └── utils.go ├── Wallets.dat ├── bc ├── blockchain.db └── main.go └── day08_10_Net ├── BLC ├── Block.go ├── BlockChain.go ├── BlockChainIterator.go ├── CLI.go ├── CLI_addresslists.go ├── CLI_createBlockChain.go ├── CLI_createwallet.go ├── CLI_getBalance.go ├── CLI_printChains.go ├── CLI_send.go ├── CLI_startnode.go ├── CLI_testmethod.go ├── Constant.go ├── MerkleTree.go ├── ProofOfWork.go ├── Server.go ├── Server_GetData.go ├── Server_Inv.go ├── Server_Tx.go ├── Server_Version.go ├── Server_block.go ├── Server_getblocks.go ├── Server_handle.go ├── Server_send.go ├── Server_var.go ├── Transaction.go ├── Transaction_TxInput.go ├── Transaction_TxOutput.go ├── Transaction_UTXO.go ├── TxOutputs.go ├── UTXO_Set.go ├── Wallet.go ├── Wallets.go ├── base58.go └── utils.go ├── Wallets_3000.dat ├── Wallets_3001.dat ├── Wallets_3002.dat ├── bc ├── blockchain_3000.db ├── blockchain_3001.db ├── blockchain_3002.db ├── blockchain_genesis.db └── main.go /README.md: -------------------------------------------------------------------------------- 1 | # goweb 2 | # goweb 3 | -------------------------------------------------------------------------------- /day01_01_Base_Prototype/BLC/Block.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import ( 4 | "time" 5 | "strconv" 6 | "bytes" 7 | "crypto/sha256" 8 | ) 9 | 10 | //step1:创建Block结构体 11 | type Block struct { 12 | //字段: 13 | //高度Height:其实就是区块的编号,第一个区块叫创世区块,高度为0 14 | Height int64 15 | //上一个区块的哈希值ProvHash: 16 | PrevBlockHash []byte 17 | //交易数据Data:目前先设计为[]byte,后期是Transaction 18 | Data [] byte 19 | //时间戳TimeStamp: 20 | TimeStamp int64 21 | //哈希值Hash:32个的字节,64个16进制数 22 | Hash []byte 23 | } 24 | 25 | //step2:创建新的区块 26 | func NewBlock(data string,provBlockHash []byte,height int64) *Block{ 27 | //创建区块 28 | block:=&Block{height,provBlockHash,[]byte(data),time.Now().Unix(),nil} 29 | //设置哈希值 30 | block.SetHash() 31 | return block 32 | } 33 | 34 | //step3:设置区块的hash 35 | func (block *Block) SetHash(){ 36 | //1.将高度转为字节数组 37 | heightBytes:= IntToHex(block.Height) 38 | //fmt.Println(heightBytes) 39 | //2.时间戳转为字节数组 40 | //timeBytes:=IntToHex(block.TimeStamp) 41 | //转为二进制的字符串 42 | //fmt.Println(block.TimeStamp) 43 | //fmt.Printf("%x,%b\n",block.TimeStamp,block.TimeStamp) 44 | timeString := strconv.FormatInt(block.TimeStamp,2) 45 | //fmt.Println("timeString:",timeString) 46 | timeBytes := [] byte(timeString) 47 | //fmt.Println("timeStamp:",timeBytes) 48 | //3.拼接所有的属性 49 | blockBytes:= bytes.Join([][]byte{ 50 | heightBytes, 51 | block.PrevBlockHash, 52 | block.Data, 53 | timeBytes},[]byte{}) 54 | //4.生成哈希值 55 | hash:=sha256.Sum256(blockBytes)//数组长度32位 56 | block.Hash = hash[:] 57 | } 58 | 59 | //step4:创建创世区块: 60 | func CreateGenesisBlock(data string) *Block{ 61 | return NewBlock(data,make([] byte,32,32),0) 62 | } 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /day01_01_Base_Prototype/BLC/BlockChain.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | //step5:创建区块链 4 | type BlockChain struct { 5 | Blocks []*Block //存储有序的区块 6 | } 7 | 8 | //step6:创建区块链,带有创世区块 9 | func CreateBlockChainWithGenesisBlock(data string) *BlockChain{ 10 | //创建创世区块 11 | genesisBlock := CreateGenesisBlock(data) 12 | //返回区块链对象 13 | return &BlockChain{[]*Block{genesisBlock}} 14 | } 15 | 16 | //step7:添加一个新的区块,到区块链中 17 | func (bc *BlockChain) AddBlockToBlockChain(data string,height int64,prevHash [] byte){ 18 | //创建新区块 19 | newBlock := NewBlock(data,prevHash,height) 20 | //添加到切片中 21 | bc.Blocks = append(bc.Blocks,newBlock) 22 | } 23 | -------------------------------------------------------------------------------- /day01_01_Base_Prototype/BLC/utils.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import ( 4 | "bytes" 5 | "encoding/binary" 6 | "log" 7 | ) 8 | 9 | /* 10 | 将一个int64的整数:转为二进制后,每8bit一个byte。转为[]byte 11 | */ 12 | func IntToHex(num int64) []byte { 13 | buff := new(bytes.Buffer) 14 | //将二进制数据写入w 15 | //func Write(w io.Writer, order ByteOrder, data interface{}) error 16 | err := binary.Write(buff, binary.BigEndian, num) 17 | if err != nil { 18 | log.Panic(err) 19 | } 20 | //转为[]byte并返回 21 | return buff.Bytes() 22 | } 23 | -------------------------------------------------------------------------------- /day01_01_Base_Prototype/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "mypublicchain/day01_01_Base_Prototype/BLC" 5 | "fmt" 6 | "crypto/sha256" 7 | ) 8 | 9 | func main() { 10 | //1.测试Block 11 | //block:=BLC.NewBlock("I am a block",make([]byte,32,32),1) 12 | //fmt.Printf("Heigth:%x\n",block.Height) 13 | //fmt.Printf("Data:%s\n",block.Data) 14 | 15 | //2.测试创世区块 16 | //genesisBlock :=BLC.CreateGenesisBlock("Genesis Block..") 17 | //fmt.Printf("Heigth:%x\n",genesisBlock.Height) 18 | //fmt.Printf("PrevBlockHash:%x\n",genesisBlock.PrevBlockHash) 19 | //fmt.Printf("Data:%s\n",genesisBlock.Data) 20 | 21 | //3.测试区块链 22 | //genesisBlockChain := BLC.CreateBlockChainWithGenesisBlock("Genesis Block..") 23 | //fmt.Println(genesisBlockChain) 24 | //fmt.Println(genesisBlockChain.Blocks) 25 | //fmt.Printf("Heigth:%x\n",genesisBlockChain.Blocks[0].Height) 26 | //fmt.Printf("PrevBlockHash:%x\n",genesisBlockChain.Blocks[0].PrevBlockHash) 27 | //fmt.Printf("Data:%s\n",genesisBlockChain.Blocks[0].Data) 28 | 29 | //4.测试添加新区块 30 | blockChain:=BLC.CreateBlockChainWithGenesisBlock("Genesis Block..") 31 | blockChain.AddBlockToBlockChain("Send 1BTC To Wangergou",blockChain.Blocks[len(blockChain.Blocks)-1].Height+1,blockChain.Blocks[len(blockChain.Blocks)-1].Hash) 32 | blockChain.AddBlockToBlockChain("Send 3BTC To lixiaohua",blockChain.Blocks[len(blockChain.Blocks)-1].Height+1,blockChain.Blocks[len(blockChain.Blocks)-1].Hash) 33 | blockChain.AddBlockToBlockChain("Send 5BTC To rose",blockChain.Blocks[len(blockChain.Blocks)-1].Height+1,blockChain.Blocks[len(blockChain.Blocks)-1].Hash) 34 | 35 | for _, block := range blockChain.Blocks { 36 | fmt.Printf("Prev. hash: %x\n", block.PrevBlockHash) 37 | fmt.Printf("Data: %s\n", block.Data) 38 | fmt.Printf("Hash: %x\n", block.Hash) 39 | fmt.Println() 40 | } 41 | 42 | hash:=sha256.Sum256([]byte("HelloWorld")) 43 | fmt.Printf("%x\n",hash) 44 | } 45 | -------------------------------------------------------------------------------- /day01_02_Proof_Of_Work/BLC/Block.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import ( 4 | "time" 5 | 6 | ) 7 | 8 | //step1:创建Block结构体 9 | type Block struct { 10 | //字段: 11 | //高度Height:其实就是区块的编号,第一个区块叫创世区块,高度为0 12 | Height int64 13 | //上一个区块的哈希值ProvHash: 14 | PrevBlockHash []byte 15 | //交易数据Data:目前先设计为[]byte,后期是Transaction 16 | Data [] byte 17 | //时间戳TimeStamp: 18 | TimeStamp int64 19 | //哈希值Hash:32个的字节,64个16进制数 20 | Hash []byte 21 | 22 | Nonce int64 23 | } 24 | 25 | //step2:创建新的区块 26 | func NewBlock(data string,provBlockHash []byte,height int64) *Block{ 27 | //创建区块 28 | block:=&Block{height,provBlockHash,[]byte(data),time.Now().Unix(),nil,0} 29 | //step5:设置block的hash和nonce 30 | //设置哈希 31 | //block.SetHash() 32 | //调用工作量证明的方法,并且返回有效的Hash和Nonce 33 | pow:=NewProofOfWork(block) 34 | hash,nonce:=pow.Run() 35 | block.Hash = hash 36 | block.Nonce = nonce 37 | 38 | 39 | return block 40 | } 41 | 42 | 43 | //step4:创建创世区块: 44 | func CreateGenesisBlock(data string) *Block{ 45 | return NewBlock(data,make([] byte,32,32),0) 46 | } 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /day01_02_Proof_Of_Work/BLC/BlockChain.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | //step5:创建区块链 4 | type BlockChain struct { 5 | Blocks []*Block //存储有序的区块 6 | } 7 | 8 | //step6:创建区块链,带有创世区块 9 | func CreateBlockChainWithGenesisBlock(data string) *BlockChain{ 10 | //创建创世区块 11 | genesisBlock := CreateGenesisBlock(data) 12 | //返回区块链对象 13 | return &BlockChain{[]*Block{genesisBlock}} 14 | } 15 | 16 | //step7:添加一个新的区块,到区块链中 17 | func (bc *BlockChain) AddBlockToBlockChain(data string,height int64,prevHash [] byte){ 18 | //创建新区块 19 | newBlock := NewBlock(data,prevHash,height) 20 | //添加到切片中 21 | bc.Blocks = append(bc.Blocks,newBlock) 22 | } 23 | -------------------------------------------------------------------------------- /day01_02_Proof_Of_Work/BLC/ProofOfWork.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import ( 4 | "math/big" 5 | "bytes" 6 | "crypto/sha256" 7 | "fmt" 8 | ) 9 | 10 | // 0000 0000 0000 0000 1001 0001 0000 .... 0001 11 | //256位Hash里面前面至少有16个零 12 | const TargetBit = 16 // 20 13 | 14 | //step2:创建pow结构体 15 | type ProofOfWork struct { 16 | //要验证的区块 17 | Block *Block 18 | 19 | //大整数存储,目标哈希 20 | Target *big.Int 21 | } 22 | 23 | //step3: 创建新的工作量证明对象 24 | func NewProofOfWork(block *Block) *ProofOfWork { 25 | //1.创建一个big对象 0000000.....00001 26 | /* 27 | 0000 0001 28 | 0010 0000 29 | */ 30 | target := big.NewInt(1) 31 | 32 | //2.左移256-bits位 33 | target = target.Lsh(target, 256-TargetBit) 34 | 35 | return &ProofOfWork{block, target} 36 | } 37 | 38 | //step4:返回有效的哈希和nonce值 39 | func (pow *ProofOfWork) Run() ([] byte, int64) { 40 | //1.将Block的属性拼接成字节数组 41 | //2.生成Hash 42 | //3.循环判断Hash的有效性,满足条件,跳出循环结束验证 43 | nonce := 0 44 | //var hashInt big.Int //用于存储新生成的hash 45 | hashInt := new(big.Int) 46 | var hash [32]byte 47 | for{ 48 | //获取字节数组 49 | dataBytes := pow.prepareData(nonce) 50 | //生成hash 51 | hash = sha256.Sum256(dataBytes) 52 | //fmt.Printf("%d: %x\n",nonce,hash) 53 | fmt.Printf("\r%d: %x",nonce,hash) 54 | //将hash存储到hashInt 55 | hashInt.SetBytes(hash[:]) 56 | //判断hashInt是否小于Block里的target 57 | /* 58 | Com compares x and y and returns: 59 | -1 if x < y 60 | 0 if x == y 61 | 1 if x > y 62 | */ 63 | if pow.Target.Cmp(hashInt) == 1{ 64 | break 65 | } 66 | nonce++ 67 | } 68 | fmt.Println() 69 | return hash[:], int64(nonce) 70 | } 71 | 72 | //step5:根据block生成一个byte数组 73 | func (pow *ProofOfWork) prepareData(nonce int)[]byte{ 74 | data := bytes.Join( 75 | [][] byte{ 76 | pow.Block.PrevBlockHash, 77 | pow.Block.Data, 78 | IntToHex(pow.Block.TimeStamp), 79 | IntToHex(int64(TargetBit)), 80 | IntToHex(int64(nonce)), 81 | }, 82 | [] byte{}, 83 | ) 84 | return data 85 | } 86 | 87 | func (pow *ProofOfWork) IsValid() bool{ 88 | hashInt := new(big.Int) 89 | hashInt.SetBytes(pow.Block.Hash) 90 | return pow.Target.Cmp(hashInt) == 1 91 | } 92 | -------------------------------------------------------------------------------- /day01_02_Proof_Of_Work/BLC/utils.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import ( 4 | "bytes" 5 | "encoding/binary" 6 | "log" 7 | ) 8 | 9 | /* 10 | 将一个int64的整数:转为二进制后,每8bit一个byte。转为[]byte 11 | */ 12 | func IntToHex(num int64) []byte { 13 | buff := new(bytes.Buffer) 14 | //将二进制数据写入w 15 | //func Write(w io.Writer, order ByteOrder, data interface{}) error 16 | err := binary.Write(buff, binary.BigEndian, num) 17 | if err != nil { 18 | log.Panic(err) 19 | } 20 | //转为[]byte并返回 21 | return buff.Bytes() 22 | } 23 | -------------------------------------------------------------------------------- /day01_02_Proof_Of_Work/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "./BLC" 5 | "fmt" 6 | "strconv" 7 | ) 8 | 9 | func main() { 10 | //1.测试Block 11 | //block:=BLC.NewBlock("I am a block",make([]byte,32,32),1) 12 | //fmt.Println(block) 13 | //2.测试创世区块 14 | //genesisBlock :=BLC.CreateGenesisBlock("Genesis Block..") 15 | //fmt.Println(genesisBlock) 16 | 17 | //3.测试区块链 18 | //genesisBlockChain := BLC.CreateBlockChainWithGenesisBlock() 19 | //fmt.Println(genesisBlockChain) 20 | //fmt.Println(genesisBlockChain.Blocks) 21 | //fmt.Println(genesisBlockChain.Blocks[0]) 22 | 23 | //4.测试添加新区块 24 | blockChain:=BLC.CreateBlockChainWithGenesisBlock("Genesis Block..") 25 | blockChain.AddBlockToBlockChain("Send 100RMB To Wangergou",blockChain.Blocks[len(blockChain.Blocks)-1].Height+1,blockChain.Blocks[len(blockChain.Blocks)-1].Hash) 26 | blockChain.AddBlockToBlockChain("Send 300RMB To lixiaohua",blockChain.Blocks[len(blockChain.Blocks)-1].Height+1,blockChain.Blocks[len(blockChain.Blocks)-1].Hash) 27 | blockChain.AddBlockToBlockChain("Send 500RMB To rose",blockChain.Blocks[len(blockChain.Blocks)-1].Height+1,blockChain.Blocks[len(blockChain.Blocks)-1].Hash) 28 | 29 | fmt.Println(blockChain) 30 | for _, block := range blockChain.Blocks { 31 | pow := BLC.NewProofOfWork(block) 32 | fmt.Printf("PoW: %s\n", strconv.FormatBool(pow.IsValid())) 33 | } 34 | 35 | /* 36 | // 5.检测pow 37 | //1.创建一个big对象 0000000.....00001 38 | target := big.NewInt(1) 39 | fmt.Printf("0x%x\n",target) //0x1 40 | 41 | //2.左移256-bits位 42 | target = target.Lsh(target, 256-BLC.TargetBit) 43 | 44 | fmt.Printf("0x%x\n",target) //61 45 | //61位:0x1000000000000000000000000000000000000000000000000000000000000 46 | //64位:0x0001000000000000000000000000000000000000000000000000000000000000 47 | 48 | s1:="HelloWorld" 49 | hash:=sha256.Sum256([]byte(s1)) 50 | fmt.Printf("0x%x\n",hash) 51 | */ 52 | } 53 | -------------------------------------------------------------------------------- /day01_02_Proof_Of_Work/课堂笔记01.txt: -------------------------------------------------------------------------------- 1 | 一:内容介绍 2 | 1.两周写一个公链的项目,是在一个外国人写一个开源项目上做的改造。他有些东西不全, 3 | 比如几个区块里可以有多笔交易,它没有。包括终端中多笔交易打包到一个区块中,一致性协议等。 4 | 但是远远没有比特笔复杂。我们了解公链的原理,实现一个简单的公链。 5 | 我们能够了解 6 | block, 7 | blockchain, 8 | POW, 9 | 数据库的存储, 10 | UTXO(为花费交易模型) 11 | Transaction,彼特币是10分钟打包一个区块,里面有多笔交易。 12 | 地址,公钥,私钥,数字签名,验证签名:使用加密算法(sha256,ripemd160,椭圆加密) 13 | 网络:节点A,节点B,节点C。。节点之间 14 | 创建钱包,能转账,查询余额 15 | 16 | 节点之间数据同步: 17 | 2.区块链和彼特币简单介绍 18 | A:起源 19 | 最早起源是2008年美国的一场金融危机,美国政府无限增发货币(记账权)。 20 | 中本聪在当年10月发表一片文章《bitcoin:A peer to peer electronic cash system》(一种对等电子现金系统), 21 | 描述了一种电子货币及其算法。整体思想时开创性的。但是技术时已经存在的。p2p、分布式存储、Hash算法、非对称加密等。 22 | 23 | B:比特币 24 | 在2009年1月3日,中本聪开发出首个实现了比特币算法的客户端程序并进行了首次"采矿"(mining)。 25 | 北京时间2009年1月4日,比特币的第一个区块,就是创世区块。 26 | 27 | 每个区块的产生后,比特币系统就会对挖矿者进行奖励。 28 | 中本聪获得了第一批比特币50个。挖矿奖励比特币数不是固定的,每产生21万个区块,奖励就减半。 29 | 30 | 比特币系统规定每10分钟产生一个区块,算下来就是每4年奖励就会减半。预计 31 | 32 | 比特币:一共2100万个 33 | 2008年开始,2012年奖励50个 34 | 2012年开始,2016年奖励25个 35 | 2016年开始,2020年奖励12.5个 36 | 37 | 38 | 39 | 40 | 第一个区块中,并没有交易记录。而是将《泰晤士报》2009年1月3日的一条新闻永远记录在了其中。 41 | 前十万个区块中:中本聪自己挖矿,coinbase交易,系统奖励金币的交易。 42 | 43 | C:挖矿 44 | 挖矿时重复计算区块头的hash,不断修改随机数nonce,指导与难度目标值匹配。 45 | 挖矿就是在争取记账权,对一段时间内比特币网络中的交易进行确认,并记录在区块链上的过程。 46 | 矿工时记账员,区块链是账本,每个区块就是整个账本中的每一个账页。 47 | 挖矿成功,矿工争取到了区块的记账权,这10分钟内被打包的所有未确认的交易的手续费都会奖励给该矿工 48 | 49 | D:区块链的流程 50 | 区块链,就是一种分布式,不保存到数据库,以文本的形式保存。保存到每一台加入比特币网络的,只要安装了比特币钱包, 51 | 就可以保存。 52 | 某个节点要做交易,全节点,轻节点(钱包节点,矿工节点),只保存自己的交易记录。 53 | 54 | 500万个用户,几万个全节点。全节点不能关机(安装了比特币客户端,并且下载了20个G就被认为是全节点),关机被认为是劣质节点。 55 | 56 | 比特币的思想:人人为我,我为人人。 57 | 中本聪世界乌托邦的大同世界。 58 | 59 | E:区块和区块链 60 | 61 | F:区块链:公链,私链,联盟链 62 | 63 | 64 | 二:本堂课内容 65 | 1.基本原型 66 | A: 67 | step1:block结构体, 68 | step2:创建新区块, 69 | step3:设置哈希 70 | Block结构体 71 | 字段: 72 | 高度Height:其实就是区块的编号,第一个区块叫创世区块,高度为0 73 | 上一个区块的哈希值ProvHash: 74 | 交易数据Data:目前先设计为[]byte,后期是Transaction 75 | 时间戳TimeStamp: 76 | 哈希值Hash: 77 | 78 | bit:1个0或1 79 | byte:8个bit 80 | 1024byte:1kb 81 | 1024kb:1mb 82 | 。。。 83 | 84 | 16进制:1111,4个bit 85 | 2个16进制数,也是一个byte。 86 | 87 | 88 | 设置哈希值: 89 | 密码算法:hash,不可逆 90 | 加密,解密:可逆 91 | 消息摘要(message digest):不可逆 92 | md5,message digest 第5,第4代容易被破解。 93 | 只有32bit。 94 | 32bit的16进制 95 | hash散列 96 | sha256:安全的256bit 97 | 64bit的16进制 98 | ripeMd160: 99 | 160bit。 100 | 40bit的16进制 101 | 102 | 安全散列算法SHA(Secure Hash Algorithm)是美国国家安全局 (NSA) 设计, 103 | 美国国家标准与技术研究院(NIST) 发布的一系列密码散列函数,包括 SHA-1、SHA-224、 104 | SHA-256、SHA-384 和 SHA-512 等变体。主要适用于数字签名标准(DigitalSignature 105 | Standard DSS)里面定义的数字签名算法(Digital Signature Algorithm DSA)。 106 | SHA-1已经不是那边安全了,google和微软都已经弃用这个加密算法。为此,我们使用热门的 107 | 比特币使用过的算法SHA-256作为实例。其它SHA算法,也可以按照这种模式进行使用。 108 | 109 | 为了短 110 | 111 | base58编码:来源base64 112 | 113 | 114 | B:step4: 115 | 创建创世区块: 116 | 比特币中创世区块,是中本聪于2009年1月3日,中本聪开发出首个实现了比特币算法的客户端程序并进 117 | 行了首次“采矿”(mining)。 北京时间2009年1月4日 2:15:05 AM(英国时间约2009年1月3日 118 | 18:15:05 PM) 比特币的第一个区块,这就是创世区块产生。 119 | 120 | 中本聪获得了第一批50个比特币。挖矿奖励比特币数并不是固定的,每产生21万个区块奖励就减半。 121 | 截止到目前每挖到一个区块奖励为12.5个比特币。 122 | 在第一个区块中,没有交易记录。而是将《泰晤士报》2009年1月3日的一条新闻永远记录在了其中。 123 | 124 | C: 125 | step5:BlockChain结构体, 126 | step6:创建带有创世区块的区块链 127 | D:向区块链中添加一个新的区块 128 | step7: 129 | 130 | 131 | 2.工作量证明 132 | 挖矿:XXXXXXX。。。。 133 | 挖矿的过程,就是个暴力破解的过程,需要算力。 134 | 挖矿计算的hash,就是将这些值拼一起做一个hash,时间戳改变,nonce从0开始累加,不同的生成hash。 135 | 用算出的hash和目标哈希匹配 136 | 137 | 挖矿:每个矿机,分别分摊nonce。有一个计算成功就可以。瞬间验证,微秒级别。 138 | 验证成功后,更新hash值, 139 | 140 | 矿机-->矿场-->矿池(跨国家) 141 | 矿池挖到框,根据算力,分配给每台矿机。 142 | CPU-GPU-专业挖矿及-矿厂-矿池 143 | 144 | Difficulty: 145 | 146 | 147 | bits:目标难度,16进制表示。 148 | 某个时间段都是固定的。如果大家都在10分钟挖到,就一直固定。否则再修改。 149 | 150 | 通过bits可以计算出目标Hash(固定的),计算出的hash要小于目标hash,就相当于挖矿成功。 151 | 152 | 计算机颠倒数据:防止前面是0。 153 | 大端排序-->小端排序 154 | 1个字节:2个数 155 | 156 | ● 难度Difficulty: 157 | ○ 整个网络会通过调整“难度”这个变量来控制生成工作量证明所需要的计算力。 158 | ○ 随着难度增加,矿工通常在循环便利4亿次随机数值后仍未找到区块,则会启用超额随机数。 159 | ● 难度目标Bits: 160 | ○ 使整个网络的计算力大致每10分钟产生一个区块所需要的难度数值即为难度目标。 161 | ○ Bits是用来存储难度目标的16进制数值。 162 | ○ 例如516532块: 163 | 1. Bits = "0x17502ab7" 164 | 2. coefficient系数,coefficient = 0x502ab7 165 | 3. exponent指数,exponent = 0x17 166 | 4. target = coefficient * Math.pow(2, 8 * (exponent - 3)) 167 | 5. 目标hash:000000000000000000502ab700000000d6420b16625d309c4561290000000000 168 | 6. 实际hash:00000000000000000041ff1cfc5f15f929c1a45d262f88e4db83680d90658c0c 169 | 7. Bits值越小,难度越大,越难挖矿。 170 | 171 | 172 | 173 | 174 | 175 | A:添加工作量证明 176 | 删除setHash()方法 177 | step1,修改Block结构体 178 | 添加Nonce(修改NewBlock()) 179 | step2:创建ProofOfWork结构体 180 | step3: 创建新的工作量证明对象NewProofOfWork() 181 | step4:返回有效的哈希和nonce值Run()-->hash([]byte),nonce(int64) 182 | step5:修改NewBlock(),设置有效的hash和nonce 183 | 184 | 185 | 186 | B:难度系数 187 | Difficulty: 188 | 整个网路会通过调整"难度"这个变量来控制生成工作量证明所需要的算力 189 | 随着难度系数的增加,矿工通常在循环遍历4亿次随机数后仍未找到区块,则会启动超额随机数 190 | Bits = "0x17502ab7" 191 | coefficient系数: 192 | coefficient = 0x502ab7 193 | exponent指数: 194 | exponent = 0x17 195 | target = coefficient * Math.pow(2, 8 * (exponent - 3)) 196 | 目标hash:000000000000000000502ab700000000d6420b16625d309c4561290000000000 197 | 实际hash:00000000000000000041ff1cfc5f15f929c1a45d262f88e4db83680d90658c0c 198 | 所以:Bit值越小,难度越大,挖矿越难。 199 | 200 | 一般经过2016个区块后,bits的值就被调整一次。 201 | 202 | step1:修改ProofOfWork结构体,添加target 203 | step2:设置targetbits = 16 204 | step3:修改NewProofOfWork() 205 | step4:创建prepareData(),用于获取block对象的[]byte -------------------------------------------------------------------------------- /day02_03_Persistence/BLC/Block.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import ( 4 | "time" 5 | "bytes" 6 | "encoding/gob" 7 | "log" 8 | ) 9 | 10 | type Block struct { 11 | //字段: 12 | //高度Height:其实就是区块的编号,第一个区块叫创世区块,高度为0 13 | Height int64 14 | //上一个区块的哈希值ProvHash: 15 | PrevBlockHash []byte 16 | //交易数据Data:目前先设计为[]byte,后期是Transaction 17 | Data [] byte 18 | //时间戳TimeStamp: 19 | TimeStamp int64 20 | //哈希值Hash:32个的字节,64个16进制数 21 | Hash []byte 22 | 23 | Nonce int64 24 | } 25 | 26 | func NewBlock(data string,provBlockHash []byte,height int64) *Block{ 27 | //创建区块 28 | block:=&Block{height,provBlockHash,[]byte(data),time.Now().Unix(),nil,0} 29 | //step5:设置block的hash和nonce 30 | //设置哈希 31 | //block.SetHash() 32 | //调用工作量证明的方法,并且返回有效的Hash和Nonce 33 | pow:=NewProofOfWork(block) 34 | hash,nonce:=pow.Run() 35 | block.Hash = hash 36 | block.Nonce = nonce 37 | 38 | 39 | return block 40 | } 41 | 42 | 43 | func CreateGenesisBlock(data string) *Block{ 44 | return NewBlock(data,make([] byte,32,32),0) 45 | } 46 | 47 | //将区块序列化,得到一个字节数组---区块的行为,设计为方法 48 | func (block *Block) Serilalize() []byte { 49 | //1.创建一个buffer 50 | var result bytes.Buffer 51 | //2.创建一个编码器 52 | encoder := gob.NewEncoder(&result) 53 | //3.编码--->打包 54 | err := encoder.Encode(block) 55 | if err != nil { 56 | log.Panic(err) 57 | } 58 | return result.Bytes() 59 | } 60 | 61 | //反序列化,得到一个区块---设计为函数 62 | func DeserializeBlock(blockBytes [] byte) *Block { 63 | var block Block 64 | var reader = bytes.NewReader(blockBytes) 65 | //1.创建一个解码器 66 | decoder := gob.NewDecoder(reader) 67 | //解包 68 | err := decoder.Decode(&block) 69 | if err != nil { 70 | log.Panic(err) 71 | } 72 | return &block 73 | } 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /day02_03_Persistence/BLC/BlockChain.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import ( 4 | "github.com/boltdb/bolt" 5 | "os" 6 | "fmt" 7 | "log" 8 | "math/big" 9 | "time" 10 | ) 11 | 12 | //step1:修改BlockChain的结构体 13 | type BlockChain struct { 14 | //Blocks []*Block //存储有序的区块 15 | Tip [] byte // 最近的取快递Hash值 16 | DB *bolt.DB //数据库对象 17 | } 18 | 19 | //step2:修改该方法 20 | func CreateBlockChainWithGenesisBlock(data string) *BlockChain { 21 | //1.先判断数据库是否存在,如果有,从数据库读取 22 | if dbExists() { 23 | fmt.Println("数据库已经存在。。") 24 | //A:打开数据库 25 | db, err := bolt.Open(DBNAME, 0600, nil) 26 | if err != nil { 27 | log.Fatal(err) 28 | } 29 | //defer db.Close() 30 | var blockchain *BlockChain 31 | //B:读取数据库 32 | err = db.View(func(tx *bolt.Tx) error { 33 | //C:打开表 34 | b := tx.Bucket([]byte(BLOCKTABLENAME)) 35 | if b != nil { 36 | //D:读取最后一个hash 37 | hash := b.Get([]byte("l")) 38 | //E:创建blockchain 39 | blockchain = &BlockChain{hash, db} 40 | } 41 | return nil 42 | }) 43 | if err != nil { 44 | log.Fatal(err) 45 | } 46 | return blockchain 47 | } 48 | 49 | //2.数据库不存在,说明第一次创建,然后存入到数据库中 50 | fmt.Println("数据库不存在。。") 51 | //A:创建创世区块 52 | //创建创世区块 53 | genesisBlock := CreateGenesisBlock(data) 54 | //B:打开数据库 55 | db, err := bolt.Open(DBNAME, 0600, nil) 56 | if err != nil { 57 | log.Fatal(err) 58 | } 59 | //defer db.Close() 60 | //C:存入数据表 61 | err = db.Update(func(tx *bolt.Tx) error { 62 | b, err := tx.CreateBucket([]byte(BLOCKTABLENAME)) 63 | if err != nil { 64 | log.Panic(err) 65 | } 66 | if b != nil { 67 | err = b.Put(genesisBlock.Hash, genesisBlock.Serilalize()) 68 | if err != nil { 69 | log.Panic("创世区块存储有误。。。") 70 | } 71 | //存储最新区块的hash 72 | b.Put([]byte("l"), genesisBlock.Hash) 73 | } 74 | return nil 75 | }) 76 | if err != nil { 77 | log.Panic(err) 78 | } 79 | 80 | //返回区块链对象 81 | return &BlockChain{genesisBlock.Hash, db} 82 | } 83 | 84 | //step4:修改该方法 85 | func (bc *BlockChain) AddBlockToBlockChain(data string) { 86 | //创建新区块 87 | //newBlock := NewBlock(data,prevHash,height) 88 | //添加到切片中 89 | //bc.Blocks = append(bc.Blocks,newBlock) 90 | //1.更新数据库 91 | err := bc.DB.Update(func(tx *bolt.Tx) error { 92 | //2.打开表 93 | b := tx.Bucket([]byte(BLOCKTABLENAME)) 94 | if b != nil { 95 | //2.根据最新块的hash读取数据,并反序列化最后一个区块 96 | blockBytes := b.Get(bc.Tip) 97 | lastBlock := DeserializeBlock(blockBytes) 98 | //3.创建新的区块 99 | newBlock := NewBlock(data, lastBlock.Hash, lastBlock.Height+1) 100 | //4.将新的区块序列化并存储 101 | err := b.Put(newBlock.Hash, newBlock.Serilalize()) 102 | if err != nil { 103 | log.Panic(err) 104 | } 105 | //5.更新最后一个哈希值,以及blockchain的tip 106 | b.Put([]byte("l"), newBlock.Hash) 107 | bc.Tip = newBlock.Hash 108 | } 109 | 110 | return nil 111 | }) 112 | if err != nil { 113 | log.Panic(err) 114 | } 115 | 116 | } 117 | 118 | //step3: 119 | //判断数据库是否存在 120 | func dbExists() bool { 121 | if _, err := os.Stat(DBNAME); os.IsNotExist(err) { 122 | return false 123 | } 124 | return true 125 | } 126 | 127 | //step5:新增方法,遍历数据库,打印输出所有的区块信息 128 | /* 129 | func (bc *BlockChain) PrintChains() { 130 | //1.根据bc的tip,获取最新的hash值,表示当前的hash 131 | var currentHash = bc.Tip 132 | //2.循环,根据当前hash读取数据,反序列化得到最后一个区块 133 | var count = 0 134 | block := new(Block) // var block *Block 135 | for { 136 | err := bc.DB.View(func(tx *bolt.Tx) error { 137 | b := tx.Bucket([]byte(BLOCKTABLENAME)) 138 | 139 | if b != nil { 140 | count++ 141 | fmt.Printf("第%d个区块的信息:\n", count) 142 | //获取当前hash对应的数据,并进行反序列化 143 | blockBytes := b.Get(currentHash) 144 | block = DeserializeBlock(blockBytes) 145 | fmt.Printf("\t高度:%d\n", block.Height) 146 | fmt.Printf("\t上一个区块的hash:%x\n", block.PrevBlockHash) 147 | fmt.Printf("\t当前的hash:%x\n", block.Hash) 148 | fmt.Printf("\t数据:%s\n", block.Data) 149 | //fmt.Printf("\t时间:%v\n", block.TimeStamp) 150 | fmt.Printf("\t时间:%s\n",time.Unix(block.TimeStamp,0).Format("2006-01-02 15:04:05")) 151 | fmt.Printf("\t次数:%d\n", block.Nonce) 152 | } 153 | 154 | return nil 155 | }) 156 | if err != nil { 157 | log.Panic(err) 158 | } 159 | //3.直到父hash值为0 160 | hashInt := new(big.Int) 161 | hashInt.SetBytes(block.PrevBlockHash) 162 | if big.NewInt(0).Cmp(hashInt) == 0 { 163 | break 164 | } 165 | //4.更新当前区块的hash值 166 | currentHash = block.PrevBlockHash 167 | } 168 | } 169 | */ 170 | 171 | //2.获取一个迭代器的方法 172 | func (bc *BlockChain) Iterator() *BlockChainIterator { 173 | return &BlockChainIterator{bc.Tip, bc.DB} 174 | } 175 | 176 | func (bc *BlockChain) PrintChains() { 177 | //1.获取迭代器对象 178 | bcIterator := bc.Iterator() 179 | 180 | var count = 0 181 | //2.循环迭代 182 | for { 183 | block := bcIterator.Next() 184 | count++ 185 | fmt.Printf("第%d个区块的信息:\n", count) 186 | //获取当前hash对应的数据,并进行反序列化 187 | fmt.Printf("\t高度:%d\n", block.Height) 188 | fmt.Printf("\t上一个区块的hash:%x\n", block.PrevBlockHash) 189 | fmt.Printf("\t当前的hash:%x\n", block.Hash) 190 | fmt.Printf("\t数据:%s\n", block.Data) 191 | //fmt.Printf("\t时间:%v\n", block.TimeStamp) 192 | fmt.Printf("\t时间:%s\n", time.Unix(block.TimeStamp, 0).Format("2006-01-02 15:04:05")) 193 | fmt.Printf("\t次数:%d\n", block.Nonce) 194 | 195 | //3.直到父hash值为0 196 | hashInt := new(big.Int) 197 | hashInt.SetBytes(block.PrevBlockHash) 198 | if big.NewInt(0).Cmp(hashInt) == 0 { 199 | break 200 | } 201 | } 202 | } 203 | 204 | -------------------------------------------------------------------------------- /day02_03_Persistence/BLC/BlockChainIterator.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import ( 4 | "github.com/boltdb/bolt" 5 | "log" 6 | ) 7 | 8 | //1.新增一个结构体 9 | type BlockChainIterator struct { 10 | CurrentHash [] byte //当前区块的hash 11 | DB *bolt.DB //数据库 12 | } 13 | 14 | 15 | 16 | 17 | //3.获取区块 18 | func (bcIterator *BlockChainIterator) Next() *Block { 19 | block:=new(Block) 20 | //1.打开数据库并读取 21 | err :=bcIterator.DB.View(func(tx *bolt.Tx) error { 22 | //2.打开数据表 23 | b:=tx.Bucket([]byte(BLOCKTABLENAME)) 24 | if b != nil{ 25 | //3.根据当前hash获取数据并反序列化 26 | blockBytes:=b.Get(bcIterator.CurrentHash) 27 | block = DeserializeBlock(blockBytes) 28 | //4.更新当前的hash 29 | bcIterator.CurrentHash = block.PrevBlockHash 30 | } 31 | 32 | return nil 33 | }) 34 | if err != nil{ 35 | log.Panic(err) 36 | } 37 | return block 38 | } 39 | 40 | 41 | -------------------------------------------------------------------------------- /day02_03_Persistence/BLC/Constant.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | const DBNAME = "blockchain.db" //数据库名 4 | const BLOCKTABLENAME = "blocks" //表名 5 | 6 | 7 | -------------------------------------------------------------------------------- /day02_03_Persistence/BLC/ProofOfWork.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import ( 4 | "math/big" 5 | "bytes" 6 | "crypto/sha256" 7 | "fmt" 8 | ) 9 | 10 | // 0000 0000 0000 0000 1001 0001 0000 .... 0001 11 | //256位Hash里面前面至少有16个零 12 | const TargetBit = 16 // 20 13 | 14 | type ProofOfWork struct { 15 | //要验证的区块 16 | Block *Block 17 | 18 | //大整数存储,目标哈希 19 | Target *big.Int 20 | } 21 | 22 | func NewProofOfWork(block *Block) *ProofOfWork { 23 | //1.创建一个big对象 0000000.....00001 24 | /* 25 | 0000 0001 26 | 0010 0000 27 | */ 28 | target := big.NewInt(1) 29 | 30 | //2.左移256-bits位 31 | target = target.Lsh(target, 256-TargetBit) 32 | 33 | return &ProofOfWork{block, target} 34 | } 35 | 36 | func (pow *ProofOfWork) Run() ([] byte, int64) { 37 | //1.将Block的属性拼接成字节数组 38 | //2.生成Hash 39 | //3.循环判断Hash的有效性,满足条件,跳出循环结束验证 40 | nonce := 0 41 | //var hashInt big.Int //用于存储新生成的hash 42 | hashInt := new(big.Int) 43 | var hash [32]byte 44 | for{ 45 | //获取字节数组 46 | dataBytes := pow.prepareData(nonce) 47 | //生成hash 48 | hash = sha256.Sum256(dataBytes) 49 | //fmt.Printf("%d: %x\n",nonce,hash) 50 | fmt.Printf("\r%d: %x",nonce,hash) 51 | //将hash存储到hashInt 52 | hashInt.SetBytes(hash[:]) 53 | //判断hashInt是否小于Block里的target 54 | /* 55 | Com compares x and y and returns: 56 | -1 if x < y 57 | 0 if x == y 58 | 1 if x > y 59 | */ 60 | if pow.Target.Cmp(hashInt) == 1{ 61 | break 62 | } 63 | nonce++ 64 | } 65 | fmt.Println() 66 | return hash[:], int64(nonce) 67 | } 68 | 69 | func (pow *ProofOfWork) prepareData(nonce int)[]byte{ 70 | data := bytes.Join( 71 | [][] byte{ 72 | pow.Block.PrevBlockHash, 73 | pow.Block.Data, 74 | IntToHex(pow.Block.TimeStamp), 75 | IntToHex(int64(TargetBit)), 76 | IntToHex(int64(nonce)), 77 | IntToHex(int64(pow.Block.Height)), 78 | }, 79 | [] byte{}, 80 | ) 81 | return data 82 | } 83 | -------------------------------------------------------------------------------- /day02_03_Persistence/BLC/utils.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import ( 4 | "bytes" 5 | "encoding/binary" 6 | "log" 7 | ) 8 | 9 | /* 10 | 将一个int64的整数:转为二进制后,每8bit一个byte。转为[]byte 11 | */ 12 | func IntToHex(num int64) []byte { 13 | buff := new(bytes.Buffer) 14 | //将二进制数据写入w 15 | //func Write(w io.Writer, order ByteOrder, data interface{}) error 16 | err := binary.Write(buff, binary.BigEndian, num) 17 | if err != nil { 18 | log.Panic(err) 19 | } 20 | //转为[]byte并返回 21 | return buff.Bytes() 22 | } 23 | -------------------------------------------------------------------------------- /day02_03_Persistence/bc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rubyhan1314/PublicChain/fd8b04084c29fe82efe813a0c30864ed1df00383/day02_03_Persistence/bc -------------------------------------------------------------------------------- /day02_03_Persistence/blockchain.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rubyhan1314/PublicChain/fd8b04084c29fe82efe813a0c30864ed1df00383/day02_03_Persistence/blockchain.db -------------------------------------------------------------------------------- /day02_03_Persistence/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "./BLC" 5 | "fmt" 6 | ) 7 | 8 | func main() { 9 | 10 | //7.测试创世区块存入数据库 11 | blockchain:=BLC.CreateBlockChainWithGenesisBlock("Genesis Block..") 12 | fmt.Println(blockchain) 13 | defer blockchain.DB.Close() 14 | //8.测试新添加的区块 15 | blockchain.AddBlockToBlockChain("Send 100RMB to wangergou") 16 | blockchain.AddBlockToBlockChain("Send 100RMB to lixiaohua") 17 | blockchain.AddBlockToBlockChain("Send 100RMB to rose") 18 | fmt.Println(blockchain) 19 | blockchain.PrintChains() 20 | 21 | } -------------------------------------------------------------------------------- /day02_04_CLI/BLC/Block.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import ( 4 | "time" 5 | "bytes" 6 | "encoding/gob" 7 | "log" 8 | ) 9 | 10 | type Block struct { 11 | //字段: 12 | //高度Height:其实就是区块的编号,第一个区块叫创世区块,高度为0 13 | Height int64 14 | //上一个区块的哈希值ProvHash: 15 | PrevBlockHash []byte 16 | //交易数据Data:目前先设计为[]byte,后期是Transaction 17 | Data [] byte 18 | //时间戳TimeStamp: 19 | TimeStamp int64 20 | //哈希值Hash:32个的字节,64个16进制数 21 | Hash []byte 22 | 23 | Nonce int64 24 | } 25 | 26 | func NewBlock(data string,provBlockHash []byte,height int64) *Block{ 27 | //创建区块 28 | block:=&Block{height,provBlockHash,[]byte(data),time.Now().Unix(),nil,0} 29 | //step5:设置block的hash和nonce 30 | //设置哈希 31 | //block.SetHash() 32 | //调用工作量证明的方法,并且返回有效的Hash和Nonce 33 | pow:=NewProofOfWork(block) 34 | hash,nonce:=pow.Run() 35 | block.Hash = hash 36 | block.Nonce = nonce 37 | 38 | 39 | return block 40 | } 41 | 42 | 43 | func CreateGenesisBlock(data string) *Block{ 44 | return NewBlock(data,make([] byte,32,32),0) 45 | } 46 | 47 | //将区块序列化,得到一个字节数组---区块的行为,设计为方法 48 | func (block *Block) Serilalize() []byte { 49 | //1.创建一个buffer 50 | var result bytes.Buffer 51 | //2.创建一个编码器 52 | encoder := gob.NewEncoder(&result) 53 | //3.编码--->打包 54 | err := encoder.Encode(block) 55 | if err != nil { 56 | log.Panic(err) 57 | } 58 | return result.Bytes() 59 | } 60 | 61 | //反序列化,得到一个区块---设计为函数 62 | func DeserializeBlock(blockBytes [] byte) *Block { 63 | var block Block 64 | var reader = bytes.NewReader(blockBytes) 65 | //1.创建一个解码器 66 | decoder := gob.NewDecoder(reader) 67 | //解包 68 | err := decoder.Decode(&block) 69 | if err != nil { 70 | log.Panic(err) 71 | } 72 | return &block 73 | } 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /day02_04_CLI/BLC/BlockChain.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import ( 4 | "github.com/boltdb/bolt" 5 | "os" 6 | "fmt" 7 | "log" 8 | "math/big" 9 | "time" 10 | ) 11 | 12 | type BlockChain struct { 13 | //Blocks []*Block //存储有序的区块 14 | Tip [] byte // 最近的取快递Hash值 15 | DB *bolt.DB //数据库对象 16 | } 17 | 18 | //修改该方法 19 | /* 20 | 1.仅仅用来创建区块链 21 | 如果数据库存在,证明区块链存在,直接结束该方法 22 | 否则进行创建创世区块,并存入数据库中 23 | */ 24 | func CreateBlockChainWithGenesisBlock(data string) { 25 | if dbExists() { 26 | fmt.Println("数据库已经存在。。。") 27 | return 28 | } 29 | 30 | // 31 | fmt.Println("创建创世区块:", data) 32 | //2.数据库不存在,说明第一次创建,然后存入到数据库中 33 | fmt.Println("数据库不存在。。") 34 | //A:创建创世区块 35 | //创建创世区块 36 | genesisBlock := CreateGenesisBlock(data) 37 | //B:打开数据库 38 | db, err := bolt.Open(DBNAME, 0600, nil) 39 | if err != nil { 40 | log.Fatal(err) 41 | } 42 | //defer db.Close() 43 | //C:存入数据表 44 | err = db.Update(func(tx *bolt.Tx) error { 45 | b, err := tx.CreateBucket([]byte(BLOCKTABLENAME)) 46 | if err != nil { 47 | log.Panic(err) 48 | } 49 | if b != nil { 50 | err = b.Put(genesisBlock.Hash, genesisBlock.Serilalize()) 51 | if err != nil { 52 | log.Panic("创世区块存储有误。。。") 53 | } 54 | //存储最新区块的hash 55 | b.Put([]byte("l"), genesisBlock.Hash) 56 | } 57 | return nil 58 | }) 59 | if err != nil { 60 | log.Panic(err) 61 | } 62 | 63 | //返回区块链对象 64 | //return &BlockChain{genesisBlock.Hash, db} 65 | } 66 | 67 | func (bc *BlockChain) AddBlockToBlockChain(data string) { 68 | //创建新区块 69 | //newBlock := NewBlock(data,prevHash,height) 70 | //添加到切片中 71 | //bc.Blocks = append(bc.Blocks,newBlock) 72 | //1.更新数据库 73 | err := bc.DB.Update(func(tx *bolt.Tx) error { 74 | //2.打开表 75 | b := tx.Bucket([]byte(BLOCKTABLENAME)) 76 | if b != nil { 77 | //2.根据最新块的hash读取数据,并反序列化最后一个区块 78 | blockBytes := b.Get(bc.Tip) 79 | lastBlock := DeserializeBlock(blockBytes) 80 | //3.创建新的区块 81 | newBlock := NewBlock(data, lastBlock.Hash, lastBlock.Height+1) 82 | //4.将新的区块序列化并存储 83 | err := b.Put(newBlock.Hash, newBlock.Serilalize()) 84 | if err != nil { 85 | log.Panic(err) 86 | } 87 | //5.更新最后一个哈希值,以及blockchain的tip 88 | b.Put([]byte("l"), newBlock.Hash) 89 | bc.Tip = newBlock.Hash 90 | } 91 | 92 | return nil 93 | }) 94 | if err != nil { 95 | log.Panic(err) 96 | } 97 | 98 | } 99 | 100 | //判断数据库是否存在 101 | func dbExists() bool { 102 | if _, err := os.Stat(DBNAME); os.IsNotExist(err) { 103 | return false 104 | } 105 | return true 106 | } 107 | 108 | /* 109 | func (bc *BlockChain) PrintChains() { 110 | //1.根据bc的tip,获取最新的hash值,表示当前的hash 111 | var currentHash = bc.Tip 112 | //2.循环,根据当前hash读取数据,反序列化得到最后一个区块 113 | var count = 0 114 | block := new(Block) // var block *Block 115 | for { 116 | err := bc.DB.View(func(tx *bolt.Tx) error { 117 | b := tx.Bucket([]byte(BLOCKTABLENAME)) 118 | 119 | if b != nil { 120 | count++ 121 | fmt.Printf("第%d个区块的信息:\n", count) 122 | //获取当前hash对应的数据,并进行反序列化 123 | blockBytes := b.Get(currentHash) 124 | block = DeserializeBlock(blockBytes) 125 | fmt.Printf("\t高度:%d\n", block.Height) 126 | fmt.Printf("\t上一个区块的hash:%x\n", block.PrevBlockHash) 127 | fmt.Printf("\t当前的hash:%x\n", block.Hash) 128 | fmt.Printf("\t数据:%s\n", block.Data) 129 | //fmt.Printf("\t时间:%v\n", block.TimeStamp) 130 | fmt.Printf("\t时间:%s\n",time.Unix(block.TimeStamp,0).Format("2006-01-02 15:04:05")) 131 | fmt.Printf("\t次数:%d\n", block.Nonce) 132 | } 133 | 134 | return nil 135 | }) 136 | if err != nil { 137 | log.Panic(err) 138 | } 139 | //3.直到父hash值为0 140 | hashInt := new(big.Int) 141 | hashInt.SetBytes(block.PrevBlockHash) 142 | if big.NewInt(0).Cmp(hashInt) == 0 { 143 | break 144 | } 145 | //4.更新当前区块的hash值 146 | currentHash = block.PrevBlockHash 147 | } 148 | } 149 | */ 150 | 151 | //2.获取一个迭代器的方法 152 | func (bc *BlockChain) Iterator() *BlockChainIterator { 153 | return &BlockChainIterator{bc.Tip, bc.DB} 154 | } 155 | 156 | func (bc *BlockChain) PrintChains() { 157 | //1.获取迭代器对象 158 | bcIterator := bc.Iterator() 159 | 160 | //2.循环迭代 161 | for { 162 | block := bcIterator.Next() 163 | fmt.Printf("第%d个区块的信息:\n", block.Height+1) 164 | //获取当前hash对应的数据,并进行反序列化 165 | fmt.Printf("\t高度:%d\n", block.Height) 166 | fmt.Printf("\t上一个区块的hash:%x\n", block.PrevBlockHash) 167 | fmt.Printf("\t当前的hash:%x\n", block.Hash) 168 | fmt.Printf("\t数据:%s\n", block.Data) 169 | //fmt.Printf("\t时间:%v\n", block.TimeStamp) 170 | fmt.Printf("\t时间:%s\n", time.Unix(block.TimeStamp, 0).Format("2006-01-02 15:04:05")) 171 | fmt.Printf("\t次数:%d\n", block.Nonce) 172 | 173 | //3.直到父hash值为0 174 | hashInt := new(big.Int) 175 | hashInt.SetBytes(block.PrevBlockHash) 176 | if big.NewInt(0).Cmp(hashInt) == 0 { 177 | break 178 | } 179 | } 180 | } 181 | 182 | //新增方法,用于获取区块链 183 | func GetBlockchainObject() *BlockChain { 184 | /* 185 | 1.如果数据库不存在,直接返回nil 186 | 2.读取数据库 187 | */ 188 | if !dbExists() { 189 | fmt.Println("数据库不存在,无法获取区块链。。") 190 | return nil 191 | } 192 | 193 | db, err := bolt.Open(DBNAME, 0600, nil) 194 | if err != nil { 195 | log.Fatal(err) 196 | } 197 | 198 | //defer db.Close() 199 | var blockchain *BlockChain 200 | //B:读取数据库 201 | err = db.View(func(tx *bolt.Tx) error { 202 | //C:打开表 203 | b := tx.Bucket([]byte(BLOCKTABLENAME)) 204 | if b != nil { 205 | //D:读取最后一个hash 206 | hash := b.Get([]byte("l")) 207 | //E:创建blockchain 208 | blockchain = &BlockChain{hash, db} 209 | } 210 | return nil 211 | }) 212 | if err != nil { 213 | log.Fatal(err) 214 | } 215 | return blockchain 216 | } 217 | -------------------------------------------------------------------------------- /day02_04_CLI/BLC/BlockChainIterator.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import ( 4 | "github.com/boltdb/bolt" 5 | "log" 6 | ) 7 | 8 | //1.新增一个结构体 9 | type BlockChainIterator struct { 10 | CurrentHash [] byte //当前区块的hash 11 | DB *bolt.DB //数据库 12 | } 13 | 14 | 15 | 16 | 17 | //3.获取区块 18 | func (bcIterator *BlockChainIterator) Next() *Block { 19 | block:=new(Block) 20 | //1.打开数据库并读取 21 | err :=bcIterator.DB.View(func(tx *bolt.Tx) error { 22 | //2.打开数据表 23 | b:=tx.Bucket([]byte(BLOCKTABLENAME)) 24 | if b != nil{ 25 | //3.根据当前hash获取数据并反序列化 26 | blockBytes:=b.Get(bcIterator.CurrentHash) 27 | block = DeserializeBlock(blockBytes) 28 | //4.更新当前的hash 29 | bcIterator.CurrentHash = block.PrevBlockHash 30 | } 31 | 32 | return nil 33 | }) 34 | if err != nil{ 35 | log.Panic(err) 36 | } 37 | return block 38 | } 39 | 40 | 41 | -------------------------------------------------------------------------------- /day02_04_CLI/BLC/CLI.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import ( 4 | "os" 5 | "fmt" 6 | "flag" 7 | "log" 8 | ) 9 | 10 | //step1: 11 | //CLI结构体 12 | type CLI struct { 13 | //Blockchain *BlockChain 14 | } 15 | 16 | //step2:添加Run方法 17 | func (cli *CLI) Run(){ 18 | //判断命令行参数的长度 19 | isValidArgs() 20 | 21 | //1.创建flagset标签对象 22 | addBlockCmd := flag.NewFlagSet("addblock",flag.ExitOnError) 23 | //fmt.Printf("%T\n",addBlockCmd) //*FlagSet 24 | printChainCmd:=flag.NewFlagSet("printchain",flag.ExitOnError) 25 | createBlockChainCmd:=flag.NewFlagSet("createblockchain",flag.ExitOnError) 26 | 27 | 28 | //2.设置标签后的参数 29 | flagAddBlockData:= addBlockCmd.String("data","helloworld..","交易数据") 30 | flagCreateBlockChainData := createBlockChainCmd.String("data","Genesis block data..","创世区块交易数据") 31 | 32 | //3.解析 33 | switch os.Args[1] { 34 | case "addblock": 35 | err:=addBlockCmd.Parse(os.Args[2:]) 36 | if err != nil{ 37 | log.Panic(err) 38 | } 39 | //fmt.Println("----",os.Args[2:]) 40 | 41 | case "printchain": 42 | err :=printChainCmd.Parse(os.Args[2:]) 43 | if err != nil{ 44 | log.Panic(err) 45 | } 46 | //fmt.Println("====",os.Args[2:]) 47 | 48 | 49 | case "createblockchain": 50 | err :=createBlockChainCmd.Parse(os.Args[2:]) 51 | if err != nil{ 52 | log.Panic(err) 53 | } 54 | 55 | default: 56 | printUsage() 57 | os.Exit(1)//退出 58 | } 59 | 60 | if addBlockCmd.Parsed(){ 61 | if *flagAddBlockData == ""{ 62 | printUsage() 63 | os.Exit(1) 64 | } 65 | cli.addBlock(*flagAddBlockData) 66 | } 67 | if printChainCmd.Parsed(){ 68 | cli.printChains() 69 | } 70 | 71 | if createBlockChainCmd.Parsed(){ 72 | if *flagCreateBlockChainData == ""{ 73 | printUsage() 74 | os.Exit(1) 75 | } 76 | cli.createGenesisBlockchain(*flagCreateBlockChainData) 77 | } 78 | 79 | } 80 | 81 | func isValidArgs(){ 82 | if len(os.Args) < 2{ 83 | printUsage() 84 | os.Exit(1) 85 | } 86 | } 87 | func printUsage(){ 88 | fmt.Println("Usage:") 89 | fmt.Println("\tcreateblockchain -data DATA -- 创建创世区块") 90 | fmt.Println("\taddblock -data Data -- 交易数据") 91 | fmt.Println("\tprintchain -- 输出信息") 92 | } 93 | 94 | func (cli *CLI)addBlock(data string){ 95 | bc:=GetBlockchainObject() 96 | if bc == nil{ 97 | fmt.Println("没有创世区块,无法添加。。") 98 | os.Exit(1) 99 | } 100 | defer bc.DB.Close() 101 | bc.AddBlockToBlockChain(data) 102 | } 103 | 104 | func (cli *CLI)printChains(){ 105 | bc:=GetBlockchainObject() 106 | if bc == nil{ 107 | fmt.Println("没有区块可以打印。。") 108 | os.Exit(1) 109 | } 110 | defer bc.DB.Close() 111 | bc.PrintChains() 112 | } 113 | func (cli *CLI) createGenesisBlockchain(data string){ 114 | //fmt.Println(data) 115 | CreateBlockChainWithGenesisBlock(data) 116 | 117 | } -------------------------------------------------------------------------------- /day02_04_CLI/BLC/Constant.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | const DBNAME = "blockchain.db" //数据库名 4 | const BLOCKTABLENAME = "blocks" //表名 5 | 6 | 7 | -------------------------------------------------------------------------------- /day02_04_CLI/BLC/ProofOfWork.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import ( 4 | "math/big" 5 | "bytes" 6 | "crypto/sha256" 7 | "fmt" 8 | ) 9 | 10 | // 0000 0000 0000 0000 1001 0001 0000 .... 0001 11 | //256位Hash里面前面至少有16个零 12 | const TargetBit = 16 // 20 13 | 14 | type ProofOfWork struct { 15 | //要验证的区块 16 | Block *Block 17 | 18 | //大整数存储,目标哈希 19 | Target *big.Int 20 | } 21 | 22 | func NewProofOfWork(block *Block) *ProofOfWork { 23 | //1.创建一个big对象 0000000.....00001 24 | /* 25 | 0000 0001 26 | 0010 0000 27 | */ 28 | target := big.NewInt(1) 29 | 30 | //2.左移256-bits位 31 | target = target.Lsh(target, 256-TargetBit) 32 | 33 | return &ProofOfWork{block, target} 34 | } 35 | 36 | func (pow *ProofOfWork) Run() ([] byte, int64) { 37 | //1.将Block的属性拼接成字节数组 38 | //2.生成Hash 39 | //3.循环判断Hash的有效性,满足条件,跳出循环结束验证 40 | nonce := 0 41 | //var hashInt big.Int //用于存储新生成的hash 42 | hashInt := new(big.Int) 43 | var hash [32]byte 44 | for{ 45 | //获取字节数组 46 | dataBytes := pow.prepareData(nonce) 47 | //生成hash 48 | hash = sha256.Sum256(dataBytes) 49 | //fmt.Printf("%d: %x\n",nonce,hash) 50 | fmt.Printf("\r%d: %x",nonce,hash) 51 | //将hash存储到hashInt 52 | hashInt.SetBytes(hash[:]) 53 | //判断hashInt是否小于Block里的target 54 | /* 55 | Com compares x and y and returns: 56 | -1 if x < y 57 | 0 if x == y 58 | 1 if x > y 59 | */ 60 | if pow.Target.Cmp(hashInt) == 1{ 61 | break 62 | } 63 | nonce++ 64 | } 65 | fmt.Println() 66 | return hash[:], int64(nonce) 67 | } 68 | 69 | func (pow *ProofOfWork) prepareData(nonce int)[]byte{ 70 | data := bytes.Join( 71 | [][] byte{ 72 | pow.Block.PrevBlockHash, 73 | pow.Block.Data, 74 | IntToHex(pow.Block.TimeStamp), 75 | IntToHex(int64(TargetBit)), 76 | IntToHex(int64(nonce)), 77 | IntToHex(int64(pow.Block.Height)), 78 | }, 79 | [] byte{}, 80 | ) 81 | return data 82 | } 83 | -------------------------------------------------------------------------------- /day02_04_CLI/BLC/utils.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import ( 4 | "bytes" 5 | "encoding/binary" 6 | "log" 7 | ) 8 | 9 | /* 10 | 将一个int64的整数:转为二进制后,每8bit一个byte。转为[]byte 11 | */ 12 | func IntToHex(num int64) []byte { 13 | buff := new(bytes.Buffer) 14 | //将二进制数据写入w 15 | //func Write(w io.Writer, order ByteOrder, data interface{}) error 16 | err := binary.Write(buff, binary.BigEndian, num) 17 | if err != nil { 18 | log.Panic(err) 19 | } 20 | //转为[]byte并返回 21 | return buff.Bytes() 22 | } 23 | -------------------------------------------------------------------------------- /day02_04_CLI/bc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rubyhan1314/PublicChain/fd8b04084c29fe82efe813a0c30864ed1df00383/day02_04_CLI/bc -------------------------------------------------------------------------------- /day02_04_CLI/blockchain.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rubyhan1314/PublicChain/fd8b04084c29fe82efe813a0c30864ed1df00383/day02_04_CLI/blockchain.db -------------------------------------------------------------------------------- /day02_04_CLI/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "./BLC" 5 | 6 | ) 7 | 8 | func main() { 9 | //1.测试Block 10 | //block:=BLC.NewBlock("I am a block",make([]byte,32,32),1) 11 | //fmt.Println(block) 12 | //2.测试创世区块 13 | //genesisBlock :=BLC.CreateGenesisBlock("Genesis Block..") 14 | //fmt.Println(genesisBlock) 15 | 16 | //3.测试区块链 17 | //genesisBlockChain := BLC.CreateBlockChainWithGenesisBlock() 18 | //fmt.Println(genesisBlockChain) 19 | //fmt.Println(genesisBlockChain.Blocks) 20 | //fmt.Println(genesisBlockChain.Blocks[0]) 21 | 22 | //4.测试添加新区块 23 | //blockChain:=BLC.CreateBlockChainWithGenesisBlock() 24 | //blockChain.AddBlockToBlockChain("Send 100RMB To Wangergou",blockChain.Blocks[len(blockChain.Blocks)-1].Height+1,blockChain.Blocks[len(blockChain.Blocks)-1].Hash) 25 | //blockChain.AddBlockToBlockChain("Send 300RMB To lixiaohua",blockChain.Blocks[len(blockChain.Blocks)-1].Height+1,blockChain.Blocks[len(blockChain.Blocks)-1].Hash) 26 | //blockChain.AddBlockToBlockChain("Send 500RMB To rose",blockChain.Blocks[len(blockChain.Blocks)-1].Height+1,blockChain.Blocks[len(blockChain.Blocks)-1].Hash) 27 | // 28 | //fmt.Println(blockChain) 29 | 30 | //5.测试序列化和反序列化 31 | //block:=BLC.NewBlock("helloworld",make([]byte,32,32),0) 32 | //data:=block.Serilalize() 33 | //fmt.Println(block) 34 | //fmt.Println(data) 35 | //block2:=BLC.DeserializeBlock(data) 36 | //fmt.Println(block2) 37 | 38 | //6.创建区块,存入数据库 39 | //打开数据库 40 | //block:=BLC.NewBlock("helloworld",make([]byte,32,32),0) 41 | //db,err := bolt.Open("my.db",0600,nil) 42 | //if err != nil{ 43 | // log.Fatal(err) 44 | //} 45 | // 46 | //defer db.Close() 47 | // 48 | //err = db.Update(func(tx *bolt.Tx) error { 49 | // //获取bucket,没有就创建新表 50 | // b := tx.Bucket([]byte("blocks")) 51 | // if b == nil{ 52 | // b,err = tx.CreateBucket([] byte("blocks")) 53 | // if err !=nil{ 54 | // log.Panic("创建表失败") 55 | // } 56 | // } 57 | // //添加数据 58 | // err = b.Put([]byte("l"),block.Serilalize()) 59 | // if err !=nil{ 60 | // log.Panic(err) 61 | // } 62 | // 63 | // return nil 64 | //}) 65 | //if err != nil{ 66 | // log.Panic(err) 67 | //} 68 | //err = db.View(func(tx *bolt.Tx) error { 69 | // b := tx.Bucket([]byte("blocks")) 70 | // if b !=nil{ 71 | // data := b.Get([]byte("l")) 72 | // //fmt.Printf("%s\n",data)//直接打印会乱码 73 | // //反序列化 74 | // block2:=BLC.DeserializeBlock(data) 75 | // //fmt.Println(block2) 76 | // fmt.Printf("%v\n",block2) 77 | // 78 | // } 79 | // return nil 80 | //}) 81 | 82 | //7.测试创世区块存入数据库 83 | //blockchain:=BLC.CreateBlockChainWithGenesisBlock("Genesis Block..") 84 | //fmt.Println(blockchain) 85 | //defer blockchain.DB.Close() 86 | 87 | //8.测试新添加的区块 88 | //blockchain.AddBlockToBlockChain("Send 100RMB to wangergou") 89 | //blockchain.AddBlockToBlockChain("Send 100RMB to lixiaohua") 90 | //blockchain.AddBlockToBlockChain("Send 100RMB to rose") 91 | //fmt.Println(blockchain) 92 | //blockchain.PrintChains() 93 | 94 | //9.CLI操作 95 | cli:=BLC.CLI{} 96 | cli.Run() 97 | 98 | 99 | } -------------------------------------------------------------------------------- /day03_05_Transaction/BLC/Block.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import ( 4 | "time" 5 | "bytes" 6 | "encoding/gob" 7 | "log" 8 | "crypto/sha256" 9 | ) 10 | //step2:修改Block的交易类型 11 | type Block struct { 12 | //字段: 13 | //高度Height:其实就是区块的编号,第一个区块叫创世区块,高度为0 14 | Height int64 15 | //上一个区块的哈希值ProvHash: 16 | PrevBlockHash []byte 17 | //交易数据Data:目前先设计为[]byte,后期是Transaction 18 | //Data [] byte 19 | Txs [] *Transaction 20 | //时间戳TimeStamp: 21 | TimeStamp int64 22 | //哈希值Hash:32个的字节,64个16进制数 23 | Hash []byte 24 | 25 | Nonce int64 26 | } 27 | 28 | func NewBlock(txs []*Transaction,provBlockHash []byte,height int64) *Block{ 29 | //创建区块 30 | block:=&Block{height,provBlockHash,txs,time.Now().Unix(),nil,0} 31 | //step5:设置block的hash和nonce 32 | //设置哈希 33 | //block.SetHash() 34 | //调用工作量证明的方法,并且返回有效的Hash和Nonce 35 | pow:=NewProofOfWork(block) 36 | hash,nonce:=pow.Run() 37 | block.Hash = hash 38 | block.Nonce = nonce 39 | 40 | 41 | return block 42 | } 43 | 44 | func CreateGenesisBlock(txs []*Transaction) *Block{ 45 | return NewBlock(txs,make([] byte,32,32),0) 46 | } 47 | 48 | //将区块序列化,得到一个字节数组---区块的行为,设计为方法 49 | func (block *Block) Serilalize() []byte { 50 | //1.创建一个buffer 51 | var result bytes.Buffer 52 | //2.创建一个编码器 53 | encoder := gob.NewEncoder(&result) 54 | //3.编码--->打包 55 | err := encoder.Encode(block) 56 | if err != nil { 57 | log.Panic(err) 58 | } 59 | return result.Bytes() 60 | } 61 | 62 | //反序列化,得到一个区块---设计为函数 63 | func DeserializeBlock(blockBytes [] byte) *Block { 64 | var block Block 65 | var reader = bytes.NewReader(blockBytes) 66 | //1.创建一个解码器 67 | decoder := gob.NewDecoder(reader) 68 | //解包 69 | err := decoder.Decode(&block) 70 | if err != nil { 71 | log.Panic(err) 72 | } 73 | return &block 74 | } 75 | 76 | //step4:新增方法 77 | //将Txs转为[]byte 78 | func (block *Block) HashTransactions()[]byte{ 79 | var txHashes [][] byte 80 | var txHash [32]byte 81 | for _,tx :=range block.Txs{ 82 | txHashes = append(txHashes,tx.TxID) 83 | } 84 | 85 | txHash = sha256.Sum256(bytes.Join(txHashes,[]byte{})) 86 | return txHash[:] 87 | } 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | -------------------------------------------------------------------------------- /day03_05_Transaction/BLC/BlockChainIterator.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import ( 4 | "github.com/boltdb/bolt" 5 | "log" 6 | ) 7 | 8 | //1.新增一个结构体 9 | type BlockChainIterator struct { 10 | CurrentHash [] byte //当前区块的hash 11 | DB *bolt.DB //数据库 12 | } 13 | 14 | 15 | 16 | 17 | //3.获取区块 18 | func (bcIterator *BlockChainIterator) Next() *Block { 19 | block:=new(Block) 20 | //1.打开数据库并读取 21 | err :=bcIterator.DB.View(func(tx *bolt.Tx) error { 22 | //2.打开数据表 23 | b:=tx.Bucket([]byte(BLOCKTABLENAME)) 24 | if b != nil{ 25 | //3.根据当前hash获取数据并反序列化 26 | blockBytes:=b.Get(bcIterator.CurrentHash) 27 | block = DeserializeBlock(blockBytes) 28 | //4.更新当前的hash 29 | bcIterator.CurrentHash = block.PrevBlockHash 30 | } 31 | 32 | return nil 33 | }) 34 | if err != nil{ 35 | log.Panic(err) 36 | } 37 | return block 38 | } 39 | 40 | 41 | -------------------------------------------------------------------------------- /day03_05_Transaction/BLC/CLI.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import ( 4 | "os" 5 | "fmt" 6 | "flag" 7 | "log" 8 | ) 9 | 10 | //step1: 11 | //CLI结构体 12 | type CLI struct { 13 | //Blockchain *BlockChain 14 | } 15 | 16 | //step2:添加Run方法 17 | func (cli *CLI) Run(){ 18 | //判断命令行参数的长度 19 | isValidArgs() 20 | 21 | //1.创建flagset标签对象 22 | sendBlockCmd := flag.NewFlagSet("send",flag.ExitOnError) 23 | //fmt.Printf("%T\n",addBlockCmd) //*FlagSet 24 | printChainCmd:=flag.NewFlagSet("printchain",flag.ExitOnError) 25 | createBlockChainCmd:=flag.NewFlagSet("createblockchain",flag.ExitOnError) 26 | getBalanceCmd:=flag.NewFlagSet("getbalance",flag.ExitOnError) 27 | 28 | //2.设置标签后的参数 29 | //flagAddBlockData:= addBlockCmd.String("data","helloworld..","交易数据") 30 | flagFromData:=sendBlockCmd.String("from","","转帐源地址") 31 | flagToData:=sendBlockCmd.String("to","","转帐目标地址") 32 | flagAmountData:=sendBlockCmd.String("amount","","转帐金额") 33 | flagCreateBlockChainData := createBlockChainCmd.String("address","","创世区块交易地址") 34 | flagGetBalanceData := getBalanceCmd.String("address","","要查询的某个账户的余额") 35 | 36 | 37 | //3.解析 38 | switch os.Args[1] { 39 | case "send": 40 | err:=sendBlockCmd.Parse(os.Args[2:]) 41 | if err != nil{ 42 | log.Panic(err) 43 | } 44 | //fmt.Println("----",os.Args[2:]) 45 | 46 | case "printchain": 47 | err :=printChainCmd.Parse(os.Args[2:]) 48 | if err != nil{ 49 | log.Panic(err) 50 | } 51 | //fmt.Println("====",os.Args[2:]) 52 | 53 | 54 | case "createblockchain": 55 | err :=createBlockChainCmd.Parse(os.Args[2:]) 56 | if err != nil{ 57 | log.Panic(err) 58 | } 59 | case "getbalance": 60 | err :=getBalanceCmd.Parse(os.Args[2:]) 61 | if err != nil{ 62 | log.Panic(err) 63 | } 64 | 65 | 66 | default: 67 | printUsage() 68 | os.Exit(1)//退出 69 | } 70 | 71 | if sendBlockCmd.Parsed(){ 72 | if *flagFromData == "" || *flagToData =="" ||*flagAmountData == "" { 73 | printUsage() 74 | os.Exit(1) 75 | } 76 | //cli.addBlock([]*Transaction{}) 77 | fmt.Println(*flagFromData) 78 | fmt.Println(*flagToData) 79 | fmt.Println(*flagAmountData) 80 | //fmt.Println(JSONToArray(*flagFrom)) 81 | //fmt.Println(JSONToArray(*flagTo)) 82 | //fmt.Println(JSONToArray(*flagAmount)) 83 | from:=JSONToArray(*flagFromData) 84 | to:=JSONToArray(*flagToData) 85 | amount:=JSONToArray(*flagAmountData) 86 | 87 | cli.send(from,to,amount) 88 | } 89 | if printChainCmd.Parsed(){ 90 | cli.printChains() 91 | } 92 | 93 | if createBlockChainCmd.Parsed(){ 94 | if *flagCreateBlockChainData == ""{ 95 | printUsage() 96 | os.Exit(1) 97 | } 98 | cli.createGenesisBlockchain(*flagCreateBlockChainData) 99 | } 100 | 101 | if getBalanceCmd.Parsed(){ 102 | if *flagGetBalanceData == ""{ 103 | fmt.Println("查询地址不能为空") 104 | printUsage() 105 | os.Exit(1) 106 | } 107 | cli.getBalance(*flagGetBalanceData) 108 | 109 | } 110 | 111 | } 112 | 113 | func isValidArgs(){ 114 | if len(os.Args) < 2{ 115 | printUsage() 116 | os.Exit(1) 117 | } 118 | } 119 | func printUsage(){ 120 | fmt.Println("Usage:") 121 | fmt.Println("\tcreateblockchain -address DATA -- 创建创世区块") 122 | fmt.Println("\tsend -from From -to To -amount Amount - 交易数据") 123 | fmt.Println("\tprintchain - 输出信息") 124 | fmt.Println("\tgetbalance -address DATA -- 查询账户余额") 125 | } 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | -------------------------------------------------------------------------------- /day03_05_Transaction/BLC/CLI_createBlockChain.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | func (cli *CLI) createGenesisBlockchain(address string){ 4 | //fmt.Println(data) 5 | CreateBlockChainWithGenesisBlock(address) 6 | 7 | } 8 | -------------------------------------------------------------------------------- /day03_05_Transaction/BLC/CLI_getBalance.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | ) 7 | 8 | //查询余额 9 | func (cli *CLI)getBalance(address string){ 10 | fmt.Println("查询余额:",address) 11 | bc := GetBlockchainObject() 12 | 13 | if bc == nil{ 14 | fmt.Println("数据库不存在,无法查询。。") 15 | os.Exit(1) 16 | } 17 | defer bc.DB.Close() 18 | //txOutputs:= bc.UnUTXOs(address) 19 | //for i,out:=range txOutputs{ 20 | // fmt.Println(i,"---->",out) 21 | //} 22 | balance:=bc.GetBalance(address,[]*Transaction{}) 23 | fmt.Printf("%s,一共有%d个Token\n",address,balance) 24 | } 25 | -------------------------------------------------------------------------------- /day03_05_Transaction/BLC/CLI_printChains.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | ) 7 | 8 | func (cli *CLI)printChains(){ 9 | bc:=GetBlockchainObject() 10 | if bc == nil{ 11 | fmt.Println("没有区块可以打印。。") 12 | os.Exit(1) 13 | } 14 | defer bc.DB.Close() 15 | bc.PrintChains() 16 | } -------------------------------------------------------------------------------- /day03_05_Transaction/BLC/CLI_send.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | ) 7 | 8 | //转账 9 | func (cli *CLI) send(from, to, amount [] string) { 10 | if !dbExists() { 11 | fmt.Println("数据库不存在。。。") 12 | os.Exit(1) 13 | } 14 | blockchain := GetBlockchainObject() 15 | 16 | blockchain.MineNewBlock(from, to, amount) 17 | defer blockchain.DB.Close() 18 | } 19 | -------------------------------------------------------------------------------- /day03_05_Transaction/BLC/Constant.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | const DBNAME = "blockchain.db" //数据库名 4 | const BLOCKTABLENAME = "blocks" //表名 5 | 6 | 7 | -------------------------------------------------------------------------------- /day03_05_Transaction/BLC/ProofOfWork.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import ( 4 | "math/big" 5 | "bytes" 6 | "crypto/sha256" 7 | "fmt" 8 | ) 9 | 10 | // 0000 0000 0000 0000 1001 0001 0000 .... 0001 11 | //256位Hash里面前面至少有16个零 12 | const TargetBit = 16 // 20 13 | 14 | type ProofOfWork struct { 15 | //要验证的区块 16 | Block *Block 17 | 18 | //大整数存储,目标哈希 19 | Target *big.Int 20 | } 21 | 22 | func NewProofOfWork(block *Block) *ProofOfWork { 23 | //1.创建一个big对象 0000000.....00001 24 | /* 25 | 0000 0001 26 | 0010 0000 27 | */ 28 | target := big.NewInt(1) 29 | 30 | //2.左移256-bits位 31 | target = target.Lsh(target, 256-TargetBit) 32 | 33 | return &ProofOfWork{block, target} 34 | } 35 | 36 | func (pow *ProofOfWork) Run() ([] byte, int64) { 37 | //1.将Block的属性拼接成字节数组 38 | //2.生成Hash 39 | //3.循环判断Hash的有效性,满足条件,跳出循环结束验证 40 | nonce := 0 41 | //var hashInt big.Int //用于存储新生成的hash 42 | hashInt := new(big.Int) 43 | var hash [32]byte 44 | for{ 45 | //获取字节数组 46 | dataBytes := pow.prepareData(nonce) 47 | //生成hash 48 | hash = sha256.Sum256(dataBytes) 49 | //fmt.Printf("%d: %x\n",nonce,hash) 50 | fmt.Printf("\r%d: %x",nonce,hash) 51 | //将hash存储到hashInt 52 | hashInt.SetBytes(hash[:]) 53 | //判断hashInt是否小于Block里的target 54 | /* 55 | Com compares x and y and returns: 56 | -1 if x < y 57 | 0 if x == y 58 | 1 if x > y 59 | */ 60 | if pow.Target.Cmp(hashInt) == 1{ 61 | break 62 | } 63 | nonce++ 64 | } 65 | fmt.Println() 66 | return hash[:], int64(nonce) 67 | } 68 | 69 | func (pow *ProofOfWork) prepareData(nonce int)[]byte{ 70 | data := bytes.Join( 71 | [][] byte{ 72 | pow.Block.PrevBlockHash, 73 | pow.Block.HashTransactions(),//此行代码改变 74 | IntToHex(pow.Block.TimeStamp), 75 | IntToHex(int64(TargetBit)), 76 | IntToHex(int64(nonce)), 77 | IntToHex(int64(pow.Block.Height)), 78 | }, 79 | [] byte{}, 80 | ) 81 | return data 82 | } 83 | -------------------------------------------------------------------------------- /day03_05_Transaction/BLC/Transaction.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import ( 4 | "bytes" 5 | "encoding/gob" 6 | "log" 7 | "crypto/sha256" 8 | "encoding/hex" 9 | "time" 10 | ) 11 | 12 | //step1:创建Transaction结构体 13 | type Transaction struct { 14 | //1.交易ID 15 | TxID []byte 16 | //2.输入 17 | Vins []*TXInput 18 | //3.输出 19 | Vouts [] *TXOuput 20 | } 21 | 22 | //step2: 23 | /* 24 | Transaction 创建分两种情况 25 | 1.创世区块创建时的Transaction 26 | 27 | 2.转账时产生的Transaction 28 | 29 | */ 30 | func NewCoinBaseTransaction(address string) *Transaction { 31 | txInput := &TXInput{[]byte{}, -1, "Genesis Data"} 32 | txOutput := &TXOuput{10, address} 33 | txCoinbase := &Transaction{[]byte{}, []*TXInput{txInput}, []*TXOuput{txOutput}} 34 | //设置hash值 35 | //txCoinbase.HashTransaction() 36 | txCoinbase.SetTxID() 37 | return txCoinbase 38 | } 39 | 40 | //设置交易ID,其实就是hash 41 | func (tx *Transaction) SetTxID() { 42 | var buff bytes.Buffer 43 | encoder := gob.NewEncoder(&buff) 44 | err := encoder.Encode(tx) 45 | if err != nil { 46 | log.Panic(err) 47 | } 48 | 49 | buffBytes:=bytes.Join([][]byte{IntToHex(time.Now().Unix()),buff.Bytes()},[]byte{}) 50 | 51 | hash := sha256.Sum256(buffBytes) 52 | tx.TxID = hash[:] 53 | } 54 | 55 | 56 | func NewSimpleTransaction(from,to string,amount int64,bc *BlockChain,txs []*Transaction)*Transaction{ 57 | var txInputs [] *TXInput 58 | var txOutputs [] *TXOuput 59 | 60 | balance, spendableUTXO := bc.FindSpendableUTXOs(from,amount,txs) 61 | 62 | 63 | //代表消费 64 | 65 | 66 | //txInput := &TXInput{bytes, 0, from} 67 | //txInputs = append(txInputs, txInput) 68 | 69 | for txID,indexArray:=range spendableUTXO{ 70 | txIDBytes,_:=hex.DecodeString(txID) 71 | for _,index:=range indexArray{ 72 | txInput := &TXInput{txIDBytes,index,from} 73 | txInputs = append(txInputs,txInput) 74 | } 75 | } 76 | 77 | //转账 78 | txOutput1 := &TXOuput{amount, to} 79 | txOutputs = append(txOutputs, txOutput1) 80 | 81 | //找零 82 | //txOutput2 := &TXOuput{10 - amount, from} 83 | //txOutput2 := &TXOuput{4 - amount, from} 84 | txOutput2 := &TXOuput{balance - amount, from} 85 | 86 | 87 | txOutputs = append(txOutputs, txOutput2) 88 | 89 | tx := &Transaction{[]byte{}, txInputs, txOutputs} 90 | //设置hash值 91 | tx.SetTxID() 92 | return tx 93 | } 94 | 95 | //判断当前交易是否是Coinbase交易 96 | func (tx *Transaction) IsCoinbaseTransaction() bool { 97 | return len(tx.Vins[0].TxID) == 0 && tx.Vins[0].Vout == -1 98 | } 99 | 100 | 101 | -------------------------------------------------------------------------------- /day03_05_Transaction/BLC/Transaction_TxInput.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | type TXInput struct { 4 | //1.交易的ID 5 | TxID [] byte 6 | //2.存储Txoutput的vout里面的索引 7 | Vout int 8 | //3.用户名 9 | ScriptSiq string 10 | } 11 | 12 | //判断当前txInput消费,和指定的address是否一致 13 | func (txInput *TXInput) UnLockWithAddress(address string) bool{ 14 | return txInput.ScriptSiq == address 15 | } 16 | 17 | 18 | -------------------------------------------------------------------------------- /day03_05_Transaction/BLC/Transaction_TxOutput.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | //交易的输出,就是币实际存储的地方 3 | type TXOuput struct { 4 | Value int64 5 | //一个锁定脚本(ScriptPubKey),要花这笔钱,必须要解锁该脚本。 6 | ScriptPubKey string //公钥:先理解为,用户名 7 | } 8 | 9 | //判断当前txOutput消费,和指定的address是否一致 10 | func (txOutput *TXOuput) UnLockWithAddress(address string) bool{ 11 | return txOutput.ScriptPubKey == address 12 | } -------------------------------------------------------------------------------- /day03_05_Transaction/BLC/Transaction_UTXO.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | //step1:创建一个结构体UTXO,用于表示所有未花费的 4 | type UTXO struct { 5 | TxID [] byte //当前Transaction的交易ID 6 | Index int //下标索引 7 | Output *TXOuput // 8 | } 9 | -------------------------------------------------------------------------------- /day03_05_Transaction/BLC/utils.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import ( 4 | "bytes" 5 | "encoding/binary" 6 | "log" 7 | "encoding/json" 8 | ) 9 | 10 | /* 11 | 将一个int64的整数:转为二进制后,每8bit一个byte。转为[]byte 12 | */ 13 | func IntToHex(num int64) []byte { 14 | buff := new(bytes.Buffer) 15 | //将二进制数据写入w 16 | //func Write(w io.Writer, order ByteOrder, data interface{}) error 17 | err := binary.Write(buff, binary.BigEndian, num) 18 | if err != nil { 19 | log.Panic(err) 20 | } 21 | //转为[]byte并返回 22 | return buff.Bytes() 23 | } 24 | 25 | /* 26 | Json字符串转为[] string数组 27 | */ 28 | func JSONToArray (jsonString string) [] string{ 29 | var sArr [] string 30 | if err := json.Unmarshal([]byte(jsonString),&sArr);err != nil{ 31 | log.Panic(err) 32 | } 33 | return sArr 34 | } 35 | -------------------------------------------------------------------------------- /day03_05_Transaction/bc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rubyhan1314/PublicChain/fd8b04084c29fe82efe813a0c30864ed1df00383/day03_05_Transaction/bc -------------------------------------------------------------------------------- /day03_05_Transaction/blockchain.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rubyhan1314/PublicChain/fd8b04084c29fe82efe813a0c30864ed1df00383/day03_05_Transaction/blockchain.db -------------------------------------------------------------------------------- /day03_05_Transaction/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "./BLC" 5 | ) 6 | 7 | func main() { 8 | //1.测试Block 9 | //block:=BLC.NewBlock("I am a block",make([]byte,32,32),1) 10 | //fmt.Println(block) 11 | //2.测试创世区块 12 | //genesisBlock :=BLC.CreateGenesisBlock("Genesis Block..") 13 | //fmt.Println(genesisBlock) 14 | 15 | //3.测试区块链 16 | //genesisBlockChain := BLC.CreateBlockChainWithGenesisBlock() 17 | //fmt.Println(genesisBlockChain) 18 | //fmt.Println(genesisBlockChain.Blocks) 19 | //fmt.Println(genesisBlockChain.Blocks[0]) 20 | 21 | //4.测试添加新区块 22 | //blockChain:=BLC.CreateBlockChainWithGenesisBlock() 23 | //blockChain.AddBlockToBlockChain("Send 100RMB To Wangergou",blockChain.Blocks[len(blockChain.Blocks)-1].Height+1,blockChain.Blocks[len(blockChain.Blocks)-1].Hash) 24 | //blockChain.AddBlockToBlockChain("Send 300RMB To lixiaohua",blockChain.Blocks[len(blockChain.Blocks)-1].Height+1,blockChain.Blocks[len(blockChain.Blocks)-1].Hash) 25 | //blockChain.AddBlockToBlockChain("Send 500RMB To rose",blockChain.Blocks[len(blockChain.Blocks)-1].Height+1,blockChain.Blocks[len(blockChain.Blocks)-1].Hash) 26 | // 27 | //fmt.Println(blockChain) 28 | 29 | //5.测试序列化和反序列化 30 | //block:=BLC.NewBlock("helloworld",make([]byte,32,32),0) 31 | //data:=block.Serilalize() 32 | //fmt.Println(block) 33 | //fmt.Println(data) 34 | //block2:=BLC.DeserializeBlock(data) 35 | //fmt.Println(block2) 36 | 37 | //6.创建区块,存入数据库 38 | //打开数据库 39 | //block:=BLC.NewBlock("helloworld",make([]byte,32,32),0) 40 | //db,err := bolt.Open("my.db",0600,nil) 41 | //if err != nil{ 42 | // log.Fatal(err) 43 | //} 44 | // 45 | //defer db.Close() 46 | // 47 | //err = db.Update(func(tx *bolt.Tx) error { 48 | // //获取bucket,没有就创建新表 49 | // b := tx.Bucket([]byte("blocks")) 50 | // if b == nil{ 51 | // b,err = tx.CreateBucket([] byte("blocks")) 52 | // if err !=nil{ 53 | // log.Panic("创建表失败") 54 | // } 55 | // } 56 | // //添加数据 57 | // err = b.Put([]byte("l"),block.Serilalize()) 58 | // if err !=nil{ 59 | // log.Panic(err) 60 | // } 61 | // 62 | // return nil 63 | //}) 64 | //if err != nil{ 65 | // log.Panic(err) 66 | //} 67 | //err = db.View(func(tx *bolt.Tx) error { 68 | // b := tx.Bucket([]byte("blocks")) 69 | // if b !=nil{ 70 | // data := b.Get([]byte("l")) 71 | // //fmt.Printf("%s\n",data)//直接打印会乱码 72 | // //反序列化 73 | // block2:=BLC.DeserializeBlock(data) 74 | // //fmt.Println(block2) 75 | // fmt.Printf("%v\n",block2) 76 | // 77 | // } 78 | // return nil 79 | //}) 80 | 81 | //7.测试创世区块存入数据库 82 | //blockchain:=BLC.CreateBlockChainWithGenesisBlock("Genesis Block..") 83 | //fmt.Println(blockchain) 84 | //defer blockchain.DB.Close() 85 | //8.测试新添加的区块 86 | //blockchain.AddBlockToBlockChain("Send 100RMB to wangergou") 87 | //blockchain.AddBlockToBlockChain("Send 100RMB to lixiaohua") 88 | //blockchain.AddBlockToBlockChain("Send 100RMB to rose") 89 | //fmt.Println(blockchain) 90 | //blockchain.PrintChains() 91 | 92 | //9.CLI操作 93 | cli:=BLC.CLI{} 94 | cli.Run() 95 | 96 | 97 | } -------------------------------------------------------------------------------- /day04_06_Address/BLC/Block.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import ( 4 | "time" 5 | "bytes" 6 | "encoding/gob" 7 | "log" 8 | "crypto/sha256" 9 | ) 10 | //step2:修改Block的交易类型 11 | type Block struct { 12 | //字段: 13 | //高度Height:其实就是区块的编号,第一个区块叫创世区块,高度为0 14 | Height int64 15 | //上一个区块的哈希值ProvHash: 16 | PrevBlockHash []byte 17 | //交易数据Data:目前先设计为[]byte,后期是Transaction 18 | //Data [] byte 19 | Txs [] *Transaction 20 | //时间戳TimeStamp: 21 | TimeStamp int64 22 | //哈希值Hash:32个的字节,64个16进制数 23 | Hash []byte 24 | 25 | Nonce int64 26 | } 27 | 28 | func NewBlock(txs []*Transaction,provBlockHash []byte,height int64) *Block{ 29 | //创建区块 30 | block:=&Block{height,provBlockHash,txs,time.Now().Unix(),nil,0} 31 | //step5:设置block的hash和nonce 32 | //设置哈希 33 | //block.SetHash() 34 | //调用工作量证明的方法,并且返回有效的Hash和Nonce 35 | pow:=NewProofOfWork(block) 36 | hash,nonce:=pow.Run() 37 | block.Hash = hash 38 | block.Nonce = nonce 39 | 40 | 41 | return block 42 | } 43 | 44 | func CreateGenesisBlock(txs []*Transaction) *Block{ 45 | return NewBlock(txs,make([] byte,32,32),0) 46 | } 47 | 48 | //将区块序列化,得到一个字节数组---区块的行为,设计为方法 49 | func (block *Block) Serilalize() []byte { 50 | //1.创建一个buffer 51 | var result bytes.Buffer 52 | //2.创建一个编码器 53 | encoder := gob.NewEncoder(&result) 54 | //3.编码--->打包 55 | err := encoder.Encode(block) 56 | if err != nil { 57 | log.Panic(err) 58 | } 59 | return result.Bytes() 60 | } 61 | 62 | //反序列化,得到一个区块---设计为函数 63 | func DeserializeBlock(blockBytes [] byte) *Block { 64 | var block Block 65 | var reader = bytes.NewReader(blockBytes) 66 | //1.创建一个解码器 67 | decoder := gob.NewDecoder(reader) 68 | //解包 69 | err := decoder.Decode(&block) 70 | if err != nil { 71 | log.Panic(err) 72 | } 73 | return &block 74 | } 75 | 76 | //step4:新增方法 77 | //将Txs转为[]byte 78 | func (block *Block) HashTransactions()[]byte{ 79 | var txHashes [][] byte 80 | var txHash [32]byte 81 | for _,tx :=range block.Txs{ 82 | txHashes = append(txHashes,tx.TxID) 83 | } 84 | 85 | txHash = sha256.Sum256(bytes.Join(txHashes,[]byte{})) 86 | return txHash[:] 87 | } 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | -------------------------------------------------------------------------------- /day04_06_Address/BLC/BlockChainIterator.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import ( 4 | "github.com/boltdb/bolt" 5 | "log" 6 | ) 7 | 8 | //1.新增一个结构体 9 | type BlockChainIterator struct { 10 | CurrentHash [] byte //当前区块的hash 11 | DB *bolt.DB //数据库 12 | } 13 | 14 | 15 | 16 | 17 | //3.获取区块 18 | func (bcIterator *BlockChainIterator) Next() *Block { 19 | block:=new(Block) 20 | //1.打开数据库并读取 21 | err :=bcIterator.DB.View(func(tx *bolt.Tx) error { 22 | //2.打开数据表 23 | b:=tx.Bucket([]byte(BLOCKTABLENAME)) 24 | if b != nil{ 25 | //3.根据当前hash获取数据并反序列化 26 | blockBytes:=b.Get(bcIterator.CurrentHash) 27 | block = DeserializeBlock(blockBytes) 28 | //4.更新当前的hash 29 | bcIterator.CurrentHash = block.PrevBlockHash 30 | } 31 | 32 | return nil 33 | }) 34 | if err != nil{ 35 | log.Panic(err) 36 | } 37 | return block 38 | } 39 | 40 | 41 | -------------------------------------------------------------------------------- /day04_06_Address/BLC/CLI.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import ( 4 | "os" 5 | "fmt" 6 | "flag" 7 | "log" 8 | ) 9 | 10 | //step1: 11 | //CLI结构体 12 | type CLI struct { 13 | //Blockchain *BlockChain 14 | } 15 | 16 | //step2:添加Run方法 17 | func (cli *CLI) Run() { 18 | //判断命令行参数的长度 19 | isValidArgs() 20 | 21 | //1.创建flagset标签对象 22 | createWalletCmd := flag.NewFlagSet("createwallet", flag.ExitOnError) 23 | addressListsCmd := flag.NewFlagSet("addresslists",flag.ExitOnError) 24 | 25 | sendBlockCmd := flag.NewFlagSet("send", flag.ExitOnError) 26 | //fmt.Printf("%T\n",addBlockCmd) //*FlagSet 27 | printChainCmd := flag.NewFlagSet("printchain", flag.ExitOnError) 28 | createBlockChainCmd := flag.NewFlagSet("createblockchain", flag.ExitOnError) 29 | getBalanceCmd := flag.NewFlagSet("getbalance", flag.ExitOnError) 30 | 31 | //2.设置标签后的参数 32 | //flagAddBlockData:= addBlockCmd.String("data","helloworld..","交易数据") 33 | flagFromData := sendBlockCmd.String("from", "", "转帐源地址") 34 | flagToData := sendBlockCmd.String("to", "", "转帐目标地址") 35 | flagAmountData := sendBlockCmd.String("amount", "", "转帐金额") 36 | flagCreateBlockChainData := createBlockChainCmd.String("address", "", "创世区块交易地址") 37 | flagGetBalanceData := getBalanceCmd.String("address", "", "要查询的某个账户的余额") 38 | 39 | //3.解析 40 | switch os.Args[1] { 41 | case "send": 42 | err := sendBlockCmd.Parse(os.Args[2:]) 43 | if err != nil { 44 | log.Panic(err) 45 | } 46 | //fmt.Println("----",os.Args[2:]) 47 | 48 | case "printchain": 49 | err := printChainCmd.Parse(os.Args[2:]) 50 | if err != nil { 51 | log.Panic(err) 52 | } 53 | //fmt.Println("====",os.Args[2:]) 54 | 55 | case "createblockchain": 56 | err := createBlockChainCmd.Parse(os.Args[2:]) 57 | if err != nil { 58 | log.Panic(err) 59 | } 60 | case "getbalance": 61 | err := getBalanceCmd.Parse(os.Args[2:]) 62 | if err != nil { 63 | log.Panic(err) 64 | } 65 | 66 | case "createwallet": 67 | err := createWalletCmd.Parse(os.Args[2:]) 68 | if err != nil { 69 | log.Panic(err) 70 | } 71 | case "addresslists": 72 | err := addressListsCmd.Parse(os.Args[2:]) 73 | if err != nil { 74 | log.Panic(err) 75 | } 76 | default: 77 | printUsage() 78 | os.Exit(1) //退出 79 | } 80 | 81 | if sendBlockCmd.Parsed() { 82 | if *flagFromData == "" || *flagToData == "" || *flagAmountData == "" { 83 | printUsage() 84 | os.Exit(1) 85 | } 86 | //cli.addBlock([]*Transaction{}) 87 | fmt.Println(*flagFromData) 88 | fmt.Println(*flagToData) 89 | fmt.Println(*flagAmountData) 90 | //fmt.Println(JSONToArray(*flagFrom)) 91 | //fmt.Println(JSONToArray(*flagTo)) 92 | //fmt.Println(JSONToArray(*flagAmount)) 93 | from := JSONToArray(*flagFromData) 94 | to := JSONToArray(*flagToData) 95 | amount := JSONToArray(*flagAmountData) 96 | 97 | for i := 0; i < len(from); i++ { 98 | if !IsValidForAddress([]byte(from[i])) || !IsValidForAddress([]byte(to[i])) { 99 | fmt.Println("钱包地址无效") 100 | printUsage() 101 | os.Exit(1) 102 | } 103 | } 104 | 105 | cli.send(from, to, amount) 106 | } 107 | if printChainCmd.Parsed() { 108 | cli.printChains() 109 | } 110 | 111 | if createBlockChainCmd.Parsed() { 112 | //if *flagCreateBlockChainData == "" { 113 | if !IsValidForAddress([]byte(*flagCreateBlockChainData)){ 114 | fmt.Println("创建地址无效") 115 | printUsage() 116 | os.Exit(1) 117 | } 118 | cli.createGenesisBlockchain(*flagCreateBlockChainData) 119 | } 120 | 121 | if getBalanceCmd.Parsed() { 122 | //if *flagGetBalanceData == "" { 123 | if !IsValidForAddress([]byte(*flagGetBalanceData)){ 124 | fmt.Println("查询地址无效") 125 | printUsage() 126 | os.Exit(1) 127 | } 128 | cli.getBalance(*flagGetBalanceData) 129 | 130 | } 131 | 132 | if createWalletCmd.Parsed() { 133 | //创建钱包 134 | cli.createWallet() 135 | } 136 | 137 | //获取所有的钱包地址 138 | if addressListsCmd.Parsed(){ 139 | cli.addressLists() 140 | } 141 | 142 | } 143 | 144 | func isValidArgs() { 145 | if len(os.Args) < 2 { 146 | printUsage() 147 | os.Exit(1) 148 | } 149 | } 150 | func printUsage() { 151 | fmt.Println("Usage:") 152 | fmt.Println("\tcreatewallet -- 创建钱包") 153 | fmt.Println("\taddresslists -- 输出所有钱包地址") 154 | fmt.Println("\tcreateblockchain -address DATA -- 创建创世区块") 155 | fmt.Println("\tsend -from From -to To -amount Amount - 交易数据") 156 | fmt.Println("\tprintchain - 输出信息:") 157 | fmt.Println("\tgetbalance -address DATA -- 查询账户余额") 158 | } 159 | -------------------------------------------------------------------------------- /day04_06_Address/BLC/CLI_addresslists.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import "fmt" 4 | 5 | func (cli *CLI)addressLists(){ 6 | fmt.Println("打印所有的钱包地址。。") 7 | //获取 8 | Wallets:=NewWallets() 9 | for address,_ := range Wallets.WalletsMap{ 10 | fmt.Println("address:",address) 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /day04_06_Address/BLC/CLI_createBlockChain.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | func (cli *CLI) createGenesisBlockchain(address string){ 4 | //fmt.Println(data) 5 | CreateBlockChainWithGenesisBlock(address) 6 | 7 | } 8 | -------------------------------------------------------------------------------- /day04_06_Address/BLC/CLI_createwallet.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | func (cli *CLI) createWallet(){ 4 | wallets:= NewWallets() 5 | wallets.CreateNewWallet() 6 | } 7 | -------------------------------------------------------------------------------- /day04_06_Address/BLC/CLI_getBalance.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | ) 7 | 8 | //查询余额 9 | func (cli *CLI)getBalance(address string){ 10 | fmt.Println("查询余额:",address) 11 | bc := GetBlockchainObject() 12 | 13 | if bc == nil{ 14 | fmt.Println("数据库不存在,无法查询。。") 15 | os.Exit(1) 16 | } 17 | defer bc.DB.Close() 18 | //txOutputs:= bc.UnUTXOs(address) 19 | //for i,out:=range txOutputs{ 20 | // fmt.Println(i,"---->",out) 21 | //} 22 | balance:=bc.GetBalance(address,[]*Transaction{}) 23 | fmt.Printf("%s,一共有%d个Token\n",address,balance) 24 | } 25 | -------------------------------------------------------------------------------- /day04_06_Address/BLC/CLI_printChains.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | ) 7 | 8 | func (cli *CLI)printChains(){ 9 | bc:=GetBlockchainObject() 10 | if bc == nil{ 11 | fmt.Println("没有区块可以打印。。") 12 | os.Exit(1) 13 | } 14 | defer bc.DB.Close() 15 | bc.PrintChains() 16 | } -------------------------------------------------------------------------------- /day04_06_Address/BLC/CLI_send.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | ) 7 | 8 | //转账 9 | func (cli *CLI) send(from, to, amount [] string) { 10 | if !dbExists() { 11 | fmt.Println("数据库不存在。。。") 12 | os.Exit(1) 13 | } 14 | blockchain := GetBlockchainObject() 15 | 16 | blockchain.MineNewBlock(from, to, amount) 17 | defer blockchain.DB.Close() 18 | } 19 | -------------------------------------------------------------------------------- /day04_06_Address/BLC/Constant.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | const DBNAME = "blockchain.db" //数据库名 4 | const BLOCKTABLENAME = "blocks" //表名 5 | 6 | 7 | -------------------------------------------------------------------------------- /day04_06_Address/BLC/ProofOfWork.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import ( 4 | "math/big" 5 | "bytes" 6 | "crypto/sha256" 7 | "fmt" 8 | ) 9 | 10 | // 0000 0000 0000 0000 1001 0001 0000 .... 0001 11 | //256位Hash里面前面至少有16个零 12 | const TargetBit = 16 // 20 13 | 14 | type ProofOfWork struct { 15 | //要验证的区块 16 | Block *Block 17 | 18 | //大整数存储,目标哈希 19 | Target *big.Int 20 | } 21 | 22 | func NewProofOfWork(block *Block) *ProofOfWork { 23 | //1.创建一个big对象 0000000.....00001 24 | /* 25 | 0000 0001 26 | 0010 0000 27 | */ 28 | target := big.NewInt(1) 29 | 30 | //2.左移256-bits位 31 | target = target.Lsh(target, 256-TargetBit) 32 | 33 | return &ProofOfWork{block, target} 34 | } 35 | 36 | func (pow *ProofOfWork) Run() ([] byte, int64) { 37 | //1.将Block的属性拼接成字节数组 38 | //2.生成Hash 39 | //3.循环判断Hash的有效性,满足条件,跳出循环结束验证 40 | nonce := 0 41 | //var hashInt big.Int //用于存储新生成的hash 42 | hashInt := new(big.Int) 43 | var hash [32]byte 44 | for{ 45 | //获取字节数组 46 | dataBytes := pow.prepareData(nonce) 47 | //生成hash 48 | hash = sha256.Sum256(dataBytes) 49 | //fmt.Printf("%d: %x\n",nonce,hash) 50 | fmt.Printf("\r%d: %x",nonce,hash) 51 | //将hash存储到hashInt 52 | hashInt.SetBytes(hash[:]) 53 | //判断hashInt是否小于Block里的target 54 | /* 55 | Com compares x and y and returns: 56 | -1 if x < y 57 | 0 if x == y 58 | 1 if x > y 59 | */ 60 | if pow.Target.Cmp(hashInt) == 1{ 61 | break 62 | } 63 | nonce++ 64 | } 65 | fmt.Println() 66 | return hash[:], int64(nonce) 67 | } 68 | 69 | func (pow *ProofOfWork) prepareData(nonce int)[]byte{ 70 | data := bytes.Join( 71 | [][] byte{ 72 | pow.Block.PrevBlockHash, 73 | pow.Block.HashTransactions(), 74 | IntToHex(pow.Block.TimeStamp), 75 | IntToHex(int64(TargetBit)), 76 | IntToHex(int64(nonce)), 77 | IntToHex(int64(pow.Block.Height)), 78 | }, 79 | [] byte{}, 80 | ) 81 | return data 82 | } 83 | -------------------------------------------------------------------------------- /day04_06_Address/BLC/Transaction.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import ( 4 | "bytes" 5 | "encoding/gob" 6 | "log" 7 | "crypto/sha256" 8 | "encoding/hex" 9 | "time" 10 | ) 11 | 12 | //step1:创建Transaction结构体 13 | type Transaction struct { 14 | //1.交易ID 15 | TxID []byte 16 | //2.输入 17 | Vins []*TXInput 18 | //3.输出 19 | Vouts [] *TXOuput 20 | } 21 | 22 | //step2: 23 | /* 24 | Transaction 创建分两种情况 25 | 1.创世区块创建时的Transaction 26 | 27 | 2.转账时产生的Transaction 28 | 29 | */ 30 | func NewCoinBaseTransaction(address string) *Transaction { 31 | txInput := &TXInput{[]byte{}, -1, "Genesis Data"} 32 | txOutput := &TXOuput{10, address} 33 | txCoinbase := &Transaction{[]byte{}, []*TXInput{txInput}, []*TXOuput{txOutput}} 34 | //设置hash值 35 | //txCoinbase.HashTransaction() 36 | txCoinbase.SetTxID() 37 | return txCoinbase 38 | } 39 | 40 | //设置交易ID,其实就是hash 41 | func (tx *Transaction) SetTxID() { 42 | var buff bytes.Buffer 43 | encoder := gob.NewEncoder(&buff) 44 | err := encoder.Encode(tx) 45 | if err != nil { 46 | log.Panic(err) 47 | } 48 | 49 | buffBytes:=bytes.Join([][]byte{IntToHex(time.Now().Unix()),buff.Bytes()},[]byte{}) 50 | 51 | hash := sha256.Sum256(buffBytes) 52 | tx.TxID = hash[:] 53 | } 54 | 55 | 56 | func NewSimpleTransaction(from,to string,amount int64,bc *BlockChain,txs []*Transaction)*Transaction{ 57 | var txInputs [] *TXInput 58 | var txOutputs [] *TXOuput 59 | 60 | balance, spendableUTXO := bc.FindSpendableUTXOs(from,amount,txs) 61 | 62 | 63 | //代表消费 64 | 65 | //bytes,_:=hex.DecodeString("558e697b0f0f7adfcb6b8f8b542fb5980cd78a58a103a7a9a19e274aabefed5e") 66 | //bytes,_:=hex.DecodeString("0704aabb159bd1b276dc819b85e49581d80eb53aba69a48c84dc12442b799d8e") 67 | 68 | //txInput := &TXInput{bytes, 0, from} 69 | //txInputs = append(txInputs, txInput) 70 | 71 | for txID,indexArray:=range spendableUTXO{ 72 | txIDBytes,_:=hex.DecodeString(txID) 73 | for _,index:=range indexArray{ 74 | txInput := &TXInput{txIDBytes,index,from} 75 | txInputs = append(txInputs,txInput) 76 | } 77 | } 78 | 79 | //转账 80 | txOutput1 := &TXOuput{amount, to} 81 | txOutputs = append(txOutputs, txOutput1) 82 | 83 | //找零 84 | //txOutput2 := &TXOuput{10 - amount, from} 85 | //txOutput2 := &TXOuput{4 - amount, from} 86 | txOutput2 := &TXOuput{balance - amount, from} 87 | 88 | 89 | txOutputs = append(txOutputs, txOutput2) 90 | 91 | tx := &Transaction{[]byte{}, txInputs, txOutputs} 92 | //设置hash值 93 | tx.SetTxID() 94 | return tx 95 | } 96 | 97 | //判断当前交易是否是Coinbase交易 98 | func (tx *Transaction) IsCoinbaseTransaction() bool { 99 | return len(tx.Vins[0].TxID) == 0 && tx.Vins[0].Vout == -1 100 | } 101 | 102 | 103 | -------------------------------------------------------------------------------- /day04_06_Address/BLC/Transaction_TxInput.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | type TXInput struct { 4 | //1.交易的ID 5 | TxID [] byte 6 | //2.存储Txoutput的vout里面的索引 7 | Vout int 8 | //3.用户名 9 | ScriptSiq string 10 | } 11 | 12 | //判断当前txInput消费,和指定的address是否一致 13 | func (txInput *TXInput) UnLockWithAddress(address string) bool{ 14 | return txInput.ScriptSiq == address 15 | } 16 | 17 | 18 | -------------------------------------------------------------------------------- /day04_06_Address/BLC/Transaction_TxOutput.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | //交易的输出,就是币实际存储的地方 3 | type TXOuput struct { 4 | Value int64 5 | //一个锁定脚本(ScriptPubKey),要花这笔钱,必须要解锁该脚本。 6 | ScriptPubKey string //公钥:先理解为,用户名 7 | } 8 | 9 | //判断当前txOutput消费,和指定的address是否一致 10 | func (txOutput *TXOuput) UnLockWithAddress(address string) bool{ 11 | return txOutput.ScriptPubKey == address 12 | } -------------------------------------------------------------------------------- /day04_06_Address/BLC/Transaction_UTXO.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | //step1:创建一个结构体UTXO,用于表示所有未花费的 4 | type UTXO struct { 5 | TxID [] byte //当前Transaction的交易ID 6 | Index int //下标索引 7 | Output *TXOuput // 8 | } 9 | -------------------------------------------------------------------------------- /day04_06_Address/BLC/Wallet.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import ( 4 | "crypto/ecdsa" 5 | "crypto/elliptic" 6 | "crypto/rand" 7 | "log" 8 | "crypto/sha256" 9 | "golang.org/x/crypto/ripemd160" 10 | "bytes" 11 | ) 12 | 13 | //step1:创建一个钱包 14 | type Wallet struct { 15 | //1.私钥 16 | PrivateKey ecdsa.PrivateKey 17 | //2.公钥 18 | PublicKey [] byte 19 | } 20 | 21 | //step2:产生一对密钥 22 | func newKeyPair() (ecdsa.PrivateKey, []byte) { 23 | /* 24 | 1.通过椭圆曲线算法,随机产生私钥 25 | 2.根据私钥生成公钥 26 | 27 | elliptic:椭圆 28 | curve:曲线 29 | ecc:椭圆曲线加密 30 | ecdsa:elliptic curve digital signature algorithm,椭圆曲线数字签名算法 31 | 比特币使用SECP256K1算法,p256是ecdsa算法中的一种 32 | 33 | */ 34 | //椭圆加密 35 | curve := elliptic.P256() //椭圆加密算法,得到一个椭圆曲线值,全称:SECP256k1 36 | private, err := ecdsa.GenerateKey(curve, rand.Reader) 37 | if err != nil { 38 | log.Panic(err) 39 | } 40 | //生成公钥 41 | pubKey := append(private.PublicKey.X.Bytes(), private.PublicKey.Y.Bytes()...) 42 | return *private, pubKey 43 | } 44 | 45 | //step3:提供一个方法用于获取钱包 46 | func NewWallet() *Wallet { 47 | privateKey, publicKey := newKeyPair() 48 | //fmt.Println("privateKey:", privateKey, ",publicKey:", publicKey) 49 | return &Wallet{privateKey, publicKey} 50 | } 51 | 52 | //step4:根据一个公钥获取对应的地址 53 | /* 54 | 将公钥sha2561次,再160,1次 55 | 然后version+hash 56 | */ 57 | func (w *Wallet) GetAddress() [] byte { 58 | //1.先将公钥进行一次hash256,一次160,得到pubKeyHash 59 | pubKeyHash := PubKeyHash(w.PublicKey) 60 | //2.添加版本号 61 | versioned_payload := append([]byte{version}, pubKeyHash...) 62 | // 3.获取校验和,将pubKeyhash,两次sha256后,取前4位 63 | checkSumBytes := CheckSum(versioned_payload) 64 | full_payload := append(versioned_payload, checkSumBytes...) 65 | //fmt.Println(len(full_payload)) 66 | //4.Base58 67 | address := Base58Encode(full_payload) 68 | return address 69 | 70 | } 71 | 72 | //一次sha256,再一次ripemd160,得到publicKeyHash 73 | func PubKeyHash(publicKey [] byte) []byte { 74 | //1.sha256 75 | hasher := sha256.New() 76 | hasher.Write(publicKey) 77 | hash := hasher.Sum(nil) 78 | 79 | //2.ripemd160 80 | ripemder := ripemd160.New() 81 | ripemder.Write(hash) 82 | pubKeyHash := ripemder.Sum(nil) 83 | 84 | //返回 85 | return pubKeyHash 86 | } 87 | 88 | const version = byte(0x00) 89 | const addressChecksumLen = 4 90 | 91 | //获取验证码:将公钥哈希两次sha256,取前4位,就是校验和 92 | func CheckSum(payload []byte) []byte { 93 | firstSHA := sha256.Sum256(payload) 94 | secondSHA := sha256.Sum256(firstSHA[:]) 95 | return secondSHA[:addressChecksumLen] 96 | } 97 | 98 | 99 | 100 | //判断地址是否有效 101 | /* 102 | 根据地址,base58解码后获取byte[],获取校验和数组 103 | 使用 104 | */ 105 | func IsValidForAddress(address []byte) bool { 106 | full_payload := Base58Decode(address) 107 | //fmt.Println("检验version_public_checksumBytes:",full_payload) 108 | checkSumBytes := full_payload[len(full_payload)-addressChecksumLen:] 109 | //fmt.Println("检验checkSumBytes:",checkSumBytes) 110 | versioned_payload := full_payload[:len(full_payload)-addressChecksumLen] 111 | //fmt.Println("检验version_ripemd160:",versioned_payload) 112 | checkBytes := CheckSum(versioned_payload) 113 | //fmt.Println("检验checkBytes:",checkBytes) 114 | if bytes.Compare(checkSumBytes, checkBytes) == 0 { 115 | return true 116 | } 117 | return false 118 | } -------------------------------------------------------------------------------- /day04_06_Address/BLC/Wallets.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "io/ioutil" 7 | "log" 8 | "encoding/gob" 9 | "crypto/elliptic" 10 | "bytes" 11 | ) 12 | 13 | //1.创建钱包 14 | type Wallets struct { 15 | WalletsMap map[string]*Wallet 16 | } 17 | 18 | //2.创建一个钱包集合 19 | //创建钱包集合:文件中存在从文件中读取,否则新建一个 20 | const walletFile = "Wallets.dat" 21 | 22 | func NewWallets() *Wallets { 23 | //wallets := &WalletsMap{} 24 | //wallets.WalletsMap = make(map[string]*Wallet) 25 | //return wallets 26 | //1.判断钱包文件是否存在 27 | if _, err := os.Stat(walletFile); os.IsNotExist(err) { 28 | fmt.Println("文件不存在") 29 | wallets := &Wallets{} 30 | wallets.WalletsMap = make(map[string]*Wallet) 31 | return wallets 32 | } 33 | //2.否则读取文件中的数据 34 | fileContent, err := ioutil.ReadFile(walletFile) 35 | if err != nil { 36 | log.Panic(err) 37 | } 38 | var wallets Wallets 39 | gob.Register(elliptic.P256()) 40 | decoder := gob.NewDecoder(bytes.NewReader(fileContent)) 41 | err = decoder.Decode(&wallets) 42 | if err != nil { 43 | log.Panic(err) 44 | } 45 | return &wallets 46 | } 47 | 48 | //3.创建一个新钱包 49 | func (ws *Wallets) CreateNewWallet() { 50 | wallet := NewWallet() 51 | fmt.Printf("创建钱包地址:%s\n", wallet.GetAddress()) 52 | ws.WalletsMap[string(wallet.GetAddress())] = wallet 53 | 54 | //将钱包保存 55 | ws.SaveWallets() 56 | } 57 | 58 | /* 59 | 要让数据对象能在网络上传输或存储,我们需要进行编码和解码。 60 | 现在比较流行的编码方式有JSON,XML等。然而,Go在gob包中为我们提供了另一种方式,该方式编解码效率高于JSON。 61 | gob是Golang包自带的一个数据结构序列化的编码/解码工具 62 | */ 63 | func (ws *Wallets) SaveWallets() { 64 | var content bytes.Buffer 65 | //注册的目的,为了可以序列化任何类型,wallet结构体中有接口类型。将接口进行注册 66 | gob.Register(elliptic.P256()) //gob是Golang包自带的一个数据结构序列化的编码/解码工具 67 | encoder := gob.NewEncoder(&content) 68 | err := encoder.Encode(ws) 69 | if err != nil { 70 | log.Panic(err) 71 | } 72 | //将序列化后的数据写入到文件,原来的文件中的内容会被覆盖掉 73 | err = ioutil.WriteFile(walletFile, content.Bytes(), 0644) 74 | if err != nil { 75 | log.Panic(err) 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /day04_06_Address/BLC/base58.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | import ( 3 | "math/big" 4 | "bytes" 5 | ) 6 | 7 | //base64 8 | 9 | /* 10 | ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/ 11 | 0(零),O(大写的o),I(大写的i),l(小写的L),+,/ 12 | */ 13 | 14 | var b58Alphabet = []byte("123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz") 15 | 16 | //字节数组转Base58,编码 17 | func Base58Encode(input []byte)[]byte{ 18 | var result [] byte 19 | x := big.NewInt(0).SetBytes(input) 20 | 21 | base :=big.NewInt(int64(len(b58Alphabet))) 22 | zero:=big.NewInt(0) 23 | mod:= &big.Int{} 24 | for x.Cmp(zero) !=0{ 25 | x.DivMod(x,base,mod) 26 | result = append(result,b58Alphabet[mod.Int64()]) 27 | } 28 | ReverseBytes(result) 29 | for b:=range input{ 30 | if b == 0x00{ 31 | result = append([]byte{b58Alphabet[0]},result...) 32 | }else { 33 | break 34 | } 35 | } 36 | 37 | return result 38 | 39 | } 40 | 41 | //Base58转字节数组,解码 42 | func Base58Decode(input[] byte)[]byte{ 43 | result:=big.NewInt(0) 44 | zeroBytes := 0 45 | for b:=range input{ 46 | if b == 0x00{ 47 | zeroBytes++ 48 | } 49 | } 50 | payload := input[zeroBytes:] 51 | for _, b := range payload { 52 | charIndex := bytes.IndexByte(b58Alphabet, b) 53 | result.Mul(result, big.NewInt(58)) 54 | result.Add(result, big.NewInt(int64(charIndex))) 55 | } 56 | 57 | decoded := result.Bytes() 58 | decoded = append(bytes.Repeat([]byte{byte(0x00)}, zeroBytes), decoded...) 59 | 60 | return decoded 61 | } 62 | 63 | 64 | -------------------------------------------------------------------------------- /day04_06_Address/BLC/utils.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import ( 4 | "bytes" 5 | "encoding/binary" 6 | "log" 7 | "encoding/json" 8 | ) 9 | 10 | /* 11 | 将一个int64的整数:转为二进制后,每8bit一个byte。转为[]byte 12 | */ 13 | func IntToHex(num int64) []byte { 14 | buff := new(bytes.Buffer) 15 | //将二进制数据写入w 16 | //func Write(w io.Writer, order ByteOrder, data interface{}) error 17 | err := binary.Write(buff, binary.BigEndian, num) 18 | if err != nil { 19 | log.Panic(err) 20 | } 21 | //转为[]byte并返回 22 | return buff.Bytes() 23 | } 24 | 25 | /* 26 | Json字符串转为[] string数组 27 | */ 28 | func JSONToArray (jsonString string) [] string{ 29 | var sArr [] string 30 | if err := json.Unmarshal([]byte(jsonString),&sArr);err != nil{ 31 | log.Panic(err) 32 | } 33 | return sArr 34 | } 35 | 36 | 37 | //字节数组反转 38 | func ReverseBytes(data []byte) { 39 | for i, j := 0, len(data)-1; i < j; i, j = i+1, j-1 { 40 | data[i], data[j] = data[j], data[i] 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /day04_06_Address/Wallets.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rubyhan1314/PublicChain/fd8b04084c29fe82efe813a0c30864ed1df00383/day04_06_Address/Wallets.dat -------------------------------------------------------------------------------- /day04_06_Address/bc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rubyhan1314/PublicChain/fd8b04084c29fe82efe813a0c30864ed1df00383/day04_06_Address/bc -------------------------------------------------------------------------------- /day04_06_Address/blockchain.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rubyhan1314/PublicChain/fd8b04084c29fe82efe813a0c30864ed1df00383/day04_06_Address/blockchain.db -------------------------------------------------------------------------------- /day04_06_Address/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "./BLC" 5 | ) 6 | 7 | func main() { 8 | //1.测试Block 9 | //block:=BLC.NewBlock("I am a block",make([]byte,32,32),1) 10 | //fmt.Println(block) 11 | //2.测试创世区块 12 | //genesisBlock :=BLC.CreateGenesisBlock("Genesis Block..") 13 | //fmt.Println(genesisBlock) 14 | 15 | //3.测试区块链 16 | //genesisBlockChain := BLC.CreateBlockChainWithGenesisBlock() 17 | //fmt.Println(genesisBlockChain) 18 | //fmt.Println(genesisBlockChain.Blocks) 19 | //fmt.Println(genesisBlockChain.Blocks[0]) 20 | 21 | //4.测试添加新区块 22 | //blockChain:=BLC.CreateBlockChainWithGenesisBlock() 23 | //blockChain.AddBlockToBlockChain("Send 100RMB To Wangergou",blockChain.Blocks[len(blockChain.Blocks)-1].Height+1,blockChain.Blocks[len(blockChain.Blocks)-1].Hash) 24 | //blockChain.AddBlockToBlockChain("Send 300RMB To lixiaohua",blockChain.Blocks[len(blockChain.Blocks)-1].Height+1,blockChain.Blocks[len(blockChain.Blocks)-1].Hash) 25 | //blockChain.AddBlockToBlockChain("Send 500RMB To rose",blockChain.Blocks[len(blockChain.Blocks)-1].Height+1,blockChain.Blocks[len(blockChain.Blocks)-1].Hash) 26 | // 27 | //fmt.Println(blockChain) 28 | 29 | //5.测试序列化和反序列化 30 | //block:=BLC.NewBlock("helloworld",make([]byte,32,32),0) 31 | //data:=block.Serilalize() 32 | //fmt.Println(block) 33 | //fmt.Println(data) 34 | //block2:=BLC.DeserializeBlock(data) 35 | //fmt.Println(block2) 36 | 37 | //6.创建区块,存入数据库 38 | //打开数据库 39 | //block:=BLC.NewBlock("helloworld",make([]byte,32,32),0) 40 | //db,err := bolt.Open("my.db",0600,nil) 41 | //if err != nil{ 42 | // log.Fatal(err) 43 | //} 44 | // 45 | //defer db.Close() 46 | // 47 | //err = db.Update(func(tx *bolt.Tx) error { 48 | // //获取bucket,没有就创建新表 49 | // b := tx.Bucket([]byte("blocks")) 50 | // if b == nil{ 51 | // b,err = tx.CreateBucket([] byte("blocks")) 52 | // if err !=nil{ 53 | // log.Panic("创建表失败") 54 | // } 55 | // } 56 | // //添加数据 57 | // err = b.Put([]byte("l"),block.Serilalize()) 58 | // if err !=nil{ 59 | // log.Panic(err) 60 | // } 61 | // 62 | // return nil 63 | //}) 64 | //if err != nil{ 65 | // log.Panic(err) 66 | //} 67 | //err = db.View(func(tx *bolt.Tx) error { 68 | // b := tx.Bucket([]byte("blocks")) 69 | // if b !=nil{ 70 | // data := b.Get([]byte("l")) 71 | // //fmt.Printf("%s\n",data)//直接打印会乱码 72 | // //反序列化 73 | // block2:=BLC.DeserializeBlock(data) 74 | // //fmt.Println(block2) 75 | // fmt.Printf("%v\n",block2) 76 | // 77 | // } 78 | // return nil 79 | //}) 80 | 81 | //7.测试创世区块存入数据库 82 | //blockchain:=BLC.CreateBlockChainWithGenesisBlock("Genesis Block..") 83 | //fmt.Println(blockchain) 84 | //defer blockchain.DB.Close() 85 | //8.测试新添加的区块 86 | //blockchain.AddBlockToBlockChain("Send 100RMB to wangergou") 87 | //blockchain.AddBlockToBlockChain("Send 100RMB to lixiaohua") 88 | //blockchain.AddBlockToBlockChain("Send 100RMB to rose") 89 | //fmt.Println(blockchain) 90 | //blockchain.PrintChains() 91 | 92 | //9.CLI操作 93 | cli := BLC.CLI{} 94 | cli.Run() 95 | 96 | } 97 | -------------------------------------------------------------------------------- /day05_07_signature/BLC/Block.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import ( 4 | "time" 5 | "bytes" 6 | "encoding/gob" 7 | "log" 8 | "crypto/sha256" 9 | ) 10 | //step2:修改Block的交易类型 11 | type Block struct { 12 | //字段: 13 | //高度Height:其实就是区块的编号,第一个区块叫创世区块,高度为0 14 | Height int64 15 | //上一个区块的哈希值ProvHash: 16 | PrevBlockHash []byte 17 | //交易数据Data:目前先设计为[]byte,后期是Transaction 18 | //Data [] byte 19 | Txs [] *Transaction 20 | //时间戳TimeStamp: 21 | TimeStamp int64 22 | //哈希值Hash:32个的字节,64个16进制数 23 | Hash []byte 24 | 25 | Nonce int64 26 | } 27 | 28 | func NewBlock(txs []*Transaction,provBlockHash []byte,height int64) *Block{ 29 | //创建区块 30 | block:=&Block{height,provBlockHash,txs,time.Now().Unix(),nil,0} 31 | //step5:设置block的hash和nonce 32 | //设置哈希 33 | //block.SetHash() 34 | //调用工作量证明的方法,并且返回有效的Hash和Nonce 35 | pow:=NewProofOfWork(block) 36 | hash,nonce:=pow.Run() 37 | block.Hash = hash 38 | block.Nonce = nonce 39 | 40 | 41 | return block 42 | } 43 | 44 | func CreateGenesisBlock(txs []*Transaction) *Block{ 45 | return NewBlock(txs,make([] byte,32,32),0) 46 | } 47 | 48 | //将区块序列化,得到一个字节数组---区块的行为,设计为方法 49 | func (block *Block) Serilalize() []byte { 50 | //1.创建一个buffer 51 | var result bytes.Buffer 52 | //2.创建一个编码器 53 | encoder := gob.NewEncoder(&result) 54 | //3.编码--->打包 55 | err := encoder.Encode(block) 56 | if err != nil { 57 | log.Panic(err) 58 | } 59 | return result.Bytes() 60 | } 61 | 62 | //反序列化,得到一个区块---设计为函数 63 | func DeserializeBlock(blockBytes [] byte) *Block { 64 | var block Block 65 | var reader = bytes.NewReader(blockBytes) 66 | //1.创建一个解码器 67 | decoder := gob.NewDecoder(reader) 68 | //解包 69 | err := decoder.Decode(&block) 70 | if err != nil { 71 | log.Panic(err) 72 | } 73 | return &block 74 | } 75 | 76 | //step4:新增方法 77 | //将Txs转为[]byte 78 | func (block *Block) HashTransactions()[]byte{ 79 | var txHashes [][] byte 80 | var txHash [32]byte 81 | for _,tx :=range block.Txs{ 82 | txHashes = append(txHashes,tx.TxID) 83 | } 84 | 85 | txHash = sha256.Sum256(bytes.Join(txHashes,[]byte{})) 86 | return txHash[:] 87 | } 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | -------------------------------------------------------------------------------- /day05_07_signature/BLC/BlockChainIterator.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import ( 4 | "github.com/boltdb/bolt" 5 | "log" 6 | ) 7 | 8 | //1.新增一个结构体 9 | type BlockChainIterator struct { 10 | CurrentHash [] byte //当前区块的hash 11 | DB *bolt.DB //数据库 12 | } 13 | 14 | 15 | 16 | 17 | //3.获取区块 18 | func (bcIterator *BlockChainIterator) Next() *Block { 19 | block:=new(Block) 20 | //1.打开数据库并读取 21 | err :=bcIterator.DB.View(func(tx *bolt.Tx) error { 22 | //2.打开数据表 23 | b:=tx.Bucket([]byte(BLOCKTABLENAME)) 24 | if b != nil{ 25 | //3.根据当前hash获取数据并反序列化 26 | blockBytes:=b.Get(bcIterator.CurrentHash) 27 | block = DeserializeBlock(blockBytes) 28 | //4.更新当前的hash 29 | bcIterator.CurrentHash = block.PrevBlockHash 30 | } 31 | 32 | return nil 33 | }) 34 | if err != nil{ 35 | log.Panic(err) 36 | } 37 | return block 38 | } 39 | 40 | 41 | -------------------------------------------------------------------------------- /day05_07_signature/BLC/CLI.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import ( 4 | "os" 5 | "fmt" 6 | "flag" 7 | "log" 8 | ) 9 | 10 | //step1: 11 | //CLI结构体 12 | type CLI struct { 13 | //Blockchain *BlockChain 14 | } 15 | 16 | //step2:添加Run方法 17 | func (cli *CLI) Run() { 18 | //判断命令行参数的长度 19 | isValidArgs() 20 | 21 | //1.创建flagset标签对象 22 | createWalletCmd := flag.NewFlagSet("createwallet", flag.ExitOnError) 23 | addressListsCmd := flag.NewFlagSet("addresslists",flag.ExitOnError) 24 | 25 | sendBlockCmd := flag.NewFlagSet("send", flag.ExitOnError) 26 | //fmt.Printf("%T\n",addBlockCmd) //*FlagSet 27 | printChainCmd := flag.NewFlagSet("printchain", flag.ExitOnError) 28 | createBlockChainCmd := flag.NewFlagSet("createblockchain", flag.ExitOnError) 29 | getBalanceCmd := flag.NewFlagSet("getbalance", flag.ExitOnError) 30 | 31 | //2.设置标签后的参数 32 | //flagAddBlockData:= addBlockCmd.String("data","helloworld..","交易数据") 33 | flagFromData := sendBlockCmd.String("from", "", "转帐源地址") 34 | flagToData := sendBlockCmd.String("to", "", "转帐目标地址") 35 | flagAmountData := sendBlockCmd.String("amount", "", "转帐金额") 36 | flagCreateBlockChainData := createBlockChainCmd.String("address", "", "创世区块交易地址") 37 | flagGetBalanceData := getBalanceCmd.String("address", "", "要查询的某个账户的余额") 38 | 39 | //3.解析 40 | switch os.Args[1] { 41 | case "send": 42 | err := sendBlockCmd.Parse(os.Args[2:]) 43 | if err != nil { 44 | log.Panic(err) 45 | } 46 | //fmt.Println("----",os.Args[2:]) 47 | 48 | case "printchain": 49 | err := printChainCmd.Parse(os.Args[2:]) 50 | if err != nil { 51 | log.Panic(err) 52 | } 53 | //fmt.Println("====",os.Args[2:]) 54 | 55 | case "createblockchain": 56 | err := createBlockChainCmd.Parse(os.Args[2:]) 57 | if err != nil { 58 | log.Panic(err) 59 | } 60 | case "getbalance": 61 | err := getBalanceCmd.Parse(os.Args[2:]) 62 | if err != nil { 63 | log.Panic(err) 64 | } 65 | 66 | case "createwallet": 67 | err := createWalletCmd.Parse(os.Args[2:]) 68 | if err != nil { 69 | log.Panic(err) 70 | } 71 | case "addresslists": 72 | err := addressListsCmd.Parse(os.Args[2:]) 73 | if err != nil { 74 | log.Panic(err) 75 | } 76 | default: 77 | printUsage() 78 | os.Exit(1) //退出 79 | } 80 | 81 | if sendBlockCmd.Parsed() { 82 | if *flagFromData == "" || *flagToData == "" || *flagAmountData == "" { 83 | printUsage() 84 | os.Exit(1) 85 | } 86 | //cli.addBlock([]*Transaction{}) 87 | fmt.Println(*flagFromData) 88 | fmt.Println(*flagToData) 89 | fmt.Println(*flagAmountData) 90 | //fmt.Println(JSONToArray(*flagFrom)) 91 | //fmt.Println(JSONToArray(*flagTo)) 92 | //fmt.Println(JSONToArray(*flagAmount)) 93 | from := JSONToArray(*flagFromData) 94 | to := JSONToArray(*flagToData) 95 | amount := JSONToArray(*flagAmountData) 96 | 97 | for i := 0; i < len(from); i++ { 98 | if !IsValidForAddress([]byte(from[i])) || !IsValidForAddress([]byte(to[i])) { 99 | fmt.Println("钱包地址无效") 100 | printUsage() 101 | os.Exit(1) 102 | } 103 | } 104 | 105 | cli.send(from, to, amount) 106 | } 107 | if printChainCmd.Parsed() { 108 | cli.printChains() 109 | } 110 | 111 | if createBlockChainCmd.Parsed() { 112 | //if *flagCreateBlockChainData == "" { 113 | if !IsValidForAddress([]byte(*flagCreateBlockChainData)){ 114 | fmt.Println("创建地址无效") 115 | printUsage() 116 | os.Exit(1) 117 | } 118 | cli.createGenesisBlockchain(*flagCreateBlockChainData) 119 | } 120 | 121 | if getBalanceCmd.Parsed() { 122 | //if *flagGetBalanceData == "" { 123 | if !IsValidForAddress([]byte(*flagGetBalanceData)){ 124 | fmt.Println("查询地址无效") 125 | printUsage() 126 | os.Exit(1) 127 | } 128 | cli.getBalance(*flagGetBalanceData) 129 | 130 | } 131 | 132 | if createWalletCmd.Parsed() { 133 | //创建钱包 134 | cli.createWallet() 135 | } 136 | 137 | //获取所有的钱包地址 138 | if addressListsCmd.Parsed(){ 139 | cli.addressLists() 140 | } 141 | 142 | } 143 | 144 | func isValidArgs() { 145 | if len(os.Args) < 2 { 146 | printUsage() 147 | os.Exit(1) 148 | } 149 | } 150 | func printUsage() { 151 | fmt.Println("Usage:") 152 | fmt.Println("\tcreatewallet -- 创建钱包") 153 | fmt.Println("\taddresslists -- 输出所有钱包地址") 154 | fmt.Println("\tcreateblockchain -address DATA -- 创建创世区块") 155 | fmt.Println("\tsend -from From -to To -amount Amount - 交易数据") 156 | fmt.Println("\tprintchain - 输出信息:") 157 | fmt.Println("\tgetbalance -address DATA -- 查询账户余额") 158 | } 159 | -------------------------------------------------------------------------------- /day05_07_signature/BLC/CLI_addresslists.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import "fmt" 4 | 5 | func (cli *CLI)addressLists(){ 6 | fmt.Println("打印所有的钱包地址。。") 7 | //获取 8 | Wallets:=NewWallets() 9 | for address,_ := range Wallets.WalletsMap{ 10 | fmt.Println("address:",address) 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /day05_07_signature/BLC/CLI_createBlockChain.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | func (cli *CLI) createGenesisBlockchain(address string){ 4 | //fmt.Println(data) 5 | CreateBlockChainWithGenesisBlock(address) 6 | 7 | } 8 | -------------------------------------------------------------------------------- /day05_07_signature/BLC/CLI_createwallet.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | func (cli *CLI) createWallet(){ 4 | wallets:= NewWallets() 5 | wallets.CreateNewWallet() 6 | } 7 | -------------------------------------------------------------------------------- /day05_07_signature/BLC/CLI_getBalance.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | ) 7 | 8 | //查询余额 9 | func (cli *CLI)getBalance(address string){ 10 | fmt.Println("查询余额:",address) 11 | bc := GetBlockchainObject() 12 | 13 | if bc == nil{ 14 | fmt.Println("数据库不存在,无法查询。。") 15 | os.Exit(1) 16 | } 17 | defer bc.DB.Close() 18 | //txOutputs:= bc.UnUTXOs(address) 19 | //for i,out:=range txOutputs{ 20 | // fmt.Println(i,"---->",out) 21 | //} 22 | balance:=bc.GetBalance(address,[]*Transaction{}) 23 | fmt.Printf("%s,一共有%d个Token\n",address,balance) 24 | } 25 | -------------------------------------------------------------------------------- /day05_07_signature/BLC/CLI_printChains.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | ) 7 | 8 | func (cli *CLI)printChains(){ 9 | bc:=GetBlockchainObject() 10 | if bc == nil{ 11 | fmt.Println("没有区块可以打印。。") 12 | os.Exit(1) 13 | } 14 | defer bc.DB.Close() 15 | bc.PrintChains() 16 | } -------------------------------------------------------------------------------- /day05_07_signature/BLC/CLI_send.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | ) 7 | 8 | //转账 9 | func (cli *CLI) send(from, to, amount [] string) { 10 | if !dbExists() { 11 | fmt.Println("数据库不存在。。。") 12 | os.Exit(1) 13 | } 14 | blockchain := GetBlockchainObject() 15 | 16 | blockchain.MineNewBlock(from, to, amount) 17 | defer blockchain.DB.Close() 18 | } 19 | -------------------------------------------------------------------------------- /day05_07_signature/BLC/Constant.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | const DBNAME = "blockchain.db" //数据库名 4 | const BLOCKTABLENAME = "blocks" //表名 5 | 6 | 7 | -------------------------------------------------------------------------------- /day05_07_signature/BLC/ProofOfWork.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import ( 4 | "math/big" 5 | "bytes" 6 | "crypto/sha256" 7 | "fmt" 8 | ) 9 | 10 | // 0000 0000 0000 0000 1001 0001 0000 .... 0001 11 | //256位Hash里面前面至少有16个零 12 | const TargetBit = 16 // 20 13 | 14 | type ProofOfWork struct { 15 | //要验证的区块 16 | Block *Block 17 | 18 | //大整数存储,目标哈希 19 | Target *big.Int 20 | } 21 | 22 | func NewProofOfWork(block *Block) *ProofOfWork { 23 | //1.创建一个big对象 0000000.....00001 24 | /* 25 | 0000 0001 26 | 0010 0000 27 | */ 28 | target := big.NewInt(1) 29 | 30 | //2.左移256-bits位 31 | target = target.Lsh(target, 256-TargetBit) 32 | 33 | return &ProofOfWork{block, target} 34 | } 35 | 36 | func (pow *ProofOfWork) Run() ([] byte, int64) { 37 | //1.将Block的属性拼接成字节数组 38 | //2.生成Hash 39 | //3.循环判断Hash的有效性,满足条件,跳出循环结束验证 40 | nonce := 0 41 | //var hashInt big.Int //用于存储新生成的hash 42 | hashInt := new(big.Int) 43 | var hash [32]byte 44 | for{ 45 | //获取字节数组 46 | dataBytes := pow.prepareData(nonce) 47 | //生成hash 48 | hash = sha256.Sum256(dataBytes) 49 | //fmt.Printf("%d: %x\n",nonce,hash) 50 | fmt.Printf("\r%d: %x",nonce,hash) 51 | //将hash存储到hashInt 52 | hashInt.SetBytes(hash[:]) 53 | //判断hashInt是否小于Block里的target 54 | /* 55 | Com compares x and y and returns: 56 | -1 if x < y 57 | 0 if x == y 58 | 1 if x > y 59 | */ 60 | if pow.Target.Cmp(hashInt) == 1{ 61 | break 62 | } 63 | nonce++ 64 | } 65 | fmt.Println() 66 | return hash[:], int64(nonce) 67 | } 68 | 69 | func (pow *ProofOfWork) prepareData(nonce int)[]byte{ 70 | data := bytes.Join( 71 | [][] byte{ 72 | pow.Block.PrevBlockHash, 73 | pow.Block.HashTransactions(), 74 | IntToHex(pow.Block.TimeStamp), 75 | IntToHex(int64(TargetBit)), 76 | IntToHex(int64(nonce)), 77 | IntToHex(int64(pow.Block.Height)), 78 | }, 79 | [] byte{}, 80 | ) 81 | return data 82 | } 83 | -------------------------------------------------------------------------------- /day05_07_signature/BLC/Transaction_TxInput.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import "bytes" 4 | 5 | type TXInput struct { 6 | //1.交易的ID 7 | TxID [] byte 8 | //2.存储Txoutput的vout里面的索引 9 | Vout int 10 | //3.用户名 11 | //ScriptSiq string 12 | Signature [] byte //数字签名 13 | PublicKey [] byte //公钥,钱包里面 14 | } 15 | 16 | //判断当前txInput消费,和指定的address是否一致 17 | func (txInput *TXInput) UnLockWithAddress(pubKeyHash []byte) bool{ 18 | //return txInput.ScriptSiq == address 19 | publicKey:=PubKeyHash(txInput.PublicKey) 20 | return bytes.Compare(pubKeyHash,publicKey) == 0 21 | } 22 | 23 | 24 | -------------------------------------------------------------------------------- /day05_07_signature/BLC/Transaction_TxOutput.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import "bytes" 4 | 5 | //交易的输出,就是币实际存储的地方 6 | type TXOuput struct { 7 | Value int64 8 | //一个锁定脚本(ScriptPubKey),要花这笔钱,必须要解锁该脚本。 9 | //ScriptPubKey string //公钥:先理解为,用户名 10 | PubKeyHash [] byte // 公钥 11 | } 12 | 13 | //判断当前txOutput消费,和指定的address是否一致 14 | func (txOutput *TXOuput) UnLockWithAddress(address string) bool { 15 | //return txOutput.ScriptPubKey == address 16 | fullPayloadHash := Base58Decode([]byte(address)) 17 | pubKeyHash := fullPayloadHash[1:len(fullPayloadHash)-4] 18 | return bytes.Compare(txOutput.PubKeyHash, pubKeyHash) == 0 19 | } 20 | 21 | 22 | func NewTXOuput(value int64,address string) *TXOuput{ 23 | txOutput := &TXOuput{value, nil} 24 | //设置Ripemd160Hash 25 | txOutput.Lock(address) 26 | return txOutput 27 | } 28 | 29 | func (txOutput *TXOuput) Lock(address string) { 30 | publicKeyHash := Base58Decode([] byte(address)) 31 | txOutput.PubKeyHash = publicKeyHash[1:len(publicKeyHash)-4] 32 | } -------------------------------------------------------------------------------- /day05_07_signature/BLC/Transaction_UTXO.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | //step1:创建一个结构体UTXO,用于表示所有未花费的 4 | type UTXO struct { 5 | TxID [] byte //当前Transaction的交易ID 6 | Index int //下标索引 7 | Output *TXOuput // 8 | } 9 | -------------------------------------------------------------------------------- /day05_07_signature/BLC/Wallet.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import ( 4 | "crypto/ecdsa" 5 | "crypto/elliptic" 6 | "crypto/rand" 7 | "log" 8 | "crypto/sha256" 9 | "golang.org/x/crypto/ripemd160" 10 | "bytes" 11 | ) 12 | 13 | //step1:创建一个钱包 14 | type Wallet struct { 15 | //1.私钥 16 | PrivateKey ecdsa.PrivateKey 17 | //2.公钥 18 | PublicKey [] byte 19 | } 20 | 21 | //step2:产生一对密钥 22 | func newKeyPair() (ecdsa.PrivateKey, []byte) { 23 | /* 24 | 1.通过椭圆曲线算法,随机产生私钥 25 | 2.根据私钥生成公钥 26 | 27 | elliptic:椭圆 28 | curve:曲线 29 | ecc:椭圆曲线加密 30 | ecdsa:elliptic curve digital signature algorithm,椭圆曲线数字签名算法 31 | 比特币使用SECP256K1算法,p256是ecdsa算法中的一种 32 | 33 | */ 34 | //椭圆加密 35 | curve := elliptic.P256() //椭圆加密算法,得到一个椭圆曲线值,全称:SECP256k1 36 | private, err := ecdsa.GenerateKey(curve, rand.Reader) 37 | if err != nil { 38 | log.Panic(err) 39 | } 40 | //生成公钥 41 | pubKey := append(private.PublicKey.X.Bytes(), private.PublicKey.Y.Bytes()...) 42 | return *private, pubKey 43 | } 44 | 45 | //step3:提供一个方法用于获取钱包 46 | func NewWallet() *Wallet { 47 | privateKey, publicKey := newKeyPair() 48 | //fmt.Println("privateKey:", privateKey, ",publicKey:", publicKey) 49 | return &Wallet{privateKey, publicKey} 50 | } 51 | 52 | //step4:根据一个公钥获取对应的地址 53 | /* 54 | 将公钥sha2561次,再160,1次 55 | 然后version+hash 56 | */ 57 | func (w *Wallet) GetAddress() [] byte { 58 | //1.先将公钥进行一次hash256,一次160,得到pubKeyHash 59 | pubKeyHash := PubKeyHash(w.PublicKey) 60 | //2.添加版本号 61 | versioned_payload := append([]byte{version}, pubKeyHash...) 62 | // 3.获取校验和,将pubKeyhash,两次sha256后,取前4位 63 | checkSumBytes := CheckSum(versioned_payload) 64 | full_payload := append(versioned_payload, checkSumBytes...) 65 | //fmt.Println(len(full_payload)) 66 | //4.Base58 67 | address := Base58Encode(full_payload) 68 | return address 69 | 70 | } 71 | 72 | //一次sha256,再一次ripemd160,得到publicKeyHash 73 | func PubKeyHash(publicKey [] byte) []byte { 74 | //1.sha256 75 | hasher := sha256.New() 76 | hasher.Write(publicKey) 77 | hash := hasher.Sum(nil) 78 | 79 | //2.ripemd160 80 | ripemder := ripemd160.New() 81 | ripemder.Write(hash) 82 | pubKeyHash := ripemder.Sum(nil) 83 | 84 | //返回 85 | return pubKeyHash 86 | } 87 | 88 | const version = byte(0x00) 89 | const addressChecksumLen = 4 90 | 91 | //获取验证码:将公钥哈希两次sha256,取前4位,就是校验和 92 | func CheckSum(payload []byte) []byte { 93 | firstSHA := sha256.Sum256(payload) 94 | secondSHA := sha256.Sum256(firstSHA[:]) 95 | return secondSHA[:addressChecksumLen] 96 | } 97 | 98 | 99 | 100 | //判断地址是否有效 101 | /* 102 | 根据地址,base58解码后获取byte[],获取校验和数组 103 | 使用 104 | */ 105 | func IsValidForAddress(address []byte) bool { 106 | full_payload := Base58Decode(address) 107 | //fmt.Println("检验version_public_checksumBytes:",full_payload) 108 | checkSumBytes := full_payload[len(full_payload)-addressChecksumLen:] 109 | //fmt.Println("检验checkSumBytes:",checkSumBytes) 110 | versioned_payload := full_payload[:len(full_payload)-addressChecksumLen] 111 | //fmt.Println("检验version_ripemd160:",versioned_payload) 112 | checkBytes := CheckSum(versioned_payload) 113 | //fmt.Println("检验checkBytes:",checkBytes) 114 | if bytes.Compare(checkSumBytes, checkBytes) == 0 { 115 | return true 116 | } 117 | return false 118 | } -------------------------------------------------------------------------------- /day05_07_signature/BLC/Wallets.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "io/ioutil" 7 | "log" 8 | "encoding/gob" 9 | "crypto/elliptic" 10 | "bytes" 11 | ) 12 | 13 | //1.创建钱包 14 | type Wallets struct { 15 | WalletsMap map[string]*Wallet 16 | } 17 | 18 | //2.创建一个钱包集合 19 | //创建钱包集合:文件中存在从文件中读取,否则新建一个 20 | const walletFile = "Wallets.dat" 21 | 22 | func NewWallets() *Wallets { 23 | //wallets := &WalletsMap{} 24 | //wallets.WalletsMap = make(map[string]*Wallet) 25 | //return wallets 26 | //1.判断钱包文件是否存在 27 | if _, err := os.Stat(walletFile); os.IsNotExist(err) { 28 | fmt.Println("文件不存在") 29 | wallets := &Wallets{} 30 | wallets.WalletsMap = make(map[string]*Wallet) 31 | return wallets 32 | } 33 | //2.否则读取文件中的数据 34 | fileContent, err := ioutil.ReadFile(walletFile) 35 | if err != nil { 36 | log.Panic(err) 37 | } 38 | var wallets Wallets 39 | gob.Register(elliptic.P256()) 40 | decoder := gob.NewDecoder(bytes.NewReader(fileContent)) 41 | err = decoder.Decode(&wallets) 42 | if err != nil { 43 | log.Panic(err) 44 | } 45 | return &wallets 46 | } 47 | 48 | //3.创建一个新钱包 49 | func (ws *Wallets) CreateNewWallet() { 50 | wallet := NewWallet() 51 | fmt.Printf("创建钱包地址:%s\n", wallet.GetAddress()) 52 | ws.WalletsMap[string(wallet.GetAddress())] = wallet 53 | 54 | //将钱包保存 55 | ws.SaveWallets() 56 | } 57 | 58 | /* 59 | 要让数据对象能在网络上传输或存储,我们需要进行编码和解码。现在比较流行的编码方式有JSON,XML等。然而,Go在gob包中为我们提供了另一种方式,该方式编解码效率高于JSON。 60 | gob是Golang包自带的一个数据结构序列化的编码/解码工具 61 | */ 62 | func (ws *Wallets) SaveWallets() { 63 | var content bytes.Buffer 64 | //注册的目的,为了可以序列化任何类型,wallet结构体中有接口类型。将接口进行注册 65 | gob.Register(elliptic.P256()) //gob是Golang包自带的一个数据结构序列化的编码/解码工具 66 | encoder := gob.NewEncoder(&content) 67 | err := encoder.Encode(ws) 68 | if err != nil { 69 | log.Panic(err) 70 | } 71 | //将序列化后的数据写入到文件,原来的文件中的内容会被覆盖掉 72 | err = ioutil.WriteFile(walletFile, content.Bytes(), 0644) 73 | if err != nil { 74 | log.Panic(err) 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /day05_07_signature/BLC/base58.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | import ( 3 | "math/big" 4 | "bytes" 5 | ) 6 | 7 | //base64 8 | 9 | /* 10 | ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/ 11 | 0(零),O(大写的o),I(大写的i),l(小写的L),+,/ 12 | */ 13 | 14 | var b58Alphabet = []byte("123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz") 15 | 16 | //字节数组转Base58,加密 17 | func Base58Encode(input []byte)[]byte{ 18 | var result [] byte 19 | x := big.NewInt(0).SetBytes(input) 20 | 21 | base :=big.NewInt(int64(len(b58Alphabet))) 22 | zero:=big.NewInt(0) 23 | mod:= &big.Int{} 24 | for x.Cmp(zero) !=0{ 25 | x.DivMod(x,base,mod) 26 | result = append(result,b58Alphabet[mod.Int64()]) 27 | } 28 | ReverseBytes(result) 29 | for b:=range input{ 30 | if b == 0x00{ 31 | result = append([]byte{b58Alphabet[0]},result...) 32 | }else { 33 | break 34 | } 35 | } 36 | 37 | return result 38 | 39 | } 40 | 41 | //Base58转字节数组,解密 42 | func Base58Decode(input[] byte)[]byte{ 43 | result:=big.NewInt(0) 44 | zeroBytes := 0 45 | for b:=range input{ 46 | if b == 0x00{ 47 | zeroBytes++ 48 | } 49 | } 50 | payload := input[zeroBytes:] 51 | for _, b := range payload { 52 | charIndex := bytes.IndexByte(b58Alphabet, b) 53 | result.Mul(result, big.NewInt(58)) 54 | result.Add(result, big.NewInt(int64(charIndex))) 55 | } 56 | 57 | decoded := result.Bytes() 58 | decoded = append(bytes.Repeat([]byte{byte(0x00)}, zeroBytes), decoded...) 59 | 60 | return decoded 61 | } 62 | 63 | 64 | -------------------------------------------------------------------------------- /day05_07_signature/BLC/utils.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import ( 4 | "bytes" 5 | "encoding/binary" 6 | "log" 7 | "encoding/json" 8 | ) 9 | 10 | /* 11 | 将一个int64的整数:转为二进制后,每8bit一个byte。转为[]byte 12 | */ 13 | func IntToHex(num int64) []byte { 14 | buff := new(bytes.Buffer) 15 | //将二进制数据写入w 16 | //func Write(w io.Writer, order ByteOrder, data interface{}) error 17 | err := binary.Write(buff, binary.BigEndian, num) 18 | if err != nil { 19 | log.Panic(err) 20 | } 21 | //转为[]byte并返回 22 | return buff.Bytes() 23 | } 24 | 25 | /* 26 | Json字符串转为[] string数组 27 | */ 28 | func JSONToArray (jsonString string) [] string{ 29 | var sArr [] string 30 | if err := json.Unmarshal([]byte(jsonString),&sArr);err != nil{ 31 | log.Panic(err) 32 | } 33 | return sArr 34 | } 35 | 36 | 37 | //字节数组反转 38 | func ReverseBytes(data []byte) { 39 | for i, j := 0, len(data)-1; i < j; i, j = i+1, j-1 { 40 | data[i], data[j] = data[j], data[i] 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /day05_07_signature/Wallets.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rubyhan1314/PublicChain/fd8b04084c29fe82efe813a0c30864ed1df00383/day05_07_signature/Wallets.dat -------------------------------------------------------------------------------- /day05_07_signature/bc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rubyhan1314/PublicChain/fd8b04084c29fe82efe813a0c30864ed1df00383/day05_07_signature/bc -------------------------------------------------------------------------------- /day05_07_signature/blockchain.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rubyhan1314/PublicChain/fd8b04084c29fe82efe813a0c30864ed1df00383/day05_07_signature/blockchain.db -------------------------------------------------------------------------------- /day05_07_signature/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "./BLC" 5 | ) 6 | 7 | func main() { 8 | //1.测试Block 9 | //block:=BLC.NewBlock("I am a block",make([]byte,32,32),1) 10 | //fmt.Println(block) 11 | //2.测试创世区块 12 | //genesisBlock :=BLC.CreateGenesisBlock("Genesis Block..") 13 | //fmt.Println(genesisBlock) 14 | 15 | //3.测试区块链 16 | //genesisBlockChain := BLC.CreateBlockChainWithGenesisBlock() 17 | //fmt.Println(genesisBlockChain) 18 | //fmt.Println(genesisBlockChain.Blocks) 19 | //fmt.Println(genesisBlockChain.Blocks[0]) 20 | 21 | //4.测试添加新区块 22 | //blockChain:=BLC.CreateBlockChainWithGenesisBlock() 23 | //blockChain.AddBlockToBlockChain("Send 100RMB To Wangergou",blockChain.Blocks[len(blockChain.Blocks)-1].Height+1,blockChain.Blocks[len(blockChain.Blocks)-1].Hash) 24 | //blockChain.AddBlockToBlockChain("Send 300RMB To lixiaohua",blockChain.Blocks[len(blockChain.Blocks)-1].Height+1,blockChain.Blocks[len(blockChain.Blocks)-1].Hash) 25 | //blockChain.AddBlockToBlockChain("Send 500RMB To rose",blockChain.Blocks[len(blockChain.Blocks)-1].Height+1,blockChain.Blocks[len(blockChain.Blocks)-1].Hash) 26 | // 27 | //fmt.Println(blockChain) 28 | 29 | //5.测试序列化和反序列化 30 | //block:=BLC.NewBlock("helloworld",make([]byte,32,32),0) 31 | //data:=block.Serilalize() 32 | //fmt.Println(block) 33 | //fmt.Println(data) 34 | //block2:=BLC.DeserializeBlock(data) 35 | //fmt.Println(block2) 36 | 37 | //6.创建区块,存入数据库 38 | //打开数据库 39 | //block:=BLC.NewBlock("helloworld",make([]byte,32,32),0) 40 | //db,err := bolt.Open("my.db",0600,nil) 41 | //if err != nil{ 42 | // log.Fatal(err) 43 | //} 44 | // 45 | //defer db.Close() 46 | // 47 | //err = db.Update(func(tx *bolt.Tx) error { 48 | // //获取bucket,没有就创建新表 49 | // b := tx.Bucket([]byte("blocks")) 50 | // if b == nil{ 51 | // b,err = tx.CreateBucket([] byte("blocks")) 52 | // if err !=nil{ 53 | // log.Panic("创建表失败") 54 | // } 55 | // } 56 | // //添加数据 57 | // err = b.Put([]byte("l"),block.Serilalize()) 58 | // if err !=nil{ 59 | // log.Panic(err) 60 | // } 61 | // 62 | // return nil 63 | //}) 64 | //if err != nil{ 65 | // log.Panic(err) 66 | //} 67 | //err = db.View(func(tx *bolt.Tx) error { 68 | // b := tx.Bucket([]byte("blocks")) 69 | // if b !=nil{ 70 | // data := b.Get([]byte("l")) 71 | // //fmt.Printf("%s\n",data)//直接打印会乱码 72 | // //反序列化 73 | // block2:=BLC.DeserializeBlock(data) 74 | // //fmt.Println(block2) 75 | // fmt.Printf("%v\n",block2) 76 | // 77 | // } 78 | // return nil 79 | //}) 80 | 81 | //7.测试创世区块存入数据库 82 | //blockchain:=BLC.CreateBlockChainWithGenesisBlock("Genesis Block..") 83 | //fmt.Println(blockchain) 84 | //defer blockchain.DB.Close() 85 | //8.测试新添加的区块 86 | //blockchain.AddBlockToBlockChain("Send 100RMB to wangergou") 87 | //blockchain.AddBlockToBlockChain("Send 100RMB to lixiaohua") 88 | //blockchain.AddBlockToBlockChain("Send 100RMB to rose") 89 | //fmt.Println(blockchain) 90 | //blockchain.PrintChains() 91 | 92 | //9.CLI操作 93 | cli:=BLC.CLI{} 94 | cli.Run() 95 | 96 | 97 | } -------------------------------------------------------------------------------- /day06_08_Update/BLC/Block.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import ( 4 | "time" 5 | "bytes" 6 | "encoding/gob" 7 | "log" 8 | "crypto/sha256" 9 | ) 10 | //step2:修改Block的交易类型 11 | type Block struct { 12 | //字段: 13 | //高度Height:其实就是区块的编号,第一个区块叫创世区块,高度为0 14 | Height int64 15 | //上一个区块的哈希值ProvHash: 16 | PrevBlockHash []byte 17 | //交易数据Data:目前先设计为[]byte,后期是Transaction 18 | //Data [] byte 19 | Txs [] *Transaction 20 | //时间戳TimeStamp: 21 | TimeStamp int64 22 | //哈希值Hash:32个的字节,64个16进制数 23 | Hash []byte 24 | 25 | Nonce int64 26 | } 27 | 28 | func NewBlock(txs []*Transaction,provBlockHash []byte,height int64) *Block{ 29 | //创建区块 30 | block:=&Block{height,provBlockHash,txs,time.Now().Unix(),nil,0} 31 | //step5:设置block的hash和nonce 32 | //设置哈希 33 | //block.SetHash() 34 | //调用工作量证明的方法,并且返回有效的Hash和Nonce 35 | pow:=NewProofOfWork(block) 36 | hash,nonce:=pow.Run() 37 | block.Hash = hash 38 | block.Nonce = nonce 39 | 40 | 41 | return block 42 | } 43 | 44 | func CreateGenesisBlock(txs []*Transaction) *Block{ 45 | return NewBlock(txs,make([] byte,32,32),0) 46 | } 47 | 48 | //将区块序列化,得到一个字节数组---区块的行为,设计为方法 49 | func (block *Block) Serilalize() []byte { 50 | //1.创建一个buffer 51 | var result bytes.Buffer 52 | //2.创建一个编码器 53 | encoder := gob.NewEncoder(&result) 54 | //3.编码--->打包 55 | err := encoder.Encode(block) 56 | if err != nil { 57 | log.Panic(err) 58 | } 59 | return result.Bytes() 60 | } 61 | 62 | //反序列化,得到一个区块---设计为函数 63 | func DeserializeBlock(blockBytes [] byte) *Block { 64 | var block Block 65 | var reader = bytes.NewReader(blockBytes) 66 | //1.创建一个解码器 67 | decoder := gob.NewDecoder(reader) 68 | //解包 69 | err := decoder.Decode(&block) 70 | if err != nil { 71 | log.Panic(err) 72 | } 73 | return &block 74 | } 75 | 76 | //step4:新增方法 77 | //将Txs转为[]byte 78 | func (block *Block) HashTransactions()[]byte{ 79 | var txHashes [][] byte 80 | var txHash [32]byte 81 | for _,tx :=range block.Txs{ 82 | txHashes = append(txHashes,tx.TxID) 83 | } 84 | 85 | txHash = sha256.Sum256(bytes.Join(txHashes,[]byte{})) 86 | return txHash[:] 87 | } 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | -------------------------------------------------------------------------------- /day06_08_Update/BLC/BlockChainIterator.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import ( 4 | "github.com/boltdb/bolt" 5 | "log" 6 | ) 7 | 8 | //1.新增一个结构体 9 | type BlockChainIterator struct { 10 | CurrentHash [] byte //当前区块的hash 11 | DB *bolt.DB //数据库 12 | } 13 | 14 | 15 | 16 | 17 | //3.获取区块 18 | func (bcIterator *BlockChainIterator) Next() *Block { 19 | block:=new(Block) 20 | //1.打开数据库并读取 21 | err :=bcIterator.DB.View(func(tx *bolt.Tx) error { 22 | //2.打开数据表 23 | b:=tx.Bucket([]byte(BLOCKTABLENAME)) 24 | if b != nil{ 25 | //3.根据当前hash获取数据并反序列化 26 | blockBytes:=b.Get(bcIterator.CurrentHash) 27 | block = DeserializeBlock(blockBytes) 28 | //4.更新当前的hash 29 | bcIterator.CurrentHash = block.PrevBlockHash 30 | } 31 | 32 | return nil 33 | }) 34 | if err != nil{ 35 | log.Panic(err) 36 | } 37 | return block 38 | } 39 | 40 | 41 | -------------------------------------------------------------------------------- /day06_08_Update/BLC/CLI.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import ( 4 | "os" 5 | "fmt" 6 | "flag" 7 | "log" 8 | ) 9 | 10 | //step1: 11 | //CLI结构体 12 | type CLI struct { 13 | //Blockchain *BlockChain 14 | } 15 | 16 | //step2:添加Run方法 17 | func (cli *CLI) Run() { 18 | //判断命令行参数的长度 19 | isValidArgs() 20 | 21 | //1.创建flagset标签对象 22 | createWalletCmd := flag.NewFlagSet("createwallet", flag.ExitOnError) 23 | addressListsCmd := flag.NewFlagSet("addresslists",flag.ExitOnError) 24 | 25 | sendBlockCmd := flag.NewFlagSet("send", flag.ExitOnError) 26 | //fmt.Printf("%T\n",addBlockCmd) //*FlagSet 27 | printChainCmd := flag.NewFlagSet("printchain", flag.ExitOnError) 28 | createBlockChainCmd := flag.NewFlagSet("createblockchain", flag.ExitOnError) 29 | getBalanceCmd := flag.NewFlagSet("getbalance", flag.ExitOnError) 30 | 31 | testCmd:=flag.NewFlagSet("test",flag.ExitOnError) 32 | 33 | //2.设置标签后的参数 34 | //flagAddBlockData:= addBlockCmd.String("data","helloworld..","交易数据") 35 | flagFromData := sendBlockCmd.String("from", "", "转帐源地址") 36 | flagToData := sendBlockCmd.String("to", "", "转帐目标地址") 37 | flagAmountData := sendBlockCmd.String("amount", "", "转帐金额") 38 | flagCreateBlockChainData := createBlockChainCmd.String("address", "", "创世区块交易地址") 39 | flagGetBalanceData := getBalanceCmd.String("address", "", "要查询的某个账户的余额") 40 | 41 | //3.解析 42 | switch os.Args[1] { 43 | case "send": 44 | err := sendBlockCmd.Parse(os.Args[2:]) 45 | if err != nil { 46 | log.Panic(err) 47 | } 48 | //fmt.Println("----",os.Args[2:]) 49 | 50 | case "printchain": 51 | err := printChainCmd.Parse(os.Args[2:]) 52 | if err != nil { 53 | log.Panic(err) 54 | } 55 | //fmt.Println("====",os.Args[2:]) 56 | 57 | case "createblockchain": 58 | err := createBlockChainCmd.Parse(os.Args[2:]) 59 | if err != nil { 60 | log.Panic(err) 61 | } 62 | case "getbalance": 63 | err := getBalanceCmd.Parse(os.Args[2:]) 64 | if err != nil { 65 | log.Panic(err) 66 | } 67 | 68 | case "createwallet": 69 | err := createWalletCmd.Parse(os.Args[2:]) 70 | if err != nil { 71 | log.Panic(err) 72 | } 73 | case "addresslists": 74 | err := addressListsCmd.Parse(os.Args[2:]) 75 | if err != nil { 76 | log.Panic(err) 77 | } 78 | case "test": 79 | err := testCmd.Parse(os.Args[2:]) 80 | if err != nil { 81 | log.Panic(err) 82 | } 83 | default: 84 | printUsage() 85 | os.Exit(1) //退出 86 | } 87 | 88 | if sendBlockCmd.Parsed() { 89 | if *flagFromData == "" || *flagToData == "" || *flagAmountData == "" { 90 | printUsage() 91 | os.Exit(1) 92 | } 93 | //cli.addBlock([]*Transaction{}) 94 | //fmt.Println(*flagFromData) 95 | //fmt.Println(*flagToData) 96 | //fmt.Println(*flagAmountData) 97 | //fmt.Println(JSONToArray(*flagFrom)) 98 | //fmt.Println(JSONToArray(*flagTo)) 99 | //fmt.Println(JSONToArray(*flagAmount)) 100 | from := JSONToArray(*flagFromData) 101 | to := JSONToArray(*flagToData) 102 | amount := JSONToArray(*flagAmountData) 103 | 104 | for i := 0; i < len(from); i++ { 105 | if !IsValidForAddress([]byte(from[i])) || !IsValidForAddress([]byte(to[i])) { 106 | fmt.Println("钱包地址无效") 107 | printUsage() 108 | os.Exit(1) 109 | } 110 | } 111 | 112 | cli.send(from, to, amount) 113 | } 114 | if printChainCmd.Parsed() { 115 | cli.printChains() 116 | } 117 | 118 | if createBlockChainCmd.Parsed() { 119 | //if *flagCreateBlockChainData == "" { 120 | if !IsValidForAddress([]byte(*flagCreateBlockChainData)){ 121 | fmt.Println("创建地址无效") 122 | printUsage() 123 | os.Exit(1) 124 | } 125 | cli.createGenesisBlockchain(*flagCreateBlockChainData) 126 | } 127 | 128 | if getBalanceCmd.Parsed() { 129 | //if *flagGetBalanceData == "" { 130 | if !IsValidForAddress([]byte(*flagGetBalanceData)){ 131 | fmt.Println("查询地址无效") 132 | printUsage() 133 | os.Exit(1) 134 | } 135 | cli.getBalance(*flagGetBalanceData) 136 | 137 | } 138 | 139 | if createWalletCmd.Parsed() { 140 | //创建钱包 141 | cli.createWallet() 142 | } 143 | 144 | //获取所有的钱包地址 145 | if addressListsCmd.Parsed(){ 146 | cli.addressLists() 147 | } 148 | 149 | if testCmd.Parsed(){ 150 | cli.TestMethod() 151 | } 152 | 153 | } 154 | 155 | func isValidArgs() { 156 | if len(os.Args) < 2 { 157 | printUsage() 158 | os.Exit(1) 159 | } 160 | } 161 | func printUsage() { 162 | fmt.Println("Usage:") 163 | fmt.Println("\tcreatewallet -- 创建钱包") 164 | fmt.Println("\taddresslists -- 输出所有钱包地址") 165 | fmt.Println("\tcreateblockchain -address DATA -- 创建创世区块") 166 | fmt.Println("\tsend -from From -to To -amount Amount - 交易数据") 167 | fmt.Println("\tprintchain - 输出信息:") 168 | fmt.Println("\tgetbalance -address DATA -- 查询账户余额") 169 | fmt.Println("\ttest -- 测试") 170 | } 171 | -------------------------------------------------------------------------------- /day06_08_Update/BLC/CLI_addresslists.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import "fmt" 4 | 5 | func (cli *CLI)addressLists(){ 6 | fmt.Println("打印所有的钱包地址。。") 7 | //获取 8 | Wallets:=NewWallets() 9 | for address,_ := range Wallets.WalletsMap{ 10 | fmt.Println("address:",address) 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /day06_08_Update/BLC/CLI_createBlockChain.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | func (cli *CLI) createGenesisBlockchain(address string){ 4 | //fmt.Println(data) 5 | CreateBlockChainWithGenesisBlock(address) 6 | 7 | 8 | bc:=GetBlockchainObject() 9 | defer bc.DB.Close() 10 | if bc != nil{ 11 | utxoSet:=&UTXOSet{bc} 12 | utxoSet.ResetUTXOSet() 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /day06_08_Update/BLC/CLI_createwallet.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | func (cli *CLI) createWallet(){ 4 | wallets:= NewWallets() 5 | wallets.CreateNewWallet() 6 | } 7 | -------------------------------------------------------------------------------- /day06_08_Update/BLC/CLI_getBalance.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | ) 7 | 8 | //查询余额 9 | func (cli *CLI)getBalance(address string){ 10 | fmt.Println("查询余额:",address) 11 | bc := GetBlockchainObject() 12 | 13 | if bc == nil{ 14 | fmt.Println("数据库不存在,无法查询。。") 15 | os.Exit(1) 16 | } 17 | defer bc.DB.Close() 18 | //txOutputs:= bc.UnUTXOs(address) 19 | //for i,out:=range txOutputs{ 20 | // fmt.Println(i,"---->",out) 21 | //} 22 | //balance:=bc.GetBalance(address,[]*Transaction{}) 23 | utxoSet:=&UTXOSet{bc} 24 | balance:= utxoSet.GetBalance(address) 25 | fmt.Printf("%s,一共有%d个Token\n",address,balance) 26 | } 27 | -------------------------------------------------------------------------------- /day06_08_Update/BLC/CLI_printChains.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | ) 7 | 8 | func (cli *CLI)printChains(){ 9 | bc:=GetBlockchainObject() 10 | if bc == nil{ 11 | fmt.Println("没有区块可以打印。。") 12 | os.Exit(1) 13 | } 14 | defer bc.DB.Close() 15 | bc.PrintChains() 16 | } -------------------------------------------------------------------------------- /day06_08_Update/BLC/CLI_send.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | ) 7 | 8 | //转账 9 | func (cli *CLI) send(from, to, amount [] string) { 10 | if !dbExists() { 11 | fmt.Println("数据库不存在。。。") 12 | os.Exit(1) 13 | } 14 | blockchain := GetBlockchainObject() 15 | 16 | blockchain.MineNewBlock(from, to, amount) 17 | defer blockchain.DB.Close() 18 | 19 | utxoSet:=&UTXOSet{blockchain} 20 | //转账成功以后,需要更新 21 | //utxoSet.ResetUTXOSet() 22 | utxoSet.Update() 23 | } 24 | -------------------------------------------------------------------------------- /day06_08_Update/BLC/CLI_testmethod.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import "fmt" 4 | 5 | func (cli *CLI) TestMethod(){ 6 | blockchain:=GetBlockchainObject() 7 | defer blockchain.DB.Close() 8 | 9 | unSpentOutputMap:=blockchain.FindUnSpentOutputMap() 10 | fmt.Println(unSpentOutputMap) 11 | for key,value:=range unSpentOutputMap{ 12 | fmt.Println(key) 13 | for _,utxo:=range value.UTXOS{ 14 | fmt.Println("金额:",utxo.Output.Value) 15 | fmt.Printf("地址:%v\n",utxo.Output.PubKeyHash) 16 | fmt.Println("---------------------") 17 | } 18 | } 19 | 20 | utxoSet:=&UTXOSet{blockchain} 21 | utxoSet.ResetUTXOSet() 22 | } 23 | 24 | 25 | -------------------------------------------------------------------------------- /day06_08_Update/BLC/Constant.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | const DBNAME = "blockchain.db" //数据库名 4 | const BLOCKTABLENAME = "blocks" //表名 5 | 6 | 7 | -------------------------------------------------------------------------------- /day06_08_Update/BLC/ProofOfWork.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import ( 4 | "math/big" 5 | "bytes" 6 | "crypto/sha256" 7 | "fmt" 8 | ) 9 | 10 | // 0000 0000 0000 0000 1001 0001 0000 .... 0001 11 | //256位Hash里面前面至少有16个零 12 | const TargetBit = 16 // 20 13 | 14 | type ProofOfWork struct { 15 | //要验证的区块 16 | Block *Block 17 | 18 | //大整数存储,目标哈希 19 | Target *big.Int 20 | } 21 | 22 | func NewProofOfWork(block *Block) *ProofOfWork { 23 | //1.创建一个big对象 0000000.....00001 24 | /* 25 | 0000 0001 26 | 0010 0000 27 | */ 28 | target := big.NewInt(1) 29 | 30 | //2.左移256-bits位 31 | target = target.Lsh(target, 256-TargetBit) 32 | 33 | return &ProofOfWork{block, target} 34 | } 35 | 36 | func (pow *ProofOfWork) Run() ([] byte, int64) { 37 | //1.将Block的属性拼接成字节数组 38 | //2.生成Hash 39 | //3.循环判断Hash的有效性,满足条件,跳出循环结束验证 40 | nonce := 0 41 | //var hashInt big.Int //用于存储新生成的hash 42 | hashInt := new(big.Int) 43 | var hash [32]byte 44 | for{ 45 | //获取字节数组 46 | dataBytes := pow.prepareData(nonce) 47 | //生成hash 48 | hash = sha256.Sum256(dataBytes) 49 | //fmt.Printf("%d: %x\n",nonce,hash) 50 | fmt.Printf("\r%d: %x",nonce,hash) 51 | //将hash存储到hashInt 52 | hashInt.SetBytes(hash[:]) 53 | //判断hashInt是否小于Block里的target 54 | /* 55 | Com compares x and y and returns: 56 | -1 if x < y 57 | 0 if x == y 58 | 1 if x > y 59 | */ 60 | if pow.Target.Cmp(hashInt) == 1{ 61 | break 62 | } 63 | nonce++ 64 | } 65 | fmt.Println() 66 | return hash[:], int64(nonce) 67 | } 68 | 69 | func (pow *ProofOfWork) prepareData(nonce int)[]byte{ 70 | data := bytes.Join( 71 | [][] byte{ 72 | pow.Block.PrevBlockHash, 73 | pow.Block.HashTransactions(), 74 | IntToHex(pow.Block.TimeStamp), 75 | IntToHex(int64(TargetBit)), 76 | IntToHex(int64(nonce)), 77 | IntToHex(int64(pow.Block.Height)), 78 | }, 79 | [] byte{}, 80 | ) 81 | return data 82 | } 83 | -------------------------------------------------------------------------------- /day06_08_Update/BLC/Transaction_TxInput.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import "bytes" 4 | 5 | type TXInput struct { 6 | //1.交易的ID 7 | TxID [] byte 8 | //2.存储Txoutput的vout里面的索引 9 | Vout int 10 | //3.用户名 11 | //ScriptSiq string 12 | Signature [] byte //数字签名 13 | PublicKey [] byte //公钥,钱包里面 14 | } 15 | 16 | //判断当前txInput消费,和指定的address是否一致 17 | func (txInput *TXInput) UnLockWithAddress(pubKeyHash []byte) bool{ 18 | //return txInput.ScriptSiq == address 19 | publicKey:=PubKeyHash(txInput.PublicKey) 20 | return bytes.Compare(pubKeyHash,publicKey) == 0 21 | } 22 | 23 | 24 | -------------------------------------------------------------------------------- /day06_08_Update/BLC/Transaction_TxOutput.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import "bytes" 4 | 5 | //交易的输出,就是币实际存储的地方 6 | type TXOuput struct { 7 | Value int64 8 | //一个锁定脚本(ScriptPubKey),要花这笔钱,必须要解锁该脚本。 9 | //ScriptPubKey string //公钥:先理解为,用户名 10 | PubKeyHash [] byte // 公钥 11 | } 12 | 13 | //判断当前txOutput消费,和指定的address是否一致 14 | func (txOutput *TXOuput) UnLockWithAddress(address string) bool { 15 | //return txOutput.ScriptPubKey == address 16 | fullPayloadHash := Base58Decode([]byte(address)) 17 | pubKeyHash := fullPayloadHash[1:len(fullPayloadHash)-4] 18 | return bytes.Compare(txOutput.PubKeyHash, pubKeyHash) == 0 19 | } 20 | 21 | 22 | func NewTXOuput(value int64,address string) *TXOuput{ 23 | txOutput := &TXOuput{value, nil} 24 | //设置Ripemd160Hash 25 | txOutput.Lock(address) 26 | return txOutput 27 | } 28 | 29 | func (txOutput *TXOuput) Lock(address string) { 30 | publicKeyHash := Base58Decode([] byte(address)) 31 | txOutput.PubKeyHash = publicKeyHash[1:len(publicKeyHash)-4] 32 | } -------------------------------------------------------------------------------- /day06_08_Update/BLC/Transaction_UTXO.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | //step1:创建一个结构体UTXO,用于表示所有未花费的 4 | type UTXO struct { 5 | TxID [] byte //当前Transaction的交易ID 6 | Index int //下标索引 7 | Output *TXOuput // 8 | } 9 | -------------------------------------------------------------------------------- /day06_08_Update/BLC/TxOutputs.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import ( 4 | "bytes" 5 | "encoding/gob" 6 | "log" 7 | ) 8 | 9 | type TxOutputs struct { 10 | UTXOS []*UTXO 11 | } 12 | 13 | 14 | //序列化 15 | func (outs *TxOutputs) Serilalize()[]byte{ 16 | //1.创建一个buffer 17 | var result bytes.Buffer 18 | //2.创建一个编码器 19 | encoder := gob.NewEncoder(&result) 20 | //3.编码--->打包 21 | err := encoder.Encode(outs) 22 | if err != nil { 23 | log.Panic(err) 24 | } 25 | return result.Bytes() 26 | } 27 | 28 | //反序列化 29 | func DeserializeTXOutputs(txOutputsBytes [] byte) *TxOutputs { 30 | var txOutputs TxOutputs 31 | var reader = bytes.NewReader(txOutputsBytes) 32 | //1.创建一个解码器 33 | decoder := gob.NewDecoder(reader) 34 | //解包 35 | err := decoder.Decode(&txOutputs) 36 | if err != nil { 37 | log.Panic(err) 38 | } 39 | return &txOutputs 40 | } 41 | -------------------------------------------------------------------------------- /day06_08_Update/BLC/Wallet.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import ( 4 | "crypto/ecdsa" 5 | "crypto/elliptic" 6 | "crypto/rand" 7 | "log" 8 | "crypto/sha256" 9 | "golang.org/x/crypto/ripemd160" 10 | "bytes" 11 | ) 12 | 13 | //step1:创建一个钱包 14 | type Wallet struct { 15 | //1.私钥 16 | PrivateKey ecdsa.PrivateKey 17 | //2.公钥 18 | PublicKey [] byte 19 | } 20 | 21 | //step2:产生一对密钥 22 | func newKeyPair() (ecdsa.PrivateKey, []byte) { 23 | /* 24 | 1.通过椭圆曲线算法,随机产生私钥 25 | 2.根据私钥生成公钥 26 | 27 | elliptic:椭圆 28 | curve:曲线 29 | ecc:椭圆曲线加密 30 | ecdsa:elliptic curve digital signature algorithm,椭圆曲线数字签名算法 31 | 比特币使用SECP256K1算法,p256是ecdsa算法中的一种 32 | 33 | */ 34 | //椭圆加密 35 | curve := elliptic.P256() //椭圆加密算法,得到一个椭圆曲线值,全称:SECP256k1 36 | private, err := ecdsa.GenerateKey(curve, rand.Reader) 37 | if err != nil { 38 | log.Panic(err) 39 | } 40 | //生成公钥 41 | pubKey := append(private.PublicKey.X.Bytes(), private.PublicKey.Y.Bytes()...) 42 | return *private, pubKey 43 | } 44 | 45 | //step3:提供一个方法用于获取钱包 46 | func NewWallet() *Wallet { 47 | privateKey, publicKey := newKeyPair() 48 | //fmt.Println("privateKey:", privateKey, ",publicKey:", publicKey) 49 | return &Wallet{privateKey, publicKey} 50 | } 51 | 52 | //step4:根据一个公钥获取对应的地址 53 | /* 54 | 将公钥sha2561次,再160,1次 55 | 然后version+hash 56 | */ 57 | func (w *Wallet) GetAddress() [] byte { 58 | //1.先将公钥进行一次hash256,一次160,得到pubKeyHash 59 | pubKeyHash := PubKeyHash(w.PublicKey) 60 | //2.添加版本号 61 | versioned_payload := append([]byte{version}, pubKeyHash...) 62 | // 3.获取校验和,将pubKeyhash,两次sha256后,取前4位 63 | checkSumBytes := CheckSum(versioned_payload) 64 | full_payload := append(versioned_payload, checkSumBytes...) 65 | //fmt.Println(len(full_payload)) 66 | //4.Base58 67 | address := Base58Encode(full_payload) 68 | return address 69 | 70 | } 71 | 72 | //一次sha256,再一次ripemd160,得到publicKeyHash 73 | func PubKeyHash(publicKey [] byte) []byte { 74 | //1.sha256 75 | hasher := sha256.New() 76 | hasher.Write(publicKey) 77 | hash := hasher.Sum(nil) 78 | 79 | //2.ripemd160 80 | ripemder := ripemd160.New() 81 | ripemder.Write(hash) 82 | pubKeyHash := ripemder.Sum(nil) 83 | 84 | //返回 85 | return pubKeyHash 86 | } 87 | 88 | const version = byte(0x00) 89 | const addressChecksumLen = 4 90 | 91 | //获取验证码:将公钥哈希两次sha256,取前4位,就是校验和 92 | func CheckSum(payload []byte) []byte { 93 | firstSHA := sha256.Sum256(payload) 94 | secondSHA := sha256.Sum256(firstSHA[:]) 95 | return secondSHA[:addressChecksumLen] 96 | } 97 | 98 | 99 | 100 | //判断地址是否有效 101 | /* 102 | 根据地址,base58解码后获取byte[],获取校验和数组 103 | 使用 104 | */ 105 | func IsValidForAddress(address []byte) bool { 106 | full_payload := Base58Decode(address) 107 | //fmt.Println("检验version_public_checksumBytes:",full_payload) 108 | checkSumBytes := full_payload[len(full_payload)-addressChecksumLen:] 109 | //fmt.Println("检验checkSumBytes:",checkSumBytes) 110 | versioned_payload := full_payload[:len(full_payload)-addressChecksumLen] 111 | //fmt.Println("检验version_ripemd160:",versioned_payload) 112 | checkBytes := CheckSum(versioned_payload) 113 | //fmt.Println("检验checkBytes:",checkBytes) 114 | if bytes.Compare(checkSumBytes, checkBytes) == 0 { 115 | return true 116 | } 117 | return false 118 | } -------------------------------------------------------------------------------- /day06_08_Update/BLC/Wallets.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "io/ioutil" 7 | "log" 8 | "encoding/gob" 9 | "crypto/elliptic" 10 | "bytes" 11 | ) 12 | 13 | //1.创建钱包 14 | type Wallets struct { 15 | WalletsMap map[string]*Wallet 16 | } 17 | 18 | //2.创建一个钱包集合 19 | //创建钱包集合:文件中存在从文件中读取,否则新建一个 20 | const walletFile = "Wallets.dat" 21 | 22 | func NewWallets() *Wallets { 23 | //wallets := &WalletsMap{} 24 | //wallets.WalletsMap = make(map[string]*Wallet) 25 | //return wallets 26 | //1.判断钱包文件是否存在 27 | if _, err := os.Stat(walletFile); os.IsNotExist(err) { 28 | fmt.Println("文件不存在") 29 | wallets := &Wallets{} 30 | wallets.WalletsMap = make(map[string]*Wallet) 31 | return wallets 32 | } 33 | //2.否则读取文件中的数据 34 | fileContent, err := ioutil.ReadFile(walletFile) 35 | if err != nil { 36 | log.Panic(err) 37 | } 38 | var wallets Wallets 39 | gob.Register(elliptic.P256()) 40 | decoder := gob.NewDecoder(bytes.NewReader(fileContent)) 41 | err = decoder.Decode(&wallets) 42 | if err != nil { 43 | log.Panic(err) 44 | } 45 | return &wallets 46 | } 47 | 48 | //3.创建一个新钱包 49 | func (ws *Wallets) CreateNewWallet() { 50 | wallet := NewWallet() 51 | fmt.Printf("创建钱包地址:%s\n", wallet.GetAddress()) 52 | ws.WalletsMap[string(wallet.GetAddress())] = wallet 53 | 54 | //将钱包保存 55 | ws.SaveWallets() 56 | } 57 | 58 | /* 59 | 要让数据对象能在网络上传输或存储,我们需要进行编码和解码。现在比较流行的编码方式有JSON,XML等。然而,Go在gob包中为我们提供了另一种方式,该方式编解码效率高于JSON。 60 | gob是Golang包自带的一个数据结构序列化的编码/解码工具 61 | */ 62 | func (ws *Wallets) SaveWallets() { 63 | var content bytes.Buffer 64 | //注册的目的,为了可以序列化任何类型,wallet结构体中有接口类型。将接口进行注册 65 | gob.Register(elliptic.P256()) //gob是Golang包自带的一个数据结构序列化的编码/解码工具 66 | encoder := gob.NewEncoder(&content) 67 | err := encoder.Encode(ws) 68 | if err != nil { 69 | log.Panic(err) 70 | } 71 | //将序列化后的数据写入到文件,原来的文件中的内容会被覆盖掉 72 | err = ioutil.WriteFile(walletFile, content.Bytes(), 0644) 73 | if err != nil { 74 | log.Panic(err) 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /day06_08_Update/BLC/base58.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | import ( 3 | "math/big" 4 | "bytes" 5 | ) 6 | 7 | //base64 8 | 9 | /* 10 | ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/ 11 | 0(零),O(大写的o),I(大写的i),l(小写的L),+,/ 12 | */ 13 | 14 | var b58Alphabet = []byte("123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz") 15 | 16 | //字节数组转Base58,加密 17 | func Base58Encode(input []byte)[]byte{ 18 | var result [] byte 19 | x := big.NewInt(0).SetBytes(input) 20 | 21 | base :=big.NewInt(int64(len(b58Alphabet))) 22 | zero:=big.NewInt(0) 23 | mod:= &big.Int{} 24 | for x.Cmp(zero) !=0{ 25 | x.DivMod(x,base,mod) 26 | result = append(result,b58Alphabet[mod.Int64()]) 27 | } 28 | ReverseBytes(result) 29 | for b:=range input{ 30 | if b == 0x00{ 31 | result = append([]byte{b58Alphabet[0]},result...) 32 | }else { 33 | break 34 | } 35 | } 36 | 37 | return result 38 | 39 | } 40 | 41 | //Base58转字节数组,解密 42 | func Base58Decode(input[] byte)[]byte{ 43 | result:=big.NewInt(0) 44 | zeroBytes := 0 45 | for b:=range input{ 46 | if b == 0x00{ 47 | zeroBytes++ 48 | } 49 | } 50 | payload := input[zeroBytes:] 51 | for _, b := range payload { 52 | charIndex := bytes.IndexByte(b58Alphabet, b) 53 | result.Mul(result, big.NewInt(58)) 54 | result.Add(result, big.NewInt(int64(charIndex))) 55 | } 56 | 57 | decoded := result.Bytes() 58 | decoded = append(bytes.Repeat([]byte{byte(0x00)}, zeroBytes), decoded...) 59 | 60 | return decoded 61 | } 62 | 63 | 64 | -------------------------------------------------------------------------------- /day06_08_Update/BLC/utils.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import ( 4 | "bytes" 5 | "encoding/binary" 6 | "log" 7 | "encoding/json" 8 | ) 9 | 10 | /* 11 | 将一个int64的整数:转为二进制后,每8bit一个byte。转为[]byte 12 | */ 13 | func IntToHex(num int64) []byte { 14 | buff := new(bytes.Buffer) 15 | //将二进制数据写入w 16 | //func Write(w io.Writer, order ByteOrder, data interface{}) error 17 | err := binary.Write(buff, binary.BigEndian, num) 18 | if err != nil { 19 | log.Panic(err) 20 | } 21 | //转为[]byte并返回 22 | return buff.Bytes() 23 | } 24 | 25 | /* 26 | Json字符串转为[] string数组 27 | */ 28 | func JSONToArray (jsonString string) [] string{ 29 | var sArr [] string 30 | if err := json.Unmarshal([]byte(jsonString),&sArr);err != nil{ 31 | log.Panic(err) 32 | } 33 | return sArr 34 | } 35 | 36 | 37 | //字节数组反转 38 | func ReverseBytes(data []byte) { 39 | for i, j := 0, len(data)-1; i < j; i, j = i+1, j-1 { 40 | data[i], data[j] = data[j], data[i] 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /day06_08_Update/Wallets.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rubyhan1314/PublicChain/fd8b04084c29fe82efe813a0c30864ed1df00383/day06_08_Update/Wallets.dat -------------------------------------------------------------------------------- /day06_08_Update/bc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rubyhan1314/PublicChain/fd8b04084c29fe82efe813a0c30864ed1df00383/day06_08_Update/bc -------------------------------------------------------------------------------- /day06_08_Update/blockchain.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rubyhan1314/PublicChain/fd8b04084c29fe82efe813a0c30864ed1df00383/day06_08_Update/blockchain.db -------------------------------------------------------------------------------- /day06_08_Update/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "./BLC" 5 | ) 6 | 7 | func main() { 8 | //1.测试Block 9 | //block:=BLC.NewBlock("I am a block",make([]byte,32,32),1) 10 | //fmt.Println(block) 11 | //2.测试创世区块 12 | //genesisBlock :=BLC.CreateGenesisBlock("Genesis Block..") 13 | //fmt.Println(genesisBlock) 14 | 15 | //3.测试区块链 16 | //genesisBlockChain := BLC.CreateBlockChainWithGenesisBlock() 17 | //fmt.Println(genesisBlockChain) 18 | //fmt.Println(genesisBlockChain.Blocks) 19 | //fmt.Println(genesisBlockChain.Blocks[0]) 20 | 21 | //4.测试添加新区块 22 | //blockChain:=BLC.CreateBlockChainWithGenesisBlock() 23 | //blockChain.AddBlockToBlockChain("Send 100RMB To Wangergou",blockChain.Blocks[len(blockChain.Blocks)-1].Height+1,blockChain.Blocks[len(blockChain.Blocks)-1].Hash) 24 | //blockChain.AddBlockToBlockChain("Send 300RMB To lixiaohua",blockChain.Blocks[len(blockChain.Blocks)-1].Height+1,blockChain.Blocks[len(blockChain.Blocks)-1].Hash) 25 | //blockChain.AddBlockToBlockChain("Send 500RMB To rose",blockChain.Blocks[len(blockChain.Blocks)-1].Height+1,blockChain.Blocks[len(blockChain.Blocks)-1].Hash) 26 | // 27 | //fmt.Println(blockChain) 28 | 29 | //5.测试序列化和反序列化 30 | //block:=BLC.NewBlock("helloworld",make([]byte,32,32),0) 31 | //data:=block.Serilalize() 32 | //fmt.Println(block) 33 | //fmt.Println(data) 34 | //block2:=BLC.DeserializeBlock(data) 35 | //fmt.Println(block2) 36 | 37 | //6.创建区块,存入数据库 38 | //打开数据库 39 | //block:=BLC.NewBlock("helloworld",make([]byte,32,32),0) 40 | //db,err := bolt.Open("my.db",0600,nil) 41 | //if err != nil{ 42 | // log.Fatal(err) 43 | //} 44 | // 45 | //defer db.Close() 46 | // 47 | //err = db.Update(func(tx *bolt.Tx) error { 48 | // //获取bucket,没有就创建新表 49 | // b := tx.Bucket([]byte("blocks")) 50 | // if b == nil{ 51 | // b,err = tx.CreateBucket([] byte("blocks")) 52 | // if err !=nil{ 53 | // log.Panic("创建表失败") 54 | // } 55 | // } 56 | // //添加数据 57 | // err = b.Put([]byte("l"),block.Serilalize()) 58 | // if err !=nil{ 59 | // log.Panic(err) 60 | // } 61 | // 62 | // return nil 63 | //}) 64 | //if err != nil{ 65 | // log.Panic(err) 66 | //} 67 | //err = db.View(func(tx *bolt.Tx) error { 68 | // b := tx.Bucket([]byte("blocks")) 69 | // if b !=nil{ 70 | // data := b.Get([]byte("l")) 71 | // //fmt.Printf("%s\n",data)//直接打印会乱码 72 | // //反序列化 73 | // block2:=BLC.DeserializeBlock(data) 74 | // //fmt.Println(block2) 75 | // fmt.Printf("%v\n",block2) 76 | // 77 | // } 78 | // return nil 79 | //}) 80 | 81 | //7.测试创世区块存入数据库 82 | //blockchain:=BLC.CreateBlockChainWithGenesisBlock("Genesis Block..") 83 | //fmt.Println(blockchain) 84 | //defer blockchain.DB.Close() 85 | //8.测试新添加的区块 86 | //blockchain.AddBlockToBlockChain("Send 100RMB to wangergou") 87 | //blockchain.AddBlockToBlockChain("Send 100RMB to lixiaohua") 88 | //blockchain.AddBlockToBlockChain("Send 100RMB to rose") 89 | //fmt.Println(blockchain) 90 | //blockchain.PrintChains() 91 | 92 | //9.CLI操作 93 | cli:=BLC.CLI{} 94 | cli.Run() 95 | 96 | //outsMap := make(map[string]*BLC.TxOutputs) 97 | //outputs:=outsMap["aa"] 98 | //fmt.Println(outputs) 99 | //fmt.Println(len(outputs.UTXOS)) 100 | 101 | 102 | } -------------------------------------------------------------------------------- /day07_09_Merkle/BLC/Block.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import ( 4 | "time" 5 | "bytes" 6 | "encoding/gob" 7 | "log" 8 | ) 9 | //step2:修改Block的交易类型 10 | type Block struct { 11 | //字段: 12 | //高度Height:其实就是区块的编号,第一个区块叫创世区块,高度为0 13 | Height int64 14 | //上一个区块的哈希值ProvHash: 15 | PrevBlockHash []byte 16 | //交易数据Data:目前先设计为[]byte,后期是Transaction 17 | //Data [] byte 18 | Txs [] *Transaction 19 | //时间戳TimeStamp: 20 | TimeStamp int64 21 | //哈希值Hash:32个的字节,64个16进制数 22 | Hash []byte 23 | 24 | Nonce int64 25 | } 26 | 27 | func NewBlock(txs []*Transaction,provBlockHash []byte,height int64) *Block{ 28 | //创建区块 29 | block:=&Block{height,provBlockHash,txs,time.Now().Unix(),nil,0} 30 | //step5:设置block的hash和nonce 31 | //设置哈希 32 | //block.SetHash() 33 | //调用工作量证明的方法,并且返回有效的Hash和Nonce 34 | pow:=NewProofOfWork(block) 35 | hash,nonce:=pow.Run() 36 | block.Hash = hash 37 | block.Nonce = nonce 38 | 39 | 40 | return block 41 | } 42 | 43 | func CreateGenesisBlock(txs []*Transaction) *Block{ 44 | return NewBlock(txs,make([] byte,32,32),0) 45 | } 46 | 47 | //将区块序列化,得到一个字节数组---区块的行为,设计为方法 48 | func (block *Block) Serilalize() []byte { 49 | //1.创建一个buffer 50 | var result bytes.Buffer 51 | //2.创建一个编码器 52 | encoder := gob.NewEncoder(&result) 53 | //3.编码--->打包 54 | err := encoder.Encode(block) 55 | if err != nil { 56 | log.Panic(err) 57 | } 58 | return result.Bytes() 59 | } 60 | 61 | //反序列化,得到一个区块---设计为函数 62 | func DeserializeBlock(blockBytes [] byte) *Block { 63 | var block Block 64 | var reader = bytes.NewReader(blockBytes) 65 | //1.创建一个解码器 66 | decoder := gob.NewDecoder(reader) 67 | //解包 68 | err := decoder.Decode(&block) 69 | if err != nil { 70 | log.Panic(err) 71 | } 72 | return &block 73 | } 74 | 75 | //step4:新增方法 76 | //将Txs转为[]byte 77 | func (block *Block) HashTransactions()[]byte{ 78 | //var txHashes [][] byte 79 | //var txHash [32]byte 80 | //for _,tx :=range block.Txs{ 81 | // txHashes = append(txHashes,tx.TxID) 82 | //} 83 | // 84 | //txHash = sha256.Sum256(bytes.Join(txHashes,[]byte{})) 85 | //return txHash[:] 86 | 87 | var txs [][] byte 88 | for _,tx:=range block.Txs{ 89 | txs = append(txs, tx.Serialize()) 90 | } 91 | mTree:=NewMerkleTree(txs) 92 | return mTree.RootNode.Data 93 | 94 | 95 | } 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | -------------------------------------------------------------------------------- /day07_09_Merkle/BLC/BlockChainIterator.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import ( 4 | "github.com/boltdb/bolt" 5 | "log" 6 | ) 7 | 8 | //1.新增一个结构体 9 | type BlockChainIterator struct { 10 | CurrentHash [] byte //当前区块的hash 11 | DB *bolt.DB //数据库 12 | } 13 | 14 | 15 | 16 | 17 | //3.获取区块 18 | func (bcIterator *BlockChainIterator) Next() *Block { 19 | block:=new(Block) 20 | //1.打开数据库并读取 21 | err :=bcIterator.DB.View(func(tx *bolt.Tx) error { 22 | //2.打开数据表 23 | b:=tx.Bucket([]byte(BLOCKTABLENAME)) 24 | if b != nil{ 25 | //3.根据当前hash获取数据并反序列化 26 | blockBytes:=b.Get(bcIterator.CurrentHash) 27 | block = DeserializeBlock(blockBytes) 28 | //4.更新当前的hash 29 | bcIterator.CurrentHash = block.PrevBlockHash 30 | } 31 | 32 | return nil 33 | }) 34 | if err != nil{ 35 | log.Panic(err) 36 | } 37 | return block 38 | } 39 | 40 | 41 | -------------------------------------------------------------------------------- /day07_09_Merkle/BLC/CLI.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import ( 4 | "os" 5 | "fmt" 6 | "flag" 7 | "log" 8 | ) 9 | 10 | //step1: 11 | //CLI结构体 12 | type CLI struct { 13 | //Blockchain *BlockChain 14 | } 15 | 16 | //step2:添加Run方法 17 | func (cli *CLI) Run() { 18 | //判断命令行参数的长度 19 | isValidArgs() 20 | 21 | //1.创建flagset标签对象 22 | createWalletCmd := flag.NewFlagSet("createwallet", flag.ExitOnError) 23 | addressListsCmd := flag.NewFlagSet("addresslists",flag.ExitOnError) 24 | 25 | sendBlockCmd := flag.NewFlagSet("send", flag.ExitOnError) 26 | //fmt.Printf("%T\n",addBlockCmd) //*FlagSet 27 | printChainCmd := flag.NewFlagSet("printchain", flag.ExitOnError) 28 | createBlockChainCmd := flag.NewFlagSet("createblockchain", flag.ExitOnError) 29 | getBalanceCmd := flag.NewFlagSet("getbalance", flag.ExitOnError) 30 | 31 | testCmd:=flag.NewFlagSet("test",flag.ExitOnError) 32 | 33 | //2.设置标签后的参数 34 | //flagAddBlockData:= addBlockCmd.String("data","helloworld..","交易数据") 35 | flagFromData := sendBlockCmd.String("from", "", "转帐源地址") 36 | flagToData := sendBlockCmd.String("to", "", "转帐目标地址") 37 | flagAmountData := sendBlockCmd.String("amount", "", "转帐金额") 38 | flagCreateBlockChainData := createBlockChainCmd.String("address", "", "创世区块交易地址") 39 | flagGetBalanceData := getBalanceCmd.String("address", "", "要查询的某个账户的余额") 40 | 41 | //3.解析 42 | switch os.Args[1] { 43 | case "send": 44 | err := sendBlockCmd.Parse(os.Args[2:]) 45 | if err != nil { 46 | log.Panic(err) 47 | } 48 | //fmt.Println("----",os.Args[2:]) 49 | 50 | case "printchain": 51 | err := printChainCmd.Parse(os.Args[2:]) 52 | if err != nil { 53 | log.Panic(err) 54 | } 55 | //fmt.Println("====",os.Args[2:]) 56 | 57 | case "createblockchain": 58 | err := createBlockChainCmd.Parse(os.Args[2:]) 59 | if err != nil { 60 | log.Panic(err) 61 | } 62 | case "getbalance": 63 | err := getBalanceCmd.Parse(os.Args[2:]) 64 | if err != nil { 65 | log.Panic(err) 66 | } 67 | 68 | case "createwallet": 69 | err := createWalletCmd.Parse(os.Args[2:]) 70 | if err != nil { 71 | log.Panic(err) 72 | } 73 | case "addresslists": 74 | err := addressListsCmd.Parse(os.Args[2:]) 75 | if err != nil { 76 | log.Panic(err) 77 | } 78 | case "test": 79 | err := testCmd.Parse(os.Args[2:]) 80 | if err != nil { 81 | log.Panic(err) 82 | } 83 | default: 84 | printUsage() 85 | os.Exit(1) //退出 86 | } 87 | 88 | if sendBlockCmd.Parsed() { 89 | if *flagFromData == "" || *flagToData == "" || *flagAmountData == "" { 90 | printUsage() 91 | os.Exit(1) 92 | } 93 | //cli.addBlock([]*Transaction{}) 94 | //fmt.Println(*flagFromData) 95 | //fmt.Println(*flagToData) 96 | //fmt.Println(*flagAmountData) 97 | //fmt.Println(JSONToArray(*flagFrom)) 98 | //fmt.Println(JSONToArray(*flagTo)) 99 | //fmt.Println(JSONToArray(*flagAmount)) 100 | from := JSONToArray(*flagFromData) 101 | to := JSONToArray(*flagToData) 102 | amount := JSONToArray(*flagAmountData) 103 | 104 | for i := 0; i < len(from); i++ { 105 | if !IsValidForAddress([]byte(from[i])) || !IsValidForAddress([]byte(to[i])) { 106 | fmt.Println("钱包地址无效") 107 | printUsage() 108 | os.Exit(1) 109 | } 110 | } 111 | 112 | cli.send(from, to, amount) 113 | } 114 | if printChainCmd.Parsed() { 115 | cli.printChains() 116 | } 117 | 118 | if createBlockChainCmd.Parsed() { 119 | //if *flagCreateBlockChainData == "" { 120 | if !IsValidForAddress([]byte(*flagCreateBlockChainData)){ 121 | fmt.Println("创建地址无效") 122 | printUsage() 123 | os.Exit(1) 124 | } 125 | cli.createGenesisBlockchain(*flagCreateBlockChainData) 126 | } 127 | 128 | if getBalanceCmd.Parsed() { 129 | //if *flagGetBalanceData == "" { 130 | if !IsValidForAddress([]byte(*flagGetBalanceData)){ 131 | fmt.Println("查询地址无效") 132 | printUsage() 133 | os.Exit(1) 134 | } 135 | cli.getBalance(*flagGetBalanceData) 136 | 137 | } 138 | 139 | if createWalletCmd.Parsed() { 140 | //创建钱包 141 | cli.createWallet() 142 | } 143 | 144 | //获取所有的钱包地址 145 | if addressListsCmd.Parsed(){ 146 | cli.addressLists() 147 | } 148 | 149 | if testCmd.Parsed(){ 150 | cli.TestMethod() 151 | } 152 | 153 | } 154 | 155 | func isValidArgs() { 156 | if len(os.Args) < 2 { 157 | printUsage() 158 | os.Exit(1) 159 | } 160 | } 161 | func printUsage() { 162 | fmt.Println("Usage:") 163 | fmt.Println("\tcreatewallet -- 创建钱包") 164 | fmt.Println("\taddresslists -- 输出所有钱包地址") 165 | fmt.Println("\tcreateblockchain -address DATA -- 创建创世区块") 166 | fmt.Println("\tsend -from From -to To -amount Amount - 交易数据") 167 | fmt.Println("\tprintchain - 输出信息:") 168 | fmt.Println("\tgetbalance -address DATA -- 查询账户余额") 169 | fmt.Println("\ttest -- 测试") 170 | } 171 | -------------------------------------------------------------------------------- /day07_09_Merkle/BLC/CLI_addresslists.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import "fmt" 4 | 5 | func (cli *CLI)addressLists(){ 6 | fmt.Println("打印所有的钱包地址。。") 7 | //获取 8 | Wallets:=NewWallets() 9 | for address,_ := range Wallets.WalletsMap{ 10 | fmt.Println("address:",address) 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /day07_09_Merkle/BLC/CLI_createBlockChain.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | 4 | func (cli *CLI) createGenesisBlockchain(address string){ 5 | //fmt.Println(data) 6 | CreateBlockChainWithGenesisBlock(address) 7 | 8 | 9 | bc:=GetBlockchainObject() 10 | defer bc.DB.Close() 11 | if bc != nil{ 12 | utxoSet:=&UTXOSet{bc} 13 | utxoSet.ResetUTXOSet() 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /day07_09_Merkle/BLC/CLI_createwallet.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | func (cli *CLI) createWallet(){ 4 | wallets:= NewWallets() 5 | wallets.CreateNewWallet() 6 | } 7 | -------------------------------------------------------------------------------- /day07_09_Merkle/BLC/CLI_getBalance.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | ) 7 | 8 | //查询余额 9 | func (cli *CLI)getBalance(address string){ 10 | fmt.Println("查询余额:",address) 11 | bc := GetBlockchainObject() 12 | 13 | if bc == nil{ 14 | fmt.Println("数据库不存在,无法查询。。") 15 | os.Exit(1) 16 | } 17 | defer bc.DB.Close() 18 | //txOutputs:= bc.UnUTXOs(address) 19 | //for i,out:=range txOutputs{ 20 | // fmt.Println(i,"---->",out) 21 | //} 22 | //balance:=bc.GetBalance(address,[]*Transaction{}) 23 | utxoSet:=&UTXOSet{bc} 24 | balance:= utxoSet.GetBalance(address) 25 | fmt.Printf("%s,一共有%d个Token\n",address,balance) 26 | } 27 | -------------------------------------------------------------------------------- /day07_09_Merkle/BLC/CLI_printChains.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | ) 7 | 8 | func (cli *CLI)printChains(){ 9 | bc:=GetBlockchainObject() 10 | if bc == nil{ 11 | fmt.Println("没有区块可以打印。。") 12 | os.Exit(1) 13 | } 14 | defer bc.DB.Close() 15 | bc.PrintChains() 16 | } -------------------------------------------------------------------------------- /day07_09_Merkle/BLC/CLI_send.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | ) 7 | 8 | //转账 9 | func (cli *CLI) send(from, to, amount [] string) { 10 | if !dbExists() { 11 | fmt.Println("数据库不存在。。。") 12 | os.Exit(1) 13 | } 14 | blockchain := GetBlockchainObject() 15 | 16 | blockchain.MineNewBlock(from, to, amount) 17 | defer blockchain.DB.Close() 18 | 19 | utxoSet:=&UTXOSet{blockchain} 20 | //转账成功以后,需要更新 21 | //utxoSet.ResetUTXOSet() 22 | utxoSet.Update() 23 | } 24 | -------------------------------------------------------------------------------- /day07_09_Merkle/BLC/CLI_testmethod.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import "fmt" 4 | 5 | func (cli *CLI) TestMethod(){ 6 | blockchain:=GetBlockchainObject() 7 | //defer blockchain.DB.Close() 8 | 9 | unSpentOutputMap:=blockchain.FindUnSpentOutputMap() 10 | fmt.Println(unSpentOutputMap) 11 | for key,value:=range unSpentOutputMap{ 12 | fmt.Println(key) 13 | for _,utxo:=range value.UTXOS{ 14 | fmt.Println("金额:",utxo.Output.Value) 15 | fmt.Printf("地址:%v\n",utxo.Output.PubKeyHash) 16 | fmt.Println("---------------------") 17 | } 18 | } 19 | 20 | utxoSet:=&UTXOSet{blockchain} 21 | utxoSet.ResetUTXOSet() 22 | } 23 | 24 | 25 | -------------------------------------------------------------------------------- /day07_09_Merkle/BLC/Constant.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | const DBNAME = "blockchain.db" //数据库名 4 | const BLOCKTABLENAME = "blocks" //表名 5 | 6 | 7 | -------------------------------------------------------------------------------- /day07_09_Merkle/BLC/MerkleTree.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import ( 4 | "crypto/sha256" 5 | "math" 6 | ) 7 | 8 | /* 9 | 第一步:创建结构体对象,表示节点和树 10 | */ 11 | type MerkleNode struct { 12 | LeftNode *MerkleNode 13 | RightNode *MerkleNode 14 | Data []byte 15 | } 16 | 17 | type MerkleTree struct { 18 | RootNode *MerkleNode 19 | } 20 | 21 | /* 22 | 第二步:给一个左右节点,生成一个新的节点 23 | */ 24 | func NewMerkleNode(leftNode, rightNode *MerkleNode, txHash []byte) *MerkleNode { 25 | //1.创建当前的节点 26 | mNode := &MerkleNode{} 27 | 28 | //2.赋值 29 | if leftNode == nil && rightNode == nil { 30 | //mNode就是个叶子节点 31 | hash := sha256.Sum256(txHash) 32 | mNode.Data = hash[:] 33 | } else { 34 | //mNOde是非叶子节点 35 | prevHash := append(leftNode.Data, rightNode.Data...) 36 | hash := sha256.Sum256(prevHash) 37 | mNode.Data = hash[:] 38 | } 39 | mNode.LeftNode = leftNode 40 | mNode.RightNode = rightNode 41 | return mNode 42 | 43 | } 44 | 45 | /* 46 | 第三步:生成merkle 47 | */ 48 | func NewMerkleTree(txHashData [][]byte) *MerkleTree { 49 | /* 50 | Tx1,Tx2,Tx3 51 | { 52 | {tx1hash}, 53 | {tx2hash}, 54 | {tx3hash}, 55 | {tx3hash} 56 | } 57 | */ 58 | 59 | //1.创建一个数组,用于存储node节点 60 | var nodes []*MerkleNode 61 | 62 | //2.判断交易量的奇偶性 63 | if len(txHashData)%2 != 0 { 64 | //奇数,复制最后一个 65 | txHashData = append(txHashData, txHashData[len(txHashData)-1]) 66 | } 67 | //3.创建一排的叶子节点 68 | for _, datum := range txHashData { 69 | node := NewMerkleNode(nil, nil, datum) 70 | nodes = append(nodes, node) 71 | } 72 | 73 | //4.生成树其他的节点:6 74 | //for i:=0;i= len { 111 | return count 112 | } 113 | count++ 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /day07_09_Merkle/BLC/ProofOfWork.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import ( 4 | "math/big" 5 | "bytes" 6 | "crypto/sha256" 7 | "fmt" 8 | ) 9 | 10 | // 0000 0000 0000 0000 1001 0001 0000 .... 0001 11 | //256位Hash里面前面至少有16个零 12 | const TargetBit = 16 // 20 13 | 14 | type ProofOfWork struct { 15 | //要验证的区块 16 | Block *Block 17 | 18 | //大整数存储,目标哈希 19 | Target *big.Int 20 | } 21 | 22 | func NewProofOfWork(block *Block) *ProofOfWork { 23 | //1.创建一个big对象 0000000.....00001 24 | /* 25 | 0000 0001 26 | 0010 0000 27 | */ 28 | target := big.NewInt(1) 29 | 30 | //2.左移256-bits位 31 | target = target.Lsh(target, 256-TargetBit) 32 | 33 | return &ProofOfWork{block, target} 34 | } 35 | 36 | func (pow *ProofOfWork) Run() ([] byte, int64) { 37 | //1.将Block的属性拼接成字节数组 38 | //2.生成Hash 39 | //3.循环判断Hash的有效性,满足条件,跳出循环结束验证 40 | nonce := 0 41 | //var hashInt big.Int //用于存储新生成的hash 42 | hashInt := new(big.Int) 43 | var hash [32]byte 44 | for{ 45 | //获取字节数组 46 | dataBytes := pow.prepareData(nonce) 47 | //生成hash 48 | hash = sha256.Sum256(dataBytes) 49 | //fmt.Printf("%d: %x\n",nonce,hash) 50 | fmt.Printf("\r%d: %x",nonce,hash) 51 | //将hash存储到hashInt 52 | hashInt.SetBytes(hash[:]) 53 | //判断hashInt是否小于Block里的target 54 | /* 55 | Com compares x and y and returns: 56 | -1 if x < y 57 | 0 if x == y 58 | 1 if x > y 59 | */ 60 | if pow.Target.Cmp(hashInt) == 1{ 61 | break 62 | } 63 | nonce++ 64 | } 65 | fmt.Println() 66 | return hash[:], int64(nonce) 67 | } 68 | 69 | func (pow *ProofOfWork) prepareData(nonce int)[]byte{ 70 | data := bytes.Join( 71 | [][] byte{ 72 | pow.Block.PrevBlockHash, 73 | pow.Block.HashTransactions(), 74 | IntToHex(pow.Block.TimeStamp), 75 | IntToHex(int64(TargetBit)), 76 | IntToHex(int64(nonce)), 77 | IntToHex(int64(pow.Block.Height)), 78 | }, 79 | [] byte{}, 80 | ) 81 | return data 82 | } 83 | -------------------------------------------------------------------------------- /day07_09_Merkle/BLC/Transaction_TxInput.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import "bytes" 4 | 5 | type TXInput struct { 6 | //1.交易的ID 7 | TxID [] byte 8 | //2.存储Txoutput的vout里面的索引 9 | Vout int 10 | //3.用户名 11 | //ScriptSiq string 12 | Signature [] byte //数字签名 13 | PublicKey [] byte //公钥,钱包里面 14 | } 15 | 16 | //判断当前txInput消费,和指定的address是否一致 17 | func (txInput *TXInput) UnLockWithAddress(pubKeyHash []byte) bool{ 18 | //return txInput.ScriptSiq == address 19 | publicKey:=PubKeyHash(txInput.PublicKey) 20 | return bytes.Compare(pubKeyHash,publicKey) == 0 21 | } 22 | 23 | 24 | -------------------------------------------------------------------------------- /day07_09_Merkle/BLC/Transaction_TxOutput.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import "bytes" 4 | 5 | //交易的输出,就是币实际存储的地方 6 | type TXOuput struct { 7 | Value int64 8 | //一个锁定脚本(ScriptPubKey),要花这笔钱,必须要解锁该脚本。 9 | //ScriptPubKey string //公钥:先理解为,用户名 10 | PubKeyHash [] byte // 公钥 11 | } 12 | 13 | //判断当前txOutput消费,和指定的address是否一致 14 | func (txOutput *TXOuput) UnLockWithAddress(address string) bool { 15 | //return txOutput.ScriptPubKey == address 16 | fullPayloadHash := Base58Decode([]byte(address)) 17 | pubKeyHash := fullPayloadHash[1:len(fullPayloadHash)-4] 18 | return bytes.Compare(txOutput.PubKeyHash, pubKeyHash) == 0 19 | } 20 | 21 | 22 | func NewTXOuput(value int64,address string) *TXOuput{ 23 | txOutput := &TXOuput{value, nil} 24 | //设置Ripemd160Hash 25 | txOutput.Lock(address) 26 | return txOutput 27 | } 28 | 29 | func (txOutput *TXOuput) Lock(address string) { 30 | publicKeyHash := Base58Decode([] byte(address)) 31 | txOutput.PubKeyHash = publicKeyHash[1:len(publicKeyHash)-4] 32 | } -------------------------------------------------------------------------------- /day07_09_Merkle/BLC/Transaction_UTXO.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | //step1:创建一个结构体UTXO,用于表示所有未花费的 4 | type UTXO struct { 5 | TxID [] byte //当前Transaction的交易ID 6 | Index int //下标索引 7 | Output *TXOuput // 8 | } 9 | -------------------------------------------------------------------------------- /day07_09_Merkle/BLC/TxOutputs.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import ( 4 | "bytes" 5 | "encoding/gob" 6 | "log" 7 | ) 8 | 9 | type TxOutputs struct { 10 | UTXOS []*UTXO 11 | } 12 | 13 | 14 | //序列化 15 | func (outs *TxOutputs) Serilalize()[]byte{ 16 | //1.创建一个buffer 17 | var result bytes.Buffer 18 | //2.创建一个编码器 19 | encoder := gob.NewEncoder(&result) 20 | //3.编码--->打包 21 | err := encoder.Encode(outs) 22 | if err != nil { 23 | log.Panic(err) 24 | } 25 | return result.Bytes() 26 | } 27 | 28 | //反序列化 29 | func DeserializeTXOutputs(txOutputsBytes [] byte) *TxOutputs { 30 | var txOutputs TxOutputs 31 | var reader = bytes.NewReader(txOutputsBytes) 32 | //1.创建一个解码器 33 | decoder := gob.NewDecoder(reader) 34 | //解包 35 | err := decoder.Decode(&txOutputs) 36 | if err != nil { 37 | log.Panic(err) 38 | } 39 | return &txOutputs 40 | } 41 | -------------------------------------------------------------------------------- /day07_09_Merkle/BLC/Wallet.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import ( 4 | "crypto/ecdsa" 5 | "crypto/elliptic" 6 | "crypto/rand" 7 | "log" 8 | "crypto/sha256" 9 | "golang.org/x/crypto/ripemd160" 10 | "bytes" 11 | ) 12 | 13 | //step1:创建一个钱包 14 | type Wallet struct { 15 | //1.私钥 16 | PrivateKey ecdsa.PrivateKey 17 | //2.公钥 18 | PublicKey [] byte 19 | } 20 | 21 | //step2:产生一对密钥 22 | func newKeyPair() (ecdsa.PrivateKey, []byte) { 23 | /* 24 | 1.通过椭圆曲线算法,随机产生私钥 25 | 2.根据私钥生成公钥 26 | 27 | elliptic:椭圆 28 | curve:曲线 29 | ecc:椭圆曲线加密 30 | ecdsa:elliptic curve digital signature algorithm,椭圆曲线数字签名算法 31 | 比特币使用SECP256K1算法,p256是ecdsa算法中的一种 32 | 33 | */ 34 | //椭圆加密 35 | curve := elliptic.P256() //椭圆加密算法,得到一个椭圆曲线值,全称:SECP256k1 36 | private, err := ecdsa.GenerateKey(curve, rand.Reader) 37 | if err != nil { 38 | log.Panic(err) 39 | } 40 | //生成公钥 41 | pubKey := append(private.PublicKey.X.Bytes(), private.PublicKey.Y.Bytes()...) 42 | return *private, pubKey 43 | } 44 | 45 | //step3:提供一个方法用于获取钱包 46 | func NewWallet() *Wallet { 47 | privateKey, publicKey := newKeyPair() 48 | //fmt.Println("privateKey:", privateKey, ",publicKey:", publicKey) 49 | return &Wallet{privateKey, publicKey} 50 | } 51 | 52 | //step4:根据一个公钥获取对应的地址 53 | /* 54 | 将公钥sha2561次,再160,1次 55 | 然后version+hash 56 | */ 57 | func (w *Wallet) GetAddress() [] byte { 58 | //1.先将公钥进行一次hash256,一次160,得到pubKeyHash 59 | pubKeyHash := PubKeyHash(w.PublicKey) 60 | //2.添加版本号 61 | versioned_payload := append([]byte{version}, pubKeyHash...) 62 | // 3.获取校验和,将pubKeyhash,两次sha256后,取前4位 63 | checkSumBytes := CheckSum(versioned_payload) 64 | full_payload := append(versioned_payload, checkSumBytes...) 65 | //fmt.Println(len(full_payload)) 66 | //4.Base58 67 | address := Base58Encode(full_payload) 68 | return address 69 | 70 | } 71 | 72 | //一次sha256,再一次ripemd160,得到publicKeyHash 73 | func PubKeyHash(publicKey [] byte) []byte { 74 | //1.sha256 75 | hasher := sha256.New() 76 | hasher.Write(publicKey) 77 | hash := hasher.Sum(nil) 78 | 79 | //2.ripemd160 80 | ripemder := ripemd160.New() 81 | ripemder.Write(hash) 82 | pubKeyHash := ripemder.Sum(nil) 83 | 84 | //返回 85 | return pubKeyHash 86 | } 87 | 88 | const version = byte(0x00) 89 | const addressChecksumLen = 4 90 | 91 | //获取验证码:将公钥哈希两次sha256,取前4位,就是校验和 92 | func CheckSum(payload []byte) []byte { 93 | firstSHA := sha256.Sum256(payload) 94 | secondSHA := sha256.Sum256(firstSHA[:]) 95 | return secondSHA[:addressChecksumLen] 96 | } 97 | 98 | 99 | 100 | //判断地址是否有效 101 | /* 102 | 根据地址,base58解码后获取byte[],获取校验和数组 103 | 使用 104 | */ 105 | func IsValidForAddress(address []byte) bool { 106 | full_payload := Base58Decode(address) 107 | //fmt.Println("检验version_public_checksumBytes:",full_payload) 108 | checkSumBytes := full_payload[len(full_payload)-addressChecksumLen:] 109 | //fmt.Println("检验checkSumBytes:",checkSumBytes) 110 | versioned_payload := full_payload[:len(full_payload)-addressChecksumLen] 111 | //fmt.Println("检验version_ripemd160:",versioned_payload) 112 | checkBytes := CheckSum(versioned_payload) 113 | //fmt.Println("检验checkBytes:",checkBytes) 114 | if bytes.Compare(checkSumBytes, checkBytes) == 0 { 115 | return true 116 | } 117 | return false 118 | } -------------------------------------------------------------------------------- /day07_09_Merkle/BLC/Wallets.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "io/ioutil" 7 | "log" 8 | "encoding/gob" 9 | "crypto/elliptic" 10 | "bytes" 11 | ) 12 | 13 | //1.创建钱包 14 | type Wallets struct { 15 | WalletsMap map[string]*Wallet 16 | } 17 | 18 | //2.创建一个钱包集合 19 | //创建钱包集合:文件中存在从文件中读取,否则新建一个 20 | const walletFile = "Wallets.dat" 21 | 22 | func NewWallets() *Wallets { 23 | //wallets := &WalletsMap{} 24 | //wallets.WalletsMap = make(map[string]*Wallet) 25 | //return wallets 26 | //1.判断钱包文件是否存在 27 | if _, err := os.Stat(walletFile); os.IsNotExist(err) { 28 | fmt.Println("文件不存在") 29 | wallets := &Wallets{} 30 | wallets.WalletsMap = make(map[string]*Wallet) 31 | return wallets 32 | } 33 | //2.否则读取文件中的数据 34 | fileContent, err := ioutil.ReadFile(walletFile) 35 | if err != nil { 36 | log.Panic(err) 37 | } 38 | var wallets Wallets 39 | gob.Register(elliptic.P256()) 40 | decoder := gob.NewDecoder(bytes.NewReader(fileContent)) 41 | err = decoder.Decode(&wallets) 42 | if err != nil { 43 | log.Panic(err) 44 | } 45 | return &wallets 46 | } 47 | 48 | //3.创建一个新钱包 49 | func (ws *Wallets) CreateNewWallet() { 50 | wallet := NewWallet() 51 | fmt.Printf("创建钱包地址:%s\n", wallet.GetAddress()) 52 | ws.WalletsMap[string(wallet.GetAddress())] = wallet 53 | 54 | //将钱包保存 55 | ws.SaveWallets() 56 | } 57 | 58 | /* 59 | 要让数据对象能在网络上传输或存储,我们需要进行编码和解码。现在比较流行的编码方式有JSON,XML等。然而,Go在gob包中为我们提供了另一种方式,该方式编解码效率高于JSON。 60 | gob是Golang包自带的一个数据结构序列化的编码/解码工具 61 | */ 62 | func (ws *Wallets) SaveWallets() { 63 | var content bytes.Buffer 64 | //注册的目的,为了可以序列化任何类型,wallet结构体中有接口类型。将接口进行注册 65 | gob.Register(elliptic.P256()) //gob是Golang包自带的一个数据结构序列化的编码/解码工具 66 | encoder := gob.NewEncoder(&content) 67 | err := encoder.Encode(ws) 68 | if err != nil { 69 | log.Panic(err) 70 | } 71 | //将序列化后的数据写入到文件,原来的文件中的内容会被覆盖掉 72 | err = ioutil.WriteFile(walletFile, content.Bytes(), 0644) 73 | if err != nil { 74 | log.Panic(err) 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /day07_09_Merkle/BLC/base58.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | import ( 3 | "math/big" 4 | "bytes" 5 | ) 6 | 7 | //base64 8 | 9 | /* 10 | ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/ 11 | 0(零),O(大写的o),I(大写的i),l(小写的L),+,/ 12 | */ 13 | 14 | var b58Alphabet = []byte("123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz") 15 | 16 | //字节数组转Base58,加密 17 | func Base58Encode(input []byte)[]byte{ 18 | var result [] byte 19 | x := big.NewInt(0).SetBytes(input) 20 | 21 | base :=big.NewInt(int64(len(b58Alphabet))) 22 | zero:=big.NewInt(0) 23 | mod:= &big.Int{} 24 | for x.Cmp(zero) !=0{ 25 | x.DivMod(x,base,mod) 26 | result = append(result,b58Alphabet[mod.Int64()]) 27 | } 28 | ReverseBytes(result) 29 | for b:=range input{ 30 | if b == 0x00{ 31 | result = append([]byte{b58Alphabet[0]},result...) 32 | }else { 33 | break 34 | } 35 | } 36 | 37 | return result 38 | 39 | } 40 | 41 | //Base58转字节数组,解密 42 | func Base58Decode(input[] byte)[]byte{ 43 | result:=big.NewInt(0) 44 | zeroBytes := 0 45 | for b:=range input{ 46 | if b == 0x00{ 47 | zeroBytes++ 48 | } 49 | } 50 | payload := input[zeroBytes:] 51 | for _, b := range payload { 52 | charIndex := bytes.IndexByte(b58Alphabet, b) 53 | result.Mul(result, big.NewInt(58)) 54 | result.Add(result, big.NewInt(int64(charIndex))) 55 | } 56 | 57 | decoded := result.Bytes() 58 | decoded = append(bytes.Repeat([]byte{byte(0x00)}, zeroBytes), decoded...) 59 | 60 | return decoded 61 | } 62 | 63 | 64 | -------------------------------------------------------------------------------- /day07_09_Merkle/BLC/utils.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import ( 4 | "bytes" 5 | "encoding/binary" 6 | "log" 7 | "encoding/json" 8 | ) 9 | 10 | /* 11 | 将一个int64的整数:转为二进制后,每8bit一个byte。转为[]byte 12 | */ 13 | func IntToHex(num int64) []byte { 14 | buff := new(bytes.Buffer) 15 | //将二进制数据写入w 16 | //func Write(w io.Writer, order ByteOrder, data interface{}) error 17 | err := binary.Write(buff, binary.BigEndian, num) 18 | if err != nil { 19 | log.Panic(err) 20 | } 21 | //转为[]byte并返回 22 | return buff.Bytes() 23 | } 24 | 25 | /* 26 | Json字符串转为[] string数组 27 | */ 28 | func JSONToArray (jsonString string) [] string{ 29 | var sArr [] string 30 | if err := json.Unmarshal([]byte(jsonString),&sArr);err != nil{ 31 | log.Panic(err) 32 | } 33 | return sArr 34 | } 35 | 36 | 37 | //字节数组反转 38 | func ReverseBytes(data []byte) { 39 | for i, j := 0, len(data)-1; i < j; i, j = i+1, j-1 { 40 | data[i], data[j] = data[j], data[i] 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /day07_09_Merkle/Wallets.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rubyhan1314/PublicChain/fd8b04084c29fe82efe813a0c30864ed1df00383/day07_09_Merkle/Wallets.dat -------------------------------------------------------------------------------- /day07_09_Merkle/bc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rubyhan1314/PublicChain/fd8b04084c29fe82efe813a0c30864ed1df00383/day07_09_Merkle/bc -------------------------------------------------------------------------------- /day07_09_Merkle/blockchain.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rubyhan1314/PublicChain/fd8b04084c29fe82efe813a0c30864ed1df00383/day07_09_Merkle/blockchain.db -------------------------------------------------------------------------------- /day07_09_Merkle/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "./BLC" 5 | ) 6 | 7 | func main() { 8 | //1.测试Block 9 | //block:=BLC.NewBlock("I am a block",make([]byte,32,32),1) 10 | //fmt.Println(block) 11 | //2.测试创世区块 12 | //genesisBlock :=BLC.CreateGenesisBlock("Genesis Block..") 13 | //fmt.Println(genesisBlock) 14 | 15 | //3.测试区块链 16 | //genesisBlockChain := BLC.CreateBlockChainWithGenesisBlock() 17 | //fmt.Println(genesisBlockChain) 18 | //fmt.Println(genesisBlockChain.Blocks) 19 | //fmt.Println(genesisBlockChain.Blocks[0]) 20 | 21 | //4.测试添加新区块 22 | //blockChain:=BLC.CreateBlockChainWithGenesisBlock() 23 | //blockChain.AddBlockToBlockChain("Send 100RMB To Wangergou",blockChain.Blocks[len(blockChain.Blocks)-1].Height+1,blockChain.Blocks[len(blockChain.Blocks)-1].Hash) 24 | //blockChain.AddBlockToBlockChain("Send 300RMB To lixiaohua",blockChain.Blocks[len(blockChain.Blocks)-1].Height+1,blockChain.Blocks[len(blockChain.Blocks)-1].Hash) 25 | //blockChain.AddBlockToBlockChain("Send 500RMB To rose",blockChain.Blocks[len(blockChain.Blocks)-1].Height+1,blockChain.Blocks[len(blockChain.Blocks)-1].Hash) 26 | // 27 | //fmt.Println(blockChain) 28 | 29 | //5.测试序列化和反序列化 30 | //block:=BLC.NewBlock("helloworld",make([]byte,32,32),0) 31 | //data:=block.Serilalize() 32 | //fmt.Println(block) 33 | //fmt.Println(data) 34 | //block2:=BLC.DeserializeBlock(data) 35 | //fmt.Println(block2) 36 | 37 | //6.创建区块,存入数据库 38 | //打开数据库 39 | //block:=BLC.NewBlock("helloworld",make([]byte,32,32),0) 40 | //db,err := bolt.Open("my.db",0600,nil) 41 | //if err != nil{ 42 | // log.Fatal(err) 43 | //} 44 | // 45 | //defer db.Close() 46 | // 47 | //err = db.Update(func(tx *bolt.Tx) error { 48 | // //获取bucket,没有就创建新表 49 | // b := tx.Bucket([]byte("blocks")) 50 | // if b == nil{ 51 | // b,err = tx.CreateBucket([] byte("blocks")) 52 | // if err !=nil{ 53 | // log.Panic("创建表失败") 54 | // } 55 | // } 56 | // //添加数据 57 | // err = b.Put([]byte("l"),block.Serilalize()) 58 | // if err !=nil{ 59 | // log.Panic(err) 60 | // } 61 | // 62 | // return nil 63 | //}) 64 | //if err != nil{ 65 | // log.Panic(err) 66 | //} 67 | //err = db.View(func(tx *bolt.Tx) error { 68 | // b := tx.Bucket([]byte("blocks")) 69 | // if b !=nil{ 70 | // data := b.Get([]byte("l")) 71 | // //fmt.Printf("%s\n",data)//直接打印会乱码 72 | // //反序列化 73 | // block2:=BLC.DeserializeBlock(data) 74 | // //fmt.Println(block2) 75 | // fmt.Printf("%v\n",block2) 76 | // 77 | // } 78 | // return nil 79 | //}) 80 | 81 | //7.测试创世区块存入数据库 82 | //blockchain:=BLC.CreateBlockChainWithGenesisBlock("Genesis Block..") 83 | //fmt.Println(blockchain) 84 | //defer blockchain.DB.Close() 85 | //8.测试新添加的区块 86 | //blockchain.AddBlockToBlockChain("Send 100RMB to wangergou") 87 | //blockchain.AddBlockToBlockChain("Send 100RMB to lixiaohua") 88 | //blockchain.AddBlockToBlockChain("Send 100RMB to rose") 89 | //fmt.Println(blockchain) 90 | //blockchain.PrintChains() 91 | 92 | //9.CLI操作 93 | cli:=BLC.CLI{} 94 | cli.Run() 95 | 96 | //outsMap := make(map[string]*BLC.TxOutputs) 97 | //outputs:=outsMap["aa"] 98 | //fmt.Println(outputs) 99 | //fmt.Println(len(outputs.UTXOS)) 100 | 101 | 102 | } -------------------------------------------------------------------------------- /day08_10_Net/BLC/Block.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import ( 4 | "time" 5 | "bytes" 6 | "encoding/gob" 7 | "log" 8 | ) 9 | //step2:修改Block的交易类型 10 | type Block struct { 11 | //字段: 12 | //高度Height:其实就是区块的编号,第一个区块叫创世区块,高度为0 13 | Height int64 14 | //上一个区块的哈希值ProvHash: 15 | PrevBlockHash []byte 16 | //交易数据Data:目前先设计为[]byte,后期是Transaction 17 | //Data [] byte 18 | Txs [] *Transaction 19 | //时间戳TimeStamp: 20 | TimeStamp int64 21 | //哈希值Hash:32个的字节,64个16进制数 22 | Hash []byte 23 | 24 | Nonce int64 25 | } 26 | 27 | func NewBlock(txs []*Transaction,provBlockHash []byte,height int64) *Block{ 28 | //创建区块 29 | block:=&Block{height,provBlockHash,txs,time.Now().Unix(),nil,0} 30 | //step5:设置block的hash和nonce 31 | //设置哈希 32 | //block.SetHash() 33 | //调用工作量证明的方法,并且返回有效的Hash和Nonce 34 | pow:=NewProofOfWork(block) 35 | hash,nonce:=pow.Run() 36 | block.Hash = hash 37 | block.Nonce = nonce 38 | 39 | 40 | return block 41 | } 42 | 43 | func CreateGenesisBlock(txs []*Transaction) *Block{ 44 | return NewBlock(txs,make([] byte,32,32),0) 45 | } 46 | 47 | //将区块序列化,得到一个字节数组---区块的行为,设计为方法 48 | func (block *Block) Serilalize() []byte { 49 | //1.创建一个buffer 50 | var result bytes.Buffer 51 | //2.创建一个编码器 52 | encoder := gob.NewEncoder(&result) 53 | //3.编码--->打包 54 | err := encoder.Encode(block) 55 | if err != nil { 56 | log.Panic(err) 57 | } 58 | return result.Bytes() 59 | } 60 | 61 | //反序列化,得到一个区块---设计为函数 62 | func DeserializeBlock(blockBytes [] byte) *Block { 63 | var block Block 64 | var reader = bytes.NewReader(blockBytes) 65 | //1.创建一个解码器 66 | decoder := gob.NewDecoder(reader) 67 | //解包 68 | err := decoder.Decode(&block) 69 | if err != nil { 70 | log.Panic(err) 71 | } 72 | return &block 73 | } 74 | 75 | //step4:新增方法 76 | //将Txs转为[]byte 77 | func (block *Block) HashTransactions()[]byte{ 78 | //var txHashes [][] byte 79 | //var txHash [32]byte 80 | //for _,tx :=range block.Txs{ 81 | // txHashes = append(txHashes,tx.TxID) 82 | //} 83 | // 84 | //txHash = sha256.Sum256(bytes.Join(txHashes,[]byte{})) 85 | //return txHash[:] 86 | 87 | var txs [][] byte 88 | for _,tx:=range block.Txs{ 89 | txs = append(txs, tx.Serialize()) 90 | } 91 | mTree:=NewMerkleTree(txs) 92 | return mTree.RootNode.Data 93 | 94 | 95 | } 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | -------------------------------------------------------------------------------- /day08_10_Net/BLC/BlockChainIterator.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import ( 4 | "github.com/boltdb/bolt" 5 | "log" 6 | ) 7 | 8 | //1.新增一个结构体 9 | type BlockChainIterator struct { 10 | CurrentHash [] byte //当前区块的hash 11 | DB *bolt.DB //数据库 12 | } 13 | 14 | 15 | 16 | 17 | //3.获取区块 18 | func (bcIterator *BlockChainIterator) Next() *Block { 19 | block:=new(Block) 20 | //1.打开数据库并读取 21 | err :=bcIterator.DB.View(func(tx *bolt.Tx) error { 22 | //2.打开数据表 23 | b:=tx.Bucket([]byte(BLOCKTABLENAME)) 24 | if b != nil{ 25 | //3.根据当前hash获取数据并反序列化 26 | blockBytes:=b.Get(bcIterator.CurrentHash) 27 | block = DeserializeBlock(blockBytes) 28 | //4.更新当前的hash 29 | bcIterator.CurrentHash = block.PrevBlockHash 30 | } 31 | 32 | return nil 33 | }) 34 | if err != nil{ 35 | log.Panic(err) 36 | } 37 | return block 38 | } 39 | 40 | 41 | -------------------------------------------------------------------------------- /day08_10_Net/BLC/CLI.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import ( 4 | "os" 5 | "fmt" 6 | "flag" 7 | "log" 8 | ) 9 | 10 | //step1: 11 | //CLI结构体 12 | type CLI struct { 13 | //Blockchain *BlockChain 14 | } 15 | 16 | //step2:添加Run方法 17 | func (cli *CLI) Run() { 18 | //判断命令行参数的长度 19 | isValidArgs() 20 | 21 | /* 22 | 获取节点ID 23 | 解释:返回当前进程的环境变量varname的值,若变量没有定义时返回nil 24 | export NODE_ID=8888 25 | 26 | 每次打开一个终端,都需要设置NODE_ID的值。 27 | 变量名NODE_ID,可以更改别的。 28 | */ 29 | 30 | nodeID :=os.Getenv("NODE_ID") 31 | if nodeID == ""{ 32 | fmt.Printf("NODE_ID 环境变量没有设置。。\n") 33 | os.Exit(1) 34 | } 35 | fmt.Printf("NODE_ID:%s\n",nodeID) 36 | 37 | 38 | //1.创建flagset标签对象 39 | createWalletCmd := flag.NewFlagSet("createwallet", flag.ExitOnError) 40 | addressListsCmd := flag.NewFlagSet("addresslists",flag.ExitOnError) 41 | 42 | sendBlockCmd := flag.NewFlagSet("send", flag.ExitOnError) 43 | //fmt.Printf("%T\n",addBlockCmd) //*FlagSet 44 | printChainCmd := flag.NewFlagSet("printchain", flag.ExitOnError) 45 | createBlockChainCmd := flag.NewFlagSet("createblockchain", flag.ExitOnError) 46 | getBalanceCmd := flag.NewFlagSet("getbalance", flag.ExitOnError) 47 | 48 | testCmd:=flag.NewFlagSet("test",flag.ExitOnError) 49 | 50 | startNodeCmd := flag.NewFlagSet("startnode",flag.ExitOnError) 51 | 52 | //2.设置标签后的参数 53 | //flagAddBlockData:= addBlockCmd.String("data","helloworld..","交易数据") 54 | flagFromData := sendBlockCmd.String("from", "", "转帐源地址") 55 | flagToData := sendBlockCmd.String("to", "", "转帐目标地址") 56 | flagAmountData := sendBlockCmd.String("amount", "", "转帐金额") 57 | flagCreateBlockChainData := createBlockChainCmd.String("address", "", "创世区块交易地址") 58 | flagGetBalanceData := getBalanceCmd.String("address", "", "要查询的某个账户的余额") 59 | 60 | 61 | 62 | flagMiner := startNodeCmd.String("miner","","定义挖矿奖励的地址......") 63 | flagMine := sendBlockCmd.Bool("mine",false,"是否在当前节点中立即验证....") 64 | 65 | 66 | //3.解析 67 | switch os.Args[1] { 68 | case "send": 69 | err := sendBlockCmd.Parse(os.Args[2:]) 70 | if err != nil { 71 | log.Panic(err) 72 | } 73 | //fmt.Println("----",os.Args[2:]) 74 | 75 | case "printchain": 76 | err := printChainCmd.Parse(os.Args[2:]) 77 | if err != nil { 78 | log.Panic(err) 79 | } 80 | //fmt.Println("====",os.Args[2:]) 81 | 82 | case "createblockchain": 83 | err := createBlockChainCmd.Parse(os.Args[2:]) 84 | if err != nil { 85 | log.Panic(err) 86 | } 87 | case "getbalance": 88 | err := getBalanceCmd.Parse(os.Args[2:]) 89 | if err != nil { 90 | log.Panic(err) 91 | } 92 | 93 | case "createwallet": 94 | err := createWalletCmd.Parse(os.Args[2:]) 95 | if err != nil { 96 | log.Panic(err) 97 | } 98 | case "addresslists": 99 | err := addressListsCmd.Parse(os.Args[2:]) 100 | if err != nil { 101 | log.Panic(err) 102 | } 103 | case "test": 104 | err := testCmd.Parse(os.Args[2:]) 105 | if err != nil { 106 | log.Panic(err) 107 | } 108 | 109 | case "startnode": 110 | err := startNodeCmd.Parse(os.Args[2:]) 111 | if err != nil { 112 | log.Panic(err) 113 | } 114 | 115 | default: 116 | printUsage() 117 | os.Exit(1) //退出 118 | } 119 | 120 | if sendBlockCmd.Parsed() { 121 | if *flagFromData == "" || *flagToData == "" || *flagAmountData == "" { 122 | printUsage() 123 | os.Exit(1) 124 | } 125 | //cli.addBlock([]*Transaction{}) 126 | //fmt.Println(*flagFromData) 127 | //fmt.Println(*flagToData) 128 | //fmt.Println(*flagAmountData) 129 | //fmt.Println(JSONToArray(*flagFrom)) 130 | //fmt.Println(JSONToArray(*flagTo)) 131 | //fmt.Println(JSONToArray(*flagAmount)) 132 | from := JSONToArray(*flagFromData) 133 | to := JSONToArray(*flagToData) 134 | amount := JSONToArray(*flagAmountData) 135 | 136 | for i := 0; i < len(from); i++ { 137 | if !IsValidForAddress([]byte(from[i])) || !IsValidForAddress([]byte(to[i])) { 138 | fmt.Println("钱包地址无效") 139 | printUsage() 140 | os.Exit(1) 141 | } 142 | } 143 | 144 | cli.send(from, to, amount,nodeID,*flagMine) 145 | } 146 | if printChainCmd.Parsed() { 147 | cli.printChains(nodeID) 148 | } 149 | 150 | if createBlockChainCmd.Parsed() { 151 | //if *flagCreateBlockChainData == "" { 152 | if !IsValidForAddress([]byte(*flagCreateBlockChainData)){ 153 | fmt.Println("创建地址无效") 154 | printUsage() 155 | os.Exit(1) 156 | } 157 | cli.createGenesisBlockchain(*flagCreateBlockChainData,nodeID) 158 | } 159 | 160 | if getBalanceCmd.Parsed() { 161 | //if *flagGetBalanceData == "" { 162 | if !IsValidForAddress([]byte(*flagGetBalanceData)){ 163 | fmt.Println("查询地址无效") 164 | printUsage() 165 | os.Exit(1) 166 | } 167 | cli.getBalance(*flagGetBalanceData,nodeID) 168 | 169 | } 170 | 171 | if createWalletCmd.Parsed() { 172 | //创建钱包 173 | cli.createWallet(nodeID) 174 | } 175 | 176 | //获取所有的钱包地址 177 | if addressListsCmd.Parsed(){ 178 | cli.addressLists(nodeID) 179 | } 180 | 181 | if testCmd.Parsed(){ 182 | cli.TestMethod(nodeID) 183 | } 184 | 185 | if startNodeCmd.Parsed() { 186 | cli.startNode(nodeID,*flagMiner) 187 | } 188 | 189 | } 190 | 191 | func isValidArgs() { 192 | if len(os.Args) < 2 { 193 | printUsage() 194 | os.Exit(1) 195 | } 196 | } 197 | func printUsage() { 198 | fmt.Println("Usage:") 199 | fmt.Println("\tcreatewallet -- 创建钱包") 200 | fmt.Println("\taddresslists -- 输出所有钱包地址") 201 | fmt.Println("\tcreateblockchain -address DATA -- 创建创世区块") 202 | fmt.Println("\tsend -from FROM -to TO -amount AMOUNT -mine -- 交易明细.") 203 | fmt.Println("\tprintchain - 输出信息:") 204 | fmt.Println("\tgetbalance -address DATA -- 查询账户余额") 205 | fmt.Println("\ttest -- 测试") 206 | fmt.Println("\tstartnode -miner ADDRESS -- 启动节点服务器,并且指定挖矿奖励的地址.") 207 | } 208 | -------------------------------------------------------------------------------- /day08_10_Net/BLC/CLI_addresslists.go: -------------------------------------------------------------------------------- 1 | 2 | package BLC 3 | 4 | import "fmt" 5 | 6 | func (cli *CLI)addressLists(nodeID string){ 7 | fmt.Println("打印所有的钱包地址。。") 8 | //获取 9 | Wallets:=NewWallets(nodeID) 10 | for address,_ := range Wallets.WalletsMap{ 11 | fmt.Println("address:",address) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /day08_10_Net/BLC/CLI_createBlockChain.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | 4 | func (cli *CLI) createGenesisBlockchain(address string,nodeID string){ 5 | //fmt.Println(data) 6 | CreateBlockChainWithGenesisBlock(address,nodeID) 7 | 8 | 9 | bc:=GetBlockchainObject(nodeID) 10 | defer bc.DB.Close() 11 | if bc != nil{ 12 | utxoSet:=&UTXOSet{bc} 13 | utxoSet.ResetUTXOSet() 14 | } 15 | 16 | } 17 | 18 | 19 | -------------------------------------------------------------------------------- /day08_10_Net/BLC/CLI_createwallet.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | func (cli *CLI) createWallet(nodeID string){ 4 | wallets:= NewWallets(nodeID) 5 | wallets.CreateNewWallet(nodeID) 6 | } 7 | 8 | -------------------------------------------------------------------------------- /day08_10_Net/BLC/CLI_getBalance.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | ) 7 | 8 | 9 | //查询余额 10 | func (cli *CLI)getBalance(address string,nodeID string){ 11 | fmt.Println("查询余额:",address) 12 | bc := GetBlockchainObject(nodeID) 13 | 14 | if bc == nil{ 15 | fmt.Println("数据库不存在,无法查询。。") 16 | os.Exit(1) 17 | } 18 | defer bc.DB.Close() 19 | //txOutputs:= bc.UnUTXOs(address) 20 | //for i,out:=range txOutputs{ 21 | // fmt.Println(i,"---->",out) 22 | //} 23 | //balance:=bc.GetBalance(address,[]*Transaction{}) 24 | utxoSet:=&UTXOSet{bc} 25 | balance:= utxoSet.GetBalance(address) 26 | fmt.Printf("%s,一共有%d个Token\n",address,balance) 27 | } 28 | -------------------------------------------------------------------------------- /day08_10_Net/BLC/CLI_printChains.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | ) 7 | 8 | 9 | 10 | func (cli *CLI)printChains(nodeID string){ 11 | bc:=GetBlockchainObject(nodeID) 12 | if bc == nil{ 13 | fmt.Println("没有区块可以打印。。") 14 | os.Exit(1) 15 | } 16 | defer bc.DB.Close() 17 | bc.PrintChains() 18 | } -------------------------------------------------------------------------------- /day08_10_Net/BLC/CLI_send.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import ( 4 | "strconv" 5 | "fmt" 6 | ) 7 | 8 | 9 | // 转账 10 | func (cli *CLI) send(from []string, to []string, amount []string, nodeID string, mineNow bool) { 11 | 12 | blockchain := GetBlockchainObject(nodeID) 13 | utxoSet := &UTXOSet{blockchain} 14 | defer blockchain.DB.Close() 15 | 16 | if mineNow { 17 | blockchain.MineNewBlock(from, to, amount, nodeID) 18 | 19 | //转账成功以后,需要更新一下 20 | utxoSet.Update() 21 | } else { 22 | // 把交易发送到矿工节点去进行验证 23 | fmt.Println("由矿工节点处理......") 24 | value, _ := strconv.Atoi(amount[0]) 25 | tx := NewSimpleTransaction(from[0], to[0], int64(value), utxoSet, []*Transaction{}, nodeID) 26 | 27 | sendTx(knowNodes[0], tx) 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /day08_10_Net/BLC/CLI_startnode.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | ) 7 | 8 | func (cli *CLI) startNode(nodeID string,minerAdd string) { 9 | 10 | // 启动服务器 11 | fmt.Println(nodeID,minerAdd) 12 | 13 | if minerAdd == "" || IsValidForAddress([]byte(minerAdd)) { 14 | // 启动服务器 15 | fmt.Printf("启动服务器:localhost:%s\n",nodeID) 16 | startServer(nodeID,minerAdd) 17 | 18 | } else { 19 | 20 | fmt.Println("指定的地址无效....") 21 | os.Exit(0) 22 | } 23 | 24 | } -------------------------------------------------------------------------------- /day08_10_Net/BLC/CLI_testmethod.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import "fmt" 4 | 5 | 6 | func (cli *CLI) TestMethod(nodeID string){ 7 | blockchain:=GetBlockchainObject(nodeID) 8 | //defer blockchain.DB.Close() 9 | 10 | unSpentOutputMap:=blockchain.FindUnSpentOutputMap() 11 | fmt.Println(unSpentOutputMap) 12 | for key,value:=range unSpentOutputMap{ 13 | fmt.Println(key) 14 | for _,utxo:=range value.UTXOS{ 15 | fmt.Println("金额:",utxo.Output.Value) 16 | fmt.Printf("地址:%v\n",utxo.Output.PubKeyHash) 17 | fmt.Println("---------------------") 18 | } 19 | } 20 | 21 | utxoSet:=&UTXOSet{blockchain} 22 | utxoSet.ResetUTXOSet() 23 | } 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /day08_10_Net/BLC/Constant.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | const DBNAME = "blockchain_%s.db" //数据库名 4 | const BLOCKTABLENAME = "blocks" //表名 5 | 6 | 7 | 8 | const PROTOCOL = "tcp" 9 | const COMMANDLENGTH = 12 10 | const NODE_VERSION = 1 11 | 12 | 13 | //12个字节 + 结构体序列化的字节数组 14 | 15 | 16 | // 命令 17 | const COMMAND_VERSION = "version" 18 | const COMMAND_ADDR = "addr" 19 | const COMMAND_BLOCK = "block" 20 | const COMMAND_INV = "inv" 21 | const COMMAND_GETBLOCKS = "getblocks" 22 | const COMMAND_GETDATA = "getdata" 23 | const COMMAND_TX = "tx" 24 | 25 | // 类型 26 | const BLOCK_TYPE = "block" 27 | const TX_TYPE = "tx" -------------------------------------------------------------------------------- /day08_10_Net/BLC/MerkleTree.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import ( 4 | "crypto/sha256" 5 | "math" 6 | ) 7 | 8 | /* 9 | 第一步:创建结构体对象,表示节点和树 10 | */ 11 | type MerkleNode struct { 12 | LeftNode *MerkleNode 13 | RightNode *MerkleNode 14 | Data []byte 15 | } 16 | 17 | type MerkleTree struct { 18 | RootNode *MerkleNode 19 | } 20 | 21 | /* 22 | 第二步:给一个左右节点,生成一个新的节点 23 | */ 24 | func NewMerkleNode(leftNode, rightNode *MerkleNode, txHash []byte) *MerkleNode { 25 | //1.创建当前的节点 26 | mNode := &MerkleNode{} 27 | 28 | //2.赋值 29 | if leftNode == nil && rightNode == nil { 30 | //mNode就是个叶子节点 31 | hash := sha256.Sum256(txHash) 32 | mNode.Data = hash[:] 33 | } else { 34 | //mNOde是非叶子节点 35 | prevHash := append(leftNode.Data, rightNode.Data...) 36 | hash := sha256.Sum256(prevHash) 37 | mNode.Data = hash[:] 38 | } 39 | mNode.LeftNode = leftNode 40 | mNode.RightNode = rightNode 41 | return mNode 42 | 43 | } 44 | 45 | /* 46 | 第三步:生成merkle 47 | */ 48 | func NewMerkleTree(txHashData [][]byte) *MerkleTree { 49 | /* 50 | Tx1,Tx2,Tx3 51 | { 52 | {tx1hash}, 53 | {tx2hash}, 54 | {tx3hash}, 55 | {tx3hash} 56 | } 57 | */ 58 | 59 | //1.创建一个数组,用于存储node节点 60 | var nodes []*MerkleNode 61 | 62 | //2.判断交易量的奇偶性 63 | if len(txHashData)%2 != 0 { 64 | //奇数,复制最后一个 65 | txHashData = append(txHashData, txHashData[len(txHashData)-1]) 66 | } 67 | //3.创建一排的叶子节点 68 | for _, datum := range txHashData { 69 | node := NewMerkleNode(nil, nil, datum) 70 | nodes = append(nodes, node) 71 | } 72 | 73 | //4.生成树其他的节点:6 74 | //for i:=0;i= len { 111 | return count 112 | } 113 | count++ 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /day08_10_Net/BLC/ProofOfWork.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import ( 4 | "math/big" 5 | "bytes" 6 | "crypto/sha256" 7 | "fmt" 8 | ) 9 | 10 | // 0000 0000 0000 0000 1001 0001 0000 .... 0001 11 | //256位Hash里面前面至少有16个零 12 | const TargetBit = 16 // 20 13 | 14 | type ProofOfWork struct { 15 | //要验证的区块 16 | Block *Block 17 | 18 | //大整数存储,目标哈希 19 | Target *big.Int 20 | } 21 | 22 | func NewProofOfWork(block *Block) *ProofOfWork { 23 | //1.创建一个big对象 0000000.....00001 24 | /* 25 | 0000 0001 26 | 0010 0000 27 | */ 28 | target := big.NewInt(1) 29 | 30 | //2.左移256-bits位 31 | target = target.Lsh(target, 256-TargetBit) 32 | 33 | return &ProofOfWork{block, target} 34 | } 35 | 36 | func (pow *ProofOfWork) Run() ([] byte, int64) { 37 | //1.将Block的属性拼接成字节数组 38 | //2.生成Hash 39 | //3.循环判断Hash的有效性,满足条件,跳出循环结束验证 40 | nonce := 0 41 | //var hashInt big.Int //用于存储新生成的hash 42 | hashInt := new(big.Int) 43 | var hash [32]byte 44 | for{ 45 | //获取字节数组 46 | dataBytes := pow.prepareData(nonce) 47 | //生成hash 48 | hash = sha256.Sum256(dataBytes) 49 | //fmt.Printf("%d: %x\n",nonce,hash) 50 | fmt.Printf("\r%d: %x",nonce,hash) 51 | //将hash存储到hashInt 52 | hashInt.SetBytes(hash[:]) 53 | //判断hashInt是否小于Block里的target 54 | /* 55 | Com compares x and y and returns: 56 | -1 if x < y 57 | 0 if x == y 58 | 1 if x > y 59 | */ 60 | if pow.Target.Cmp(hashInt) == 1{ 61 | break 62 | } 63 | nonce++ 64 | } 65 | fmt.Println() 66 | return hash[:], int64(nonce) 67 | } 68 | 69 | func (pow *ProofOfWork) prepareData(nonce int)[]byte{ 70 | data := bytes.Join( 71 | [][] byte{ 72 | pow.Block.PrevBlockHash, 73 | pow.Block.HashTransactions(), 74 | IntToHex(pow.Block.TimeStamp), 75 | IntToHex(int64(TargetBit)), 76 | IntToHex(int64(nonce)), 77 | IntToHex(int64(pow.Block.Height)), 78 | }, 79 | [] byte{}, 80 | ) 81 | return data 82 | } 83 | -------------------------------------------------------------------------------- /day08_10_Net/BLC/Server.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import ( 4 | "fmt" 5 | "net" 6 | "log" 7 | "io/ioutil" 8 | ) 9 | 10 | func startServer(nodeID string, minerAdd string) { 11 | //"" 12 | // 当前节点的IP地址 13 | nodeAddress = fmt.Sprintf("localhost:%s", nodeID) 14 | 15 | minerAddress = minerAdd 16 | 17 | 18 | fmt.Printf("nodeAddress:%s,minerAddress:%s\n",nodeAddress,minerAddress) 19 | ln, err := net.Listen(PROTOCOL, nodeAddress) 20 | 21 | if err != nil { 22 | log.Panic(err) 23 | } 24 | 25 | defer ln.Close() 26 | 27 | bc := GetBlockchainObject(nodeID) 28 | 29 | //defer bc.DB.Close() 30 | 31 | // 第一个终端:端口为3000,启动的就是主节点 32 | // 第二个终端:端口为3001,钱包节点 33 | // 第三个终端:端口号为3002,矿工节点 34 | if nodeAddress != knowNodes[0] { 35 | // 此节点是钱包节点或者矿工节点,需要向主节点发送请求同步数据 36 | fmt.Printf("knowNodes:%s\n",knowNodes[0]) 37 | sendVersion(knowNodes[0], bc) 38 | } 39 | 40 | for { 41 | // 收到的数据的格式是固定的,12字节+结构体字节数组 42 | 43 | // 接收客户端发送过来的数据 44 | conn, err := ln.Accept() 45 | if err != nil { 46 | log.Panic(err) 47 | } 48 | 49 | go handleConnection(conn, bc) 50 | 51 | } 52 | 53 | } 54 | 55 | func handleConnection(conn net.Conn, bc *BlockChain) { 56 | 57 | // 读取客户端发送过来的所有的数据 58 | request, err := ioutil.ReadAll(conn) 59 | if err != nil { 60 | log.Panic(err) 61 | } 62 | 63 | fmt.Printf("Receive a Message:%s\n", request[:COMMANDLENGTH]) 64 | 65 | //version 66 | command := bytesToCommand(request[:COMMANDLENGTH]) 67 | 68 | // 12字节 + 某个结构体序列化以后的字节数组 69 | 70 | switch command { 71 | case COMMAND_VERSION: 72 | handleVersion(request, bc) 73 | 74 | case COMMAND_GETBLOCKS: 75 | handleGetblocks(request, bc) 76 | 77 | 78 | case COMMAND_INV: 79 | handleInv(request, bc) 80 | 81 | 82 | case COMMAND_ADDR: 83 | handleAddr(request, bc) 84 | case COMMAND_BLOCK: 85 | handleBlock(request, bc) 86 | 87 | case COMMAND_GETDATA: 88 | handleGetData(request, bc) 89 | 90 | case COMMAND_TX: 91 | handleTx(request, bc) 92 | default: 93 | fmt.Println("Unknown command!") 94 | } 95 | 96 | conn.Close() 97 | } 98 | 99 | func nodeIsKnown(addr string) bool { 100 | for _, node := range knowNodes { 101 | if node == addr { 102 | return true 103 | } 104 | } 105 | 106 | return false 107 | } 108 | -------------------------------------------------------------------------------- /day08_10_Net/BLC/Server_GetData.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | //用于某个块或交易的请求,它可以仅包含一个块或交易的 ID。 3 | type GetData struct { 4 | AddrFrom string 5 | Type string 6 | Hash []byte 7 | } 8 | -------------------------------------------------------------------------------- /day08_10_Net/BLC/Server_Inv.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | type Inv struct { 4 | AddrFrom string //自己的地址 5 | Type string //类型 block tx 6 | Items [][]byte //hash二维数组 7 | } 8 | -------------------------------------------------------------------------------- /day08_10_Net/BLC/Server_Tx.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | type Tx struct { 4 | AddrFrom string 5 | Tx *Transaction 6 | } 7 | 8 | -------------------------------------------------------------------------------- /day08_10_Net/BLC/Server_Version.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | 4 | 5 | type Version struct { 6 | Version int64 // 版本 7 | BestHeight int64 // 当前节点区块的高度 8 | AddrFrom string //当前节点的地址 9 | } 10 | -------------------------------------------------------------------------------- /day08_10_Net/BLC/Server_block.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | type BlockData struct { 4 | AddrFrom string 5 | Block []byte 6 | } 7 | -------------------------------------------------------------------------------- /day08_10_Net/BLC/Server_getblocks.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | //getblocks 意为 “给我看一下你有什么区块”(在比特币中,这会更加复杂) 4 | type GetBlocks struct { 5 | AddrFrom string 6 | } -------------------------------------------------------------------------------- /day08_10_Net/BLC/Server_send.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import ( 4 | "io" 5 | "bytes" 6 | "log" 7 | "net" 8 | "fmt" 9 | ) 10 | 11 | 12 | //COMMAND_VERSION 13 | func sendVersion(toAddress string,bc *BlockChain) { 14 | 15 | 16 | bestHeight := bc.GetBestHeight() 17 | 18 | payload := gobEncode(Version{NODE_VERSION, bestHeight, nodeAddress}) 19 | 20 | //version 21 | request := append(commandToBytes(COMMAND_VERSION), payload...) 22 | 23 | sendData(toAddress,request) 24 | 25 | 26 | } 27 | 28 | 29 | 30 | //COMMAND_GETBLOCKS 31 | func sendGetBlocks(toAddress string) { 32 | 33 | payload := gobEncode(GetBlocks{nodeAddress}) 34 | 35 | request := append(commandToBytes(COMMAND_GETBLOCKS), payload...) 36 | 37 | fmt.Printf("toAddress:%s",toAddress) 38 | sendData(toAddress,request) 39 | 40 | } 41 | 42 | // 主节点将自己的所有的区块hash发送给钱包节点 43 | //COMMAND_BLOCK 44 | // 45 | func sendInv(toAddress string, kind string, hashes [][]byte) { 46 | 47 | payload := gobEncode(Inv{nodeAddress,kind,hashes}) 48 | 49 | request := append(commandToBytes(COMMAND_INV), payload...) 50 | 51 | sendData(toAddress,request) 52 | 53 | } 54 | 55 | 56 | 57 | func sendGetData(toAddress string, kind string ,blockHash []byte) { 58 | 59 | payload := gobEncode(GetData{nodeAddress,kind,blockHash}) 60 | 61 | request := append(commandToBytes(COMMAND_GETDATA), payload...) 62 | 63 | sendData(toAddress,request) 64 | } 65 | 66 | 67 | 68 | func sendBlock(toAddress string, block []byte) { 69 | 70 | 71 | payload := gobEncode(BlockData{nodeAddress,block}) 72 | 73 | request := append(commandToBytes(COMMAND_BLOCK), payload...) 74 | 75 | sendData(toAddress,request) 76 | 77 | } 78 | 79 | func sendTx(toAddress string,tx *Transaction) { 80 | 81 | 82 | payload := gobEncode(Tx{nodeAddress,tx}) 83 | 84 | request := append(commandToBytes(COMMAND_TX), payload...) 85 | 86 | sendData(toAddress,request) 87 | 88 | } 89 | 90 | func sendData(to string,data []byte) { 91 | 92 | conn, err := net.Dial(PROTOCOL, to) 93 | fmt.Println(err) 94 | if err != nil { 95 | panic("error") 96 | } 97 | defer conn.Close() 98 | 99 | // 附带要发送的数据 100 | _, err = io.Copy(conn, bytes.NewReader(data)) 101 | if err != nil { 102 | log.Panic(err) 103 | } 104 | } -------------------------------------------------------------------------------- /day08_10_Net/BLC/Server_var.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | 4 | //存储节点全局变量 5 | 6 | 7 | //localhost:3000 主节点的地址 8 | var knowNodes = []string{"localhost:3000"} 9 | var nodeAddress string //全局变量,节点地址 10 | // 存储hash值 11 | var transactionArray [][]byte 12 | var minerAddress string 13 | var memoryTxPool = make(map[string]*Transaction) 14 | -------------------------------------------------------------------------------- /day08_10_Net/BLC/Transaction_TxInput.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import "bytes" 4 | 5 | type TXInput struct { 6 | //1.交易的ID 7 | TxID [] byte 8 | //2.存储Txoutput的vout里面的索引 9 | Vout int 10 | //3.用户名 11 | //ScriptSiq string 12 | Signature [] byte //数字签名 13 | PublicKey [] byte //公钥,钱包里面 14 | } 15 | 16 | //判断当前txInput消费,和指定的address是否一致 17 | func (txInput *TXInput) UnLockWithAddress(pubKeyHash []byte) bool{ 18 | //return txInput.ScriptSiq == address 19 | publicKey:=PubKeyHash(txInput.PublicKey) 20 | return bytes.Compare(pubKeyHash,publicKey) == 0 21 | } 22 | 23 | 24 | -------------------------------------------------------------------------------- /day08_10_Net/BLC/Transaction_TxOutput.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import "bytes" 4 | 5 | //交易的输出,就是币实际存储的地方 6 | type TXOuput struct { 7 | Value int64 8 | //一个锁定脚本(ScriptPubKey),要花这笔钱,必须要解锁该脚本。 9 | //ScriptPubKey string //公钥:先理解为,用户名 10 | PubKeyHash [] byte // 公钥 11 | } 12 | 13 | //判断当前txOutput消费,和指定的address是否一致 14 | func (txOutput *TXOuput) UnLockWithAddress(address string) bool { 15 | //return txOutput.ScriptPubKey == address 16 | fullPayloadHash := Base58Decode([]byte(address)) 17 | pubKeyHash := fullPayloadHash[1:len(fullPayloadHash)-4] 18 | return bytes.Compare(txOutput.PubKeyHash, pubKeyHash) == 0 19 | } 20 | 21 | 22 | func NewTXOuput(value int64,address string) *TXOuput{ 23 | txOutput := &TXOuput{value, nil} 24 | //设置Ripemd160Hash 25 | txOutput.Lock(address) 26 | return txOutput 27 | } 28 | 29 | func (txOutput *TXOuput) Lock(address string) { 30 | publicKeyHash := Base58Decode([] byte(address)) 31 | txOutput.PubKeyHash = publicKeyHash[1:len(publicKeyHash)-4] 32 | } -------------------------------------------------------------------------------- /day08_10_Net/BLC/Transaction_UTXO.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | //step1:创建一个结构体UTXO,用于表示所有未花费的 4 | type UTXO struct { 5 | TxID [] byte //当前Transaction的交易ID 6 | Index int //下标索引 7 | Output *TXOuput // 8 | } 9 | -------------------------------------------------------------------------------- /day08_10_Net/BLC/TxOutputs.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import ( 4 | "bytes" 5 | "encoding/gob" 6 | "log" 7 | ) 8 | 9 | type TxOutputs struct { 10 | UTXOS []*UTXO 11 | } 12 | 13 | 14 | //序列化 15 | func (outs *TxOutputs) Serilalize()[]byte{ 16 | //1.创建一个buffer 17 | var result bytes.Buffer 18 | //2.创建一个编码器 19 | encoder := gob.NewEncoder(&result) 20 | //3.编码--->打包 21 | err := encoder.Encode(outs) 22 | if err != nil { 23 | log.Panic(err) 24 | } 25 | return result.Bytes() 26 | } 27 | 28 | //反序列化 29 | func DeserializeTXOutputs(txOutputsBytes [] byte) *TxOutputs { 30 | var txOutputs TxOutputs 31 | var reader = bytes.NewReader(txOutputsBytes) 32 | //1.创建一个解码器 33 | decoder := gob.NewDecoder(reader) 34 | //解包 35 | err := decoder.Decode(&txOutputs) 36 | if err != nil { 37 | log.Panic(err) 38 | } 39 | return &txOutputs 40 | } 41 | -------------------------------------------------------------------------------- /day08_10_Net/BLC/Wallet.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import ( 4 | "crypto/ecdsa" 5 | "crypto/elliptic" 6 | "crypto/rand" 7 | "log" 8 | "crypto/sha256" 9 | "golang.org/x/crypto/ripemd160" 10 | "bytes" 11 | ) 12 | 13 | //step1:创建一个钱包 14 | type Wallet struct { 15 | //1.私钥 16 | PrivateKey ecdsa.PrivateKey 17 | //2.公钥 18 | PublicKey [] byte 19 | } 20 | 21 | //step2:产生一对密钥 22 | func newKeyPair() (ecdsa.PrivateKey, []byte) { 23 | /* 24 | 1.通过椭圆曲线算法,随机产生私钥 25 | 2.根据私钥生成公钥 26 | 27 | elliptic:椭圆 28 | curve:曲线 29 | ecc:椭圆曲线加密 30 | ecdsa:elliptic curve digital signature algorithm,椭圆曲线数字签名算法 31 | 比特币使用SECP256K1算法,p256是ecdsa算法中的一种 32 | 33 | */ 34 | //椭圆加密 35 | curve := elliptic.P256() //椭圆加密算法,得到一个椭圆曲线值,全称:SECP256k1 36 | private, err := ecdsa.GenerateKey(curve, rand.Reader) 37 | if err != nil { 38 | log.Panic(err) 39 | } 40 | //生成公钥 41 | pubKey := append(private.PublicKey.X.Bytes(), private.PublicKey.Y.Bytes()...) 42 | return *private, pubKey 43 | } 44 | 45 | //step3:提供一个方法用于获取钱包 46 | func NewWallet() *Wallet { 47 | privateKey, publicKey := newKeyPair() 48 | //fmt.Println("privateKey:", privateKey, ",publicKey:", publicKey) 49 | return &Wallet{privateKey, publicKey} 50 | } 51 | 52 | //step4:根据一个公钥获取对应的地址 53 | /* 54 | 将公钥sha2561次,再160,1次 55 | 然后version+hash 56 | */ 57 | func (w *Wallet) GetAddress() [] byte { 58 | //1.先将公钥进行一次hash256,一次160,得到pubKeyHash 59 | pubKeyHash := PubKeyHash(w.PublicKey) 60 | //2.添加版本号 61 | versioned_payload := append([]byte{version}, pubKeyHash...) 62 | // 3.获取校验和,将pubKeyhash,两次sha256后,取前4位 63 | checkSumBytes := CheckSum(versioned_payload) 64 | full_payload := append(versioned_payload, checkSumBytes...) 65 | //fmt.Println(len(full_payload)) 66 | //4.Base58 67 | address := Base58Encode(full_payload) 68 | return address 69 | 70 | } 71 | 72 | //一次sha256,再一次ripemd160,得到publicKeyHash 73 | func PubKeyHash(publicKey [] byte) []byte { 74 | //1.sha256 75 | hasher := sha256.New() 76 | hasher.Write(publicKey) 77 | hash := hasher.Sum(nil) 78 | 79 | //2.ripemd160 80 | ripemder := ripemd160.New() 81 | ripemder.Write(hash) 82 | pubKeyHash := ripemder.Sum(nil) 83 | 84 | //返回 85 | return pubKeyHash 86 | } 87 | 88 | const version = byte(0x00) 89 | const addressChecksumLen = 4 90 | 91 | //获取验证码:将公钥哈希两次sha256,取前4位,就是校验和 92 | func CheckSum(payload []byte) []byte { 93 | firstSHA := sha256.Sum256(payload) 94 | secondSHA := sha256.Sum256(firstSHA[:]) 95 | return secondSHA[:addressChecksumLen] 96 | } 97 | 98 | 99 | 100 | //判断地址是否有效 101 | /* 102 | 根据地址,base58解码后获取byte[],获取校验和数组 103 | 使用 104 | */ 105 | func IsValidForAddress(address []byte) bool { 106 | full_payload := Base58Decode(address) 107 | //fmt.Println("检验version_public_checksumBytes:",full_payload) 108 | checkSumBytes := full_payload[len(full_payload)-addressChecksumLen:] 109 | //fmt.Println("检验checkSumBytes:",checkSumBytes) 110 | versioned_payload := full_payload[:len(full_payload)-addressChecksumLen] 111 | //fmt.Println("检验version_ripemd160:",versioned_payload) 112 | checkBytes := CheckSum(versioned_payload) 113 | //fmt.Println("检验checkBytes:",checkBytes) 114 | if bytes.Compare(checkSumBytes, checkBytes) == 0 { 115 | return true 116 | } 117 | return false 118 | } -------------------------------------------------------------------------------- /day08_10_Net/BLC/Wallets.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "io/ioutil" 7 | "log" 8 | "encoding/gob" 9 | "crypto/elliptic" 10 | "bytes" 11 | ) 12 | 13 | //1.创建钱包 14 | type Wallets struct { 15 | WalletsMap map[string]*Wallet 16 | } 17 | 18 | //2.创建一个钱包集合 19 | //创建钱包集合:文件中存在从文件中读取,否则新建一个 20 | const walletFile = "Wallets_%s.dat" 21 | 22 | func NewWallets(nodeID string) *Wallets { 23 | //wallets := &WalletsMap{} 24 | //wallets.WalletsMap = make(map[string]*Wallet) 25 | //return wallets 26 | 27 | walletFile := fmt.Sprintf(walletFile,nodeID) 28 | 29 | 30 | //1.判断钱包文件是否存在 31 | if _, err := os.Stat(walletFile); os.IsNotExist(err) { 32 | fmt.Println("文件不存在") 33 | wallets := &Wallets{} 34 | wallets.WalletsMap = make(map[string]*Wallet) 35 | return wallets 36 | } 37 | //2.否则读取文件中的数据 38 | fileContent, err := ioutil.ReadFile(walletFile) 39 | if err != nil { 40 | log.Panic(err) 41 | } 42 | var wallets Wallets 43 | gob.Register(elliptic.P256()) 44 | decoder := gob.NewDecoder(bytes.NewReader(fileContent)) 45 | err = decoder.Decode(&wallets) 46 | if err != nil { 47 | log.Panic(err) 48 | } 49 | return &wallets 50 | } 51 | 52 | //3.创建一个新钱包 53 | func (ws *Wallets) CreateNewWallet(nodeID string) { 54 | wallet := NewWallet() 55 | fmt.Printf("创建钱包地址:%s\n", wallet.GetAddress()) 56 | ws.WalletsMap[string(wallet.GetAddress())] = wallet 57 | 58 | //将钱包保存 59 | ws.SaveWallets(nodeID) 60 | } 61 | 62 | /* 63 | 要让数据对象能在网络上传输或存储,我们需要进行编码和解码。现在比较流行的编码方式有JSON,XML等。然而,Go在gob包中为我们提供了另一种方式,该方式编解码效率高于JSON。 64 | gob是Golang包自带的一个数据结构序列化的编码/解码工具 65 | */ 66 | func (ws *Wallets) SaveWallets(nodeID string) { 67 | 68 | 69 | walletFile := fmt.Sprintf(walletFile,nodeID) 70 | 71 | 72 | var content bytes.Buffer 73 | //注册的目的,为了可以序列化任何类型,wallet结构体中有接口类型。将接口进行注册 74 | gob.Register(elliptic.P256()) //gob是Golang包自带的一个数据结构序列化的编码/解码工具 75 | encoder := gob.NewEncoder(&content) 76 | err := encoder.Encode(ws) 77 | if err != nil { 78 | log.Panic(err) 79 | } 80 | //将序列化后的数据写入到文件,原来的文件中的内容会被覆盖掉 81 | err = ioutil.WriteFile(walletFile, content.Bytes(), 0644) 82 | if err != nil { 83 | log.Panic(err) 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /day08_10_Net/BLC/base58.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | import ( 3 | "math/big" 4 | "bytes" 5 | ) 6 | 7 | //base64 8 | 9 | /* 10 | ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/ 11 | 0(零),O(大写的o),I(大写的i),l(小写的L),+,/ 12 | */ 13 | 14 | var b58Alphabet = []byte("123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz") 15 | 16 | //字节数组转Base58,加密 17 | func Base58Encode(input []byte)[]byte{ 18 | var result [] byte 19 | x := big.NewInt(0).SetBytes(input) 20 | 21 | base :=big.NewInt(int64(len(b58Alphabet))) 22 | zero:=big.NewInt(0) 23 | mod:= &big.Int{} 24 | for x.Cmp(zero) !=0{ 25 | x.DivMod(x,base,mod) 26 | result = append(result,b58Alphabet[mod.Int64()]) 27 | } 28 | ReverseBytes(result) 29 | for b:=range input{ 30 | if b == 0x00{ 31 | result = append([]byte{b58Alphabet[0]},result...) 32 | }else { 33 | break 34 | } 35 | } 36 | 37 | return result 38 | 39 | } 40 | 41 | //Base58转字节数组,解密 42 | func Base58Decode(input[] byte)[]byte{ 43 | result:=big.NewInt(0) 44 | zeroBytes := 0 45 | for b:=range input{ 46 | if b == 0x00{ 47 | zeroBytes++ 48 | } 49 | } 50 | payload := input[zeroBytes:] 51 | for _, b := range payload { 52 | charIndex := bytes.IndexByte(b58Alphabet, b) 53 | result.Mul(result, big.NewInt(58)) 54 | result.Add(result, big.NewInt(int64(charIndex))) 55 | } 56 | 57 | decoded := result.Bytes() 58 | decoded = append(bytes.Repeat([]byte{byte(0x00)}, zeroBytes), decoded...) 59 | 60 | return decoded 61 | } 62 | 63 | 64 | -------------------------------------------------------------------------------- /day08_10_Net/BLC/utils.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import ( 4 | "bytes" 5 | "encoding/binary" 6 | "log" 7 | "encoding/json" 8 | "encoding/gob" 9 | "fmt" 10 | ) 11 | 12 | /* 13 | 将一个int64的整数:转为二进制后,每8bit一个byte。转为[]byte 14 | */ 15 | func IntToHex(num int64) []byte { 16 | buff := new(bytes.Buffer) 17 | //将二进制数据写入w 18 | //func Write(w io.Writer, order ByteOrder, data interface{}) error 19 | err := binary.Write(buff, binary.BigEndian, num) 20 | if err != nil { 21 | log.Panic(err) 22 | } 23 | //转为[]byte并返回 24 | return buff.Bytes() 25 | } 26 | 27 | /* 28 | Json字符串转为[] string数组 29 | */ 30 | func JSONToArray (jsonString string) [] string{ 31 | var sArr [] string 32 | if err := json.Unmarshal([]byte(jsonString),&sArr);err != nil{ 33 | log.Panic(err) 34 | } 35 | return sArr 36 | } 37 | 38 | 39 | //字节数组反转 40 | func ReverseBytes(data []byte) { 41 | for i, j := 0, len(data)-1; i < j; i, j = i+1, j-1 { 42 | data[i], data[j] = data[j], data[i] 43 | } 44 | } 45 | 46 | 47 | //version 转字节数组 48 | func commandToBytes(command string) []byte { 49 | var bytes [COMMANDLENGTH]byte 50 | 51 | for i, c := range command { 52 | bytes[i] = byte(c) 53 | } 54 | 55 | return bytes[:] 56 | } 57 | 58 | 59 | 60 | //字节数组转command 61 | func bytesToCommand(bytes []byte) string { 62 | var command []byte 63 | 64 | for _, b := range bytes { 65 | if b != 0x0 { 66 | command = append(command, b) 67 | } 68 | } 69 | 70 | return fmt.Sprintf("%s", command) 71 | } 72 | 73 | 74 | // 将结构体序列化成字节数组 75 | func gobEncode(data interface{}) []byte { 76 | var buff bytes.Buffer 77 | 78 | enc := gob.NewEncoder(&buff) 79 | err := enc.Encode(data) 80 | if err != nil { 81 | log.Panic(err) 82 | } 83 | 84 | return buff.Bytes() 85 | } 86 | -------------------------------------------------------------------------------- /day08_10_Net/Wallets_3000.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rubyhan1314/PublicChain/fd8b04084c29fe82efe813a0c30864ed1df00383/day08_10_Net/Wallets_3000.dat -------------------------------------------------------------------------------- /day08_10_Net/Wallets_3001.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rubyhan1314/PublicChain/fd8b04084c29fe82efe813a0c30864ed1df00383/day08_10_Net/Wallets_3001.dat -------------------------------------------------------------------------------- /day08_10_Net/Wallets_3002.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rubyhan1314/PublicChain/fd8b04084c29fe82efe813a0c30864ed1df00383/day08_10_Net/Wallets_3002.dat -------------------------------------------------------------------------------- /day08_10_Net/bc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rubyhan1314/PublicChain/fd8b04084c29fe82efe813a0c30864ed1df00383/day08_10_Net/bc -------------------------------------------------------------------------------- /day08_10_Net/blockchain_3000.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rubyhan1314/PublicChain/fd8b04084c29fe82efe813a0c30864ed1df00383/day08_10_Net/blockchain_3000.db -------------------------------------------------------------------------------- /day08_10_Net/blockchain_3001.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rubyhan1314/PublicChain/fd8b04084c29fe82efe813a0c30864ed1df00383/day08_10_Net/blockchain_3001.db -------------------------------------------------------------------------------- /day08_10_Net/blockchain_3002.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rubyhan1314/PublicChain/fd8b04084c29fe82efe813a0c30864ed1df00383/day08_10_Net/blockchain_3002.db -------------------------------------------------------------------------------- /day08_10_Net/blockchain_genesis.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rubyhan1314/PublicChain/fd8b04084c29fe82efe813a0c30864ed1df00383/day08_10_Net/blockchain_genesis.db -------------------------------------------------------------------------------- /day08_10_Net/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "./BLC" 5 | ) 6 | 7 | func main() { 8 | //1.测试Block 9 | //block:=BLC.NewBlock("I am a block",make([]byte,32,32),1) 10 | //fmt.Println(block) 11 | //2.测试创世区块 12 | //genesisBlock :=BLC.CreateGenesisBlock("Genesis Block..") 13 | //fmt.Println(genesisBlock) 14 | 15 | //3.测试区块链 16 | //genesisBlockChain := BLC.CreateBlockChainWithGenesisBlock() 17 | //fmt.Println(genesisBlockChain) 18 | //fmt.Println(genesisBlockChain.Blocks) 19 | //fmt.Println(genesisBlockChain.Blocks[0]) 20 | 21 | //4.测试添加新区块 22 | //blockChain:=BLC.CreateBlockChainWithGenesisBlock() 23 | //blockChain.AddBlockToBlockChain("Send 100RMB To Wangergou",blockChain.Blocks[len(blockChain.Blocks)-1].Height+1,blockChain.Blocks[len(blockChain.Blocks)-1].Hash) 24 | //blockChain.AddBlockToBlockChain("Send 300RMB To lixiaohua",blockChain.Blocks[len(blockChain.Blocks)-1].Height+1,blockChain.Blocks[len(blockChain.Blocks)-1].Hash) 25 | //blockChain.AddBlockToBlockChain("Send 500RMB To rose",blockChain.Blocks[len(blockChain.Blocks)-1].Height+1,blockChain.Blocks[len(blockChain.Blocks)-1].Hash) 26 | // 27 | //fmt.Println(blockChain) 28 | 29 | //5.测试序列化和反序列化 30 | //block:=BLC.NewBlock("helloworld",make([]byte,32,32),0) 31 | //data:=block.Serilalize() 32 | //fmt.Println(block) 33 | //fmt.Println(data) 34 | //block2:=BLC.DeserializeBlock(data) 35 | //fmt.Println(block2) 36 | 37 | //6.创建区块,存入数据库 38 | //打开数据库 39 | //block:=BLC.NewBlock("helloworld",make([]byte,32,32),0) 40 | //db,err := bolt.Open("my.db",0600,nil) 41 | //if err != nil{ 42 | // log.Fatal(err) 43 | //} 44 | // 45 | //defer db.Close() 46 | // 47 | //err = db.Update(func(tx *bolt.Tx) error { 48 | // //获取bucket,没有就创建新表 49 | // b := tx.Bucket([]byte("blocks")) 50 | // if b == nil{ 51 | // b,err = tx.CreateBucket([] byte("blocks")) 52 | // if err !=nil{ 53 | // log.Panic("创建表失败") 54 | // } 55 | // } 56 | // //添加数据 57 | // err = b.Put([]byte("l"),block.Serilalize()) 58 | // if err !=nil{ 59 | // log.Panic(err) 60 | // } 61 | // 62 | // return nil 63 | //}) 64 | //if err != nil{ 65 | // log.Panic(err) 66 | //} 67 | //err = db.View(func(tx *bolt.Tx) error { 68 | // b := tx.Bucket([]byte("blocks")) 69 | // if b !=nil{ 70 | // data := b.Get([]byte("l")) 71 | // //fmt.Printf("%s\n",data)//直接打印会乱码 72 | // //反序列化 73 | // block2:=BLC.DeserializeBlock(data) 74 | // //fmt.Println(block2) 75 | // fmt.Printf("%v\n",block2) 76 | // 77 | // } 78 | // return nil 79 | //}) 80 | 81 | //7.测试创世区块存入数据库 82 | //blockchain:=BLC.CreateBlockChainWithGenesisBlock("Genesis Block..") 83 | //fmt.Println(blockchain) 84 | //defer blockchain.DB.Close() 85 | //8.测试新添加的区块 86 | //blockchain.AddBlockToBlockChain("Send 100RMB to wangergou") 87 | //blockchain.AddBlockToBlockChain("Send 100RMB to lixiaohua") 88 | //blockchain.AddBlockToBlockChain("Send 100RMB to rose") 89 | //fmt.Println(blockchain) 90 | //blockchain.PrintChains() 91 | 92 | //9.CLI操作 93 | cli:=BLC.CLI{} 94 | cli.Run() 95 | 96 | //outsMap := make(map[string]*BLC.TxOutputs) 97 | //outputs:=outsMap["aa"] 98 | //fmt.Println(outputs) 99 | //fmt.Println(len(outputs.UTXOS)) 100 | 101 | 102 | } --------------------------------------------------------------------------------