├── part2 ├── cli ├── block.db ├── BLC │ ├── Utlis.go │ ├── BlockChainIterator.go │ ├── ProofOfWork.go │ ├── CLI.go │ ├── Block.go │ └── BlockChain.go └── main.go ├── part3 ├── cli ├── block.db ├── BLC │ ├── UTXO.go │ ├── Transaction_TXOutput.go │ ├── Transaction_TXInput.go │ ├── Utlis.go │ ├── BlockChainIterator.go │ ├── ProofOfWork.go │ ├── Block.go │ ├── Transaction.go │ ├── CLI.go │ └── BlockChain.go └── main.go ├── part1 ├── block.db ├── BLC │ ├── Utlis.go │ ├── BlockChain.go │ ├── ProofOfWork.go │ └── Block.go └── main.go ├── .idea └── vcs.xml └── README.md /part2/cli: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiangyuanyuan/PublicBlackChain/HEAD/part2/cli -------------------------------------------------------------------------------- /part3/cli: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiangyuanyuan/PublicBlackChain/HEAD/part3/cli -------------------------------------------------------------------------------- /part1/block.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiangyuanyuan/PublicBlackChain/HEAD/part1/block.db -------------------------------------------------------------------------------- /part2/block.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiangyuanyuan/PublicBlackChain/HEAD/part2/block.db -------------------------------------------------------------------------------- /part3/block.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiangyuanyuan/PublicBlackChain/HEAD/part3/block.db -------------------------------------------------------------------------------- /part3/BLC/UTXO.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | type UTXO struct { 4 | TxHash []byte 5 | Index int64 6 | Output *TXOutput 7 | } 8 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /part3/BLC/Transaction_TXOutput.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | type TXOutput struct { 4 | Value int64 5 | ScriptPubKey string 6 | } 7 | 8 | //判断是否是该地址的钱 9 | func (TXOutput *TXOutput) UnLockWithAddress(address string) bool { 10 | return TXOutput.ScriptPubKey == address 11 | } 12 | -------------------------------------------------------------------------------- /part3/BLC/Transaction_TXInput.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | type TXInput struct { 4 | TxHash []byte 5 | Vout int64 6 | SciptSig string 7 | } 8 | 9 | //判断是否是该地址的钱 10 | func (TXInput *TXInput) UnLockWithAddress(address string) bool { 11 | return TXInput.SciptSig == address 12 | } 13 | -------------------------------------------------------------------------------- /part1/BLC/Utlis.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import ( 4 | "bytes" 5 | "encoding/binary" 6 | "log" 7 | ) 8 | 9 | //int64转换成字节数组 10 | func IntToHex(num int64) []byte { 11 | buff := new(bytes.Buffer) 12 | err := binary.Write(buff, binary.BigEndian, num) 13 | if err != nil { 14 | log.Panic(err) 15 | } 16 | return buff.Bytes() 17 | } 18 | -------------------------------------------------------------------------------- /part2/BLC/Utlis.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import ( 4 | "bytes" 5 | "encoding/binary" 6 | "log" 7 | ) 8 | 9 | //int64转换成字节数组 10 | func IntToHex(num int64) []byte { 11 | buff := new(bytes.Buffer) 12 | err := binary.Write(buff, binary.BigEndian, num) 13 | if err != nil { 14 | log.Panic(err) 15 | } 16 | return buff.Bytes() 17 | } 18 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PublicBlackChain 2 | GO语言简单实现BlockChain区块链公链,POW工作量证明,UTXO未使用交易输出模型,P2P网络模型(后面再写) 3 | # 持续更新中。。。 4 | ### part1 5 | * BlockChain 存储为内存数组 简单实现 6 | ### part2 7 | * BlcokChain 存储为blotdb 8 | ### part3 9 | * BlcokChain UTXO未使用交易输出模型 10 | 11 | ## 进度 12 | * pow工作量证明 OK 13 | * 终端工具 OK 14 | * UTXO未使用交易输出 OK 15 | * P2P网络模型 NO 16 | -------------------------------------------------------------------------------- /part2/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "PublicBlackChain/part2/BLC" 4 | 5 | func main() { 6 | 7 | //1、迭代测试 8 | //blockchain := BLC.CreatBlockChainWithGenensis() 9 | //blockchain.AddBlockToBlockChain("Send 100RMB To JYY") 10 | //blockchain.AddBlockToBlockChain("Send 200RMB To Freedom") 11 | //blockchain.AddBlockToBlockChain("Send 300RMB To Hope") 12 | ////blockchain.PrintChain() 13 | // 14 | //blockchain.PrintChainIterator() 15 | 16 | //2、终端工具 17 | CLI := BLC.CLI{} 18 | CLI.RUN() 19 | 20 | } 21 | -------------------------------------------------------------------------------- /part3/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "PublicBlackChain/part3/BLC" 4 | 5 | func main() { 6 | 7 | //1、迭代测试 8 | //blockchain := BLC.CreatBlockChainWithGenensis() 9 | //blockchain.AddBlockToBlockChain("Send 100RMB To JYY") 10 | //blockchain.AddBlockToBlockChain("Send 200RMB To Freedom") 11 | //blockchain.AddBlockToBlockChain("Send 300RMB To Hope") 12 | ////blockchain.PrintChain() 13 | // 14 | //blockchain.PrintChainIterator() 15 | 16 | //2、终端工具 17 | CLI := BLC.CLI{} 18 | CLI.RUN() 19 | 20 | } 21 | -------------------------------------------------------------------------------- /part1/BLC/BlockChain.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | type BlockChain struct { 4 | Blocks []*Block 5 | } 6 | 7 | //创建创世区块链 8 | func CreatBlockChainWithGenensis() *BlockChain { 9 | genensisBlock := CreateGenensisBlock("Genenis Block ...") 10 | 11 | return &BlockChain{[]*Block{genensisBlock}} 12 | } 13 | 14 | func (blc *BlockChain) AddBlockToBlockChain(data string, height int64, preHash []byte) { 15 | //创建新区块 16 | block := NewBlock(height, preHash, data) 17 | //添加到区块链中 18 | blc.Blocks = append(blc.Blocks, block) 19 | } 20 | -------------------------------------------------------------------------------- /part3/BLC/Utlis.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import ( 4 | "bytes" 5 | "encoding/binary" 6 | "encoding/json" 7 | "log" 8 | ) 9 | 10 | //int64转换成字节数组 11 | func IntToHex(num int64) []byte { 12 | buff := new(bytes.Buffer) 13 | err := binary.Write(buff, binary.BigEndian, num) 14 | if err != nil { 15 | log.Panic(err) 16 | } 17 | return buff.Bytes() 18 | } 19 | 20 | //JSON转字符串数组 21 | func JSONToArray(jsonString string) []string { 22 | var sArr []string 23 | if err := json.Unmarshal([]byte(jsonString), &sArr); err != nil { 24 | log.Panic(err) 25 | } 26 | return sArr 27 | } 28 | -------------------------------------------------------------------------------- /part3/BLC/BlockChainIterator.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import ( 4 | "github.com/boltdb/bolt" 5 | "log" 6 | ) 7 | 8 | //迭代器结构体 9 | type BlockChainIterator struct { 10 | CurrentHash []byte 11 | DB *bolt.DB 12 | } 13 | 14 | func (blockchanIterator *BlockChainIterator) Next() (block *Block) { 15 | 16 | err := blockchanIterator.DB.View(func(tx *bolt.Tx) error { 17 | b := tx.Bucket([]byte(bucketName)) 18 | if b != nil { 19 | currentBlockBytes := b.Get(blockchanIterator.CurrentHash) 20 | 21 | block = DeSerializeBlock(currentBlockBytes) 22 | 23 | blockchanIterator.CurrentHash = block.PreHash 24 | 25 | } 26 | 27 | return nil 28 | }) 29 | if err != nil { 30 | log.Panic(err) 31 | } 32 | return block 33 | } 34 | -------------------------------------------------------------------------------- /part2/BLC/BlockChainIterator.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import ( 4 | "github.com/boltdb/bolt" 5 | "log" 6 | ) 7 | 8 | //迭代器结构体 9 | type BlockChainIterator struct { 10 | CurrentHash []byte 11 | DB *bolt.DB 12 | } 13 | 14 | func (blockchainIterator *BlockChainIterator) Next() (block *Block) { 15 | 16 | err := blockchainIterator.DB.View(func(tx *bolt.Tx) error { 17 | b := tx.Bucket([]byte(bucketName)) 18 | if b != nil { 19 | currentBlockBytes := b.Get(blockchainIterator.CurrentHash) 20 | 21 | block = DeSerializeBlock(currentBlockBytes) 22 | 23 | blockchainIterator.CurrentHash = block.PreHash 24 | 25 | } 26 | 27 | return nil 28 | }) 29 | if err != nil { 30 | log.Panic(err) 31 | } 32 | return block 33 | } 34 | -------------------------------------------------------------------------------- /part1/BLC/ProofOfWork.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import ( 4 | "bytes" 5 | "crypto/sha256" 6 | "fmt" 7 | "math/big" 8 | ) 9 | 10 | const targetBit = 20 //挖矿难度 11 | type ProofOfWork struct { 12 | Block *Block 13 | target *big.Int //1左位移生成做对比的 14 | } 15 | 16 | func NewProofOfWork(block *Block) *ProofOfWork { 17 | 18 | target := big.NewInt(1) 19 | 20 | target = target.Lsh(target, 256-targetBit) //左移 生成对比值 21 | 22 | return &ProofOfWork{block, target} 23 | } 24 | 25 | func (pow *ProofOfWork) IsValid() bool { 26 | var hashInt big.Int 27 | hashInt.SetBytes(pow.Block.Hash) 28 | if pow.target.Cmp(&hashInt) == 1 { 29 | return true 30 | } 31 | return false 32 | } 33 | 34 | func (pow *ProofOfWork) Run() ([]byte, int64) { 35 | //1、拼接block所以属性 36 | //2、判断hash是否满足难度 37 | nonce := 0 38 | var hashInt big.Int //存储新生成的hash 39 | var hash [32]byte 40 | for { 41 | //准备数据 42 | dataBytes := pow.prepareData(nonce) 43 | //生成hash 44 | hash = sha256.Sum256(dataBytes) 45 | fmt.Printf("\r%x", hash) 46 | //hash 存储hashInt 47 | hashInt.SetBytes(hash[:]) 48 | 49 | //判断hashInt 是否小于target 50 | if pow.target.Cmp(&hashInt) == 1 { 51 | fmt.Println() 52 | break 53 | } 54 | 55 | nonce = nonce + 1 56 | } 57 | return hash[:], int64(nonce) 58 | } 59 | 60 | func (pow *ProofOfWork) prepareData(nonce int) []byte { 61 | //5、拼接 62 | blockBytes := bytes.Join( 63 | [][]byte{IntToHex(int64(pow.Block.Height)), 64 | pow.Block.PreHash, 65 | pow.Block.Data, 66 | IntToHex(int64(pow.Block.TimesTamp)), 67 | IntToHex(int64(targetBit)), 68 | IntToHex(int64(nonce))}, 69 | []byte{}) 70 | // 生成hash 71 | hash := sha256.Sum256(blockBytes) 72 | return hash[:] 73 | } 74 | -------------------------------------------------------------------------------- /part2/BLC/ProofOfWork.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import ( 4 | "bytes" 5 | "crypto/sha256" 6 | "fmt" 7 | "math/big" 8 | ) 9 | 10 | const targetBit = 16 //挖矿难度 11 | type ProofOfWork struct { 12 | Block *Block 13 | target *big.Int //1左位移生成做对比的 14 | } 15 | 16 | func NewProofOfWork(block *Block) *ProofOfWork { 17 | 18 | target := big.NewInt(1) 19 | 20 | target = target.Lsh(target, 256-targetBit) //左移 生成对比值 21 | 22 | return &ProofOfWork{block, target} 23 | } 24 | 25 | func (pow *ProofOfWork) IsValid() bool { 26 | var hashInt big.Int 27 | hashInt.SetBytes(pow.Block.Hash) 28 | if pow.target.Cmp(&hashInt) == 1 { 29 | return true 30 | } 31 | return false 32 | } 33 | 34 | func (pow *ProofOfWork) Run() ([]byte, int64) { 35 | //1、拼接block所以属性 36 | //2、判断hash是否满足难度 37 | nonce := 0 38 | var hashInt big.Int //存储新生成的hash 39 | var hash [32]byte 40 | for { 41 | //准备数据 42 | dataBytes := pow.prepareData(nonce) 43 | //生成hash 44 | hash = sha256.Sum256(dataBytes) 45 | fmt.Printf("\r%x", hash) 46 | //hash 存储hashInt 47 | hashInt.SetBytes(hash[:]) 48 | 49 | //判断hashInt 是否小于target 50 | if pow.target.Cmp(&hashInt) == 1 { 51 | fmt.Println() 52 | break 53 | } 54 | 55 | nonce = nonce + 1 56 | } 57 | return hash[:], int64(nonce) 58 | } 59 | 60 | func (pow *ProofOfWork) prepareData(nonce int) []byte { 61 | //5、拼接 62 | blockBytes := bytes.Join( 63 | [][]byte{IntToHex(int64(pow.Block.Height)), 64 | pow.Block.PreHash, 65 | pow.Block.Data, 66 | IntToHex(int64(pow.Block.TimesTamp)), 67 | IntToHex(int64(targetBit)), 68 | IntToHex(int64(nonce))}, 69 | []byte{}) 70 | // 生成hash 71 | hash := sha256.Sum256(blockBytes) 72 | return hash[:] 73 | } 74 | -------------------------------------------------------------------------------- /part3/BLC/ProofOfWork.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import ( 4 | "bytes" 5 | "crypto/sha256" 6 | "fmt" 7 | "math/big" 8 | ) 9 | 10 | const targetBit = 16 //挖矿难度 11 | type ProofOfWork struct { 12 | Block *Block 13 | target *big.Int //1左位移生成做对比的 14 | } 15 | 16 | func NewProofOfWork(block *Block) *ProofOfWork { 17 | 18 | target := big.NewInt(1) 19 | 20 | target = target.Lsh(target, 256-targetBit) //左移 生成对比值 21 | 22 | return &ProofOfWork{block, target} 23 | } 24 | 25 | func (pow *ProofOfWork) IsValid() bool { 26 | var hashInt big.Int 27 | hashInt.SetBytes(pow.Block.Hash) 28 | if pow.target.Cmp(&hashInt) == 1 { 29 | return true 30 | } 31 | return false 32 | } 33 | 34 | func (pow *ProofOfWork) Run() ([]byte, int64) { 35 | //1、拼接block所以属性 36 | //2、判断hash是否满足难度 37 | nonce := 0 38 | var hashInt big.Int //存储新生成的hash 39 | var hash [32]byte 40 | for { 41 | //准备数据 42 | dataBytes := pow.prepareData(nonce) 43 | //生成hash 44 | hash = sha256.Sum256(dataBytes) 45 | fmt.Printf("\r%x", hash) 46 | //hash 存储hashInt 47 | hashInt.SetBytes(hash[:]) 48 | 49 | //判断hashInt 是否小于target 50 | if pow.target.Cmp(&hashInt) == 1 { 51 | fmt.Println() 52 | break 53 | } 54 | 55 | nonce = nonce + 1 56 | } 57 | return hash[:], int64(nonce) 58 | } 59 | 60 | func (pow *ProofOfWork) prepareData(nonce int) []byte { 61 | //5、拼接 62 | blockBytes := bytes.Join( 63 | [][]byte{IntToHex(int64(pow.Block.Height)), 64 | pow.Block.PreHash, 65 | pow.Block.HashTransactions(), 66 | IntToHex(int64(pow.Block.TimesTamp)), 67 | IntToHex(int64(targetBit)), 68 | IntToHex(int64(nonce))}, 69 | []byte{}) 70 | // 生成hash 71 | hash := sha256.Sum256(blockBytes) 72 | return hash[:] 73 | } 74 | -------------------------------------------------------------------------------- /part3/BLC/Block.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import ( 4 | "bytes" 5 | "crypto/sha256" 6 | "encoding/gob" 7 | "fmt" 8 | "log" 9 | "time" 10 | ) 11 | 12 | type Block struct { 13 | //区块高度 14 | Height int64 15 | //上一个区块的hash 16 | PreHash []byte 17 | //交易数据 18 | txs []*Transaction 19 | //区块Hash 20 | Hash []byte 21 | 22 | //交易时间戳 23 | TimesTamp int64 24 | //挖矿所需的 25 | Nonce int64 26 | } 27 | 28 | //创建创世区块 29 | func CreateGenensisBlock(txs []*Transaction) *Block { 30 | 31 | return NewBlock(1, []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, txs) 32 | 33 | } 34 | 35 | //创建一个区块 36 | func NewBlock(Height int64, PreHash []byte, txs []*Transaction) *Block { 37 | //创建区块对象 38 | block := &Block{Height, PreHash, txs, nil, time.Now().Unix(), 0} 39 | 40 | //工作量证明 生成有效Hash、nonce值 41 | pow := NewProofOfWork(block) 42 | hash, nonce := pow.Run() 43 | block.Hash = hash[:] 44 | block.Nonce = nonce 45 | 46 | fmt.Println(block) 47 | fmt.Println(hash) 48 | fmt.Println(nonce) 49 | return block 50 | } 51 | 52 | //叠加交易生成[]byte 53 | func (blcok *Block) HashTransactions() []byte { 54 | 55 | var txHashs [][]byte 56 | var txHash [32]byte 57 | for _, tx := range blcok.txs { 58 | txHashs = append(txHashs, tx.TxHash) 59 | } 60 | txHash = sha256.Sum256(bytes.Join(txHashs, []byte{})) 61 | 62 | return txHash[:] 63 | } 64 | 65 | //序列化 便于存储到db中 66 | func (block *Block) Serialize() []byte { 67 | var result bytes.Buffer 68 | encoder := gob.NewEncoder(&result) 69 | err := encoder.Encode(block) 70 | if err != nil { 71 | log.Panic(err) 72 | } 73 | return result.Bytes() 74 | } 75 | 76 | //反序列化 db中取出的byte 生成block对象 77 | func DeSerializeBlock(blockBytes []byte) *Block { 78 | var block Block 79 | decoder := gob.NewDecoder(bytes.NewReader(blockBytes)) 80 | err := decoder.Decode(&block) 81 | if err != nil { 82 | log.Panic(err) 83 | } 84 | return &block 85 | } 86 | -------------------------------------------------------------------------------- /part2/BLC/CLI.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | "log" 7 | "os" 8 | ) 9 | 10 | type CLI struct { 11 | //BlockChain *BlockChain 12 | } 13 | 14 | func (cli *CLI) AddBlock(data string) { 15 | 16 | GetBlockChainObj().AddBlockToBlockChain(data) 17 | } 18 | 19 | func (cli *CLI) PrintChain() { 20 | GetBlockChainObj().PrintChainIterator() 21 | } 22 | 23 | func (cli *CLI) CreatBlockChainWithGenensis(data string) { 24 | CreatBlockChainWithGenensisCLI(data) 25 | } 26 | 27 | func (cli *CLI) RUN() { 28 | 29 | isValidArgs() 30 | addBlockCmd := flag.NewFlagSet("add", flag.ExitOnError) 31 | printChainCmd := flag.NewFlagSet("print", flag.ExitOnError) 32 | createChainCmd := flag.NewFlagSet("create", flag.ExitOnError) 33 | 34 | flagAddData := addBlockCmd.String("d", "freedom", "交易数据") 35 | flagCreateGenensisData := createChainCmd.String("d", "Genensis Block ...", "创世区块") 36 | switch os.Args[1] { 37 | case "add": 38 | err := addBlockCmd.Parse(os.Args[2:]) 39 | if err != nil { 40 | log.Panic(err) 41 | } 42 | case "print": 43 | err := printChainCmd.Parse(os.Args[2:]) 44 | if err != nil { 45 | log.Panic(err) 46 | } 47 | case "create": 48 | err := createChainCmd.Parse(os.Args[2:]) 49 | if err != nil { 50 | log.Panic(err) 51 | } 52 | default: 53 | printUsage() 54 | os.Exit(1) 55 | } 56 | 57 | if addBlockCmd.Parsed() { 58 | if *flagAddData == "" { 59 | printUsage() 60 | os.Exit(1) 61 | } 62 | fmt.Println(*flagAddData) 63 | cli.AddBlock(*flagAddData) 64 | } 65 | 66 | if printChainCmd.Parsed() { 67 | fmt.Println("输出所以区块数据") 68 | cli.PrintChain() 69 | } 70 | 71 | if createChainCmd.Parsed() { 72 | if *flagCreateGenensisData == "" { 73 | printUsage() 74 | os.Exit(1) 75 | } 76 | fmt.Println(*flagCreateGenensisData) 77 | cli.CreatBlockChainWithGenensis(*flagCreateGenensisData) 78 | } 79 | } 80 | 81 | func printUsage() { 82 | fmt.Println("Usage:") 83 | fmt.Println("\tadd -d DATA - 交易数据") 84 | fmt.Println("\tcreate -d DATA - 创世区块") 85 | fmt.Println("\tprint - 打印信息") 86 | fmt.Println("Usage:") 87 | 88 | } 89 | func isValidArgs() { 90 | if len(os.Args) < 2 { 91 | printUsage() 92 | os.Exit(1) 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /part1/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "PublicBlackChain/part1/BLC" 5 | "fmt" 6 | "github.com/boltdb/bolt" 7 | "log" 8 | ) 9 | 10 | func main() { 11 | //1、创建创世区块链、添加新区块测试 12 | //blockchain := BLC.CreatBlockChainWithGenensis() 13 | //blockchain.AddBlockToBlockChain("Send 100RMB To JYY", blockchain.Blocks[len(blockchain.Blocks)-1].Height+1, blockchain.Blocks[len(blockchain.Blocks)-1].Hash) 14 | //blockchain.AddBlockToBlockChain("Send 200RMB To Freedom", blockchain.Blocks[len(blockchain.Blocks)-1].Height+1, blockchain.Blocks[len(blockchain.Blocks)-1].Hash) 15 | //blockchain.AddBlockToBlockChain("Send 300RMB To Hope", blockchain.Blocks[len(blockchain.Blocks)-1].Height+1, blockchain.Blocks[len(blockchain.Blocks)-1].Hash) 16 | 17 | //2、有效hash验证测试 18 | //block:=BLC.NewBlock(1,[]byte{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},"test") 19 | //proofOfWork:=BLC.NewProofOfWork(block) 20 | //fmt.Printf("%v",proofOfWork.IsValid()) 21 | 22 | //3、序列号 反序列化测试 便于存储到DB 23 | //block:=BLC.NewBlock(1,[]byte{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},"test") 24 | //bytes :=block.Serialize() 25 | //fmt.Println(bytes) 26 | //block = BLC.DeSerializeBlock(bytes) 27 | //fmt.Println(block) 28 | 29 | //4、boltdb测试 30 | block := BLC.NewBlock(1, []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, "test") 31 | db, err := bolt.Open("block.db", 0600, nil) 32 | if err != nil { 33 | log.Panic(err) 34 | } 35 | defer db.Close() 36 | err = db.Update(func(tx *bolt.Tx) error { 37 | b := tx.Bucket([]byte("blocks")) 38 | if b == nil { 39 | b, err = tx.CreateBucket([]byte("blocks")) 40 | if err != nil { 41 | log.Panic(err) 42 | } 43 | } 44 | err = b.Put([]byte("l"), block.Serialize()) 45 | if err != nil { 46 | log.Panic(err) 47 | } 48 | return nil 49 | }) 50 | if err != nil { 51 | log.Panic(err) 52 | } 53 | err = db.View(func(tx *bolt.Tx) error { 54 | b := tx.Bucket([]byte("blocks")) 55 | if b != nil { 56 | blockData := b.Get([]byte("l")) 57 | fmt.Println(blockData) 58 | block := BLC.DeSerializeBlock(blockData) 59 | fmt.Println(block) 60 | } 61 | return nil 62 | }) 63 | } 64 | -------------------------------------------------------------------------------- /part3/BLC/Transaction.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import ( 4 | "bytes" 5 | "crypto/sha256" 6 | "encoding/gob" 7 | "encoding/hex" 8 | "fmt" 9 | "log" 10 | ) 11 | 12 | type Transaction struct { 13 | //交易Hash 14 | TxHash []byte 15 | 16 | //输入 17 | Vins []*TXInput 18 | 19 | //输出 20 | Vouts []*TXOutput 21 | } 22 | 23 | //是否是创世区块的交易 24 | func (tx *Transaction) IsConbaseTransaction() bool { 25 | 26 | return len(tx.Vins[0].TxHash) == 0 && tx.Vins[0].Vout == -1 27 | } 28 | 29 | //创建Transation区分2种情况 30 | //1、创世区块的 input为空的 31 | func NewCoinBaseTransaction(addr string) *Transaction { 32 | txInput := &TXInput{[]byte{}, -1, "Genensis Data"} 33 | txOutput := &TXOutput{10, addr} 34 | txCoinBase := &Transaction{[]byte{}, []*TXInput{txInput}, []*TXOutput{txOutput}} 35 | txCoinBase.TxHash = HashTransaction(txCoinBase) 36 | return txCoinBase 37 | } 38 | 39 | //2、正常交易 40 | func NewNormalTransaction(from string, to string, value int64, txs []*Transaction) *Transaction { 41 | 42 | //转账命令:./cli send -from '["freedom"]' -to '["hope"]' -d '["10"]' 43 | 44 | //1、form这个address所有的未话费交易输出的Transaction 45 | unUtxo := GetBlockChainObj().UnUTXOs(from, txs) 46 | fmt.Println(unUtxo) 47 | 48 | money, unUtxoDic := GetBlockChainObj().FindSpendableUTXOS(from, value, txs) 49 | 50 | var txInputs []*TXInput 51 | var txOutputs []*TXOutput 52 | //建立txInputs 数票子 53 | 54 | for txHash, indexArray := range unUtxoDic { 55 | txHashBytes, _ := hex.DecodeString(txHash) 56 | for _, index := range indexArray { 57 | txInput := &TXInput{txHashBytes, index, from} 58 | //消费 59 | txInputs = append(txInputs, txInput) 60 | } 61 | } 62 | 63 | //转账 64 | txOutput := &TXOutput{value, to} 65 | txOutputs = append(txOutputs, txOutput) 66 | //找零 67 | txOutput = &TXOutput{money - value, from} 68 | txOutputs = append(txOutputs, txOutput) 69 | 70 | tx := &Transaction{[]byte{}, txInputs, txOutputs} 71 | tx.TxHash = HashTransaction(tx) 72 | return tx 73 | } 74 | 75 | //交易生成hash 76 | func HashTransaction(tx *Transaction) []byte { 77 | var result bytes.Buffer 78 | encoder := gob.NewEncoder(&result) 79 | err := encoder.Encode(tx) 80 | if err != nil { 81 | log.Panic(err) 82 | } 83 | hash := sha256.Sum256(result.Bytes()) 84 | return hash[:] 85 | } 86 | -------------------------------------------------------------------------------- /part1/BLC/Block.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import ( 4 | "bytes" 5 | "crypto/sha256" 6 | "encoding/gob" 7 | "fmt" 8 | "log" 9 | "strconv" 10 | "time" 11 | ) 12 | 13 | type Block struct { 14 | //区块高度 15 | Height int64 16 | //上一个区块的hash 17 | PreHash []byte 18 | //交易数据 19 | Data []byte 20 | //区块Hash 21 | Hash []byte 22 | 23 | //交易时间戳 24 | TimesTamp int64 25 | //挖矿所需的 26 | Nonce int64 27 | } 28 | 29 | //创建创世区块 30 | func CreateGenensisBlock(data string) *Block { 31 | return NewBlock(1, []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, data) 32 | 33 | } 34 | 35 | //创建一个区块 36 | func NewBlock(Height int64, PreHash []byte, data string) *Block { 37 | //创建区块对象 38 | block := &Block{Height, PreHash, []byte(data), nil, time.Now().Unix(), 0} 39 | //设置Hash 40 | //block.SetHash() 41 | 42 | //工作量证明 生成有效Hash、nonce值 43 | pow := NewProofOfWork(block) 44 | hash, nonce := pow.Run() 45 | block.Hash = hash[:] 46 | block.Nonce = nonce 47 | 48 | fmt.Println(block) 49 | fmt.Println(hash) 50 | fmt.Println(nonce) 51 | return block 52 | } 53 | 54 | //序列化 便于存储到db中 55 | func (block *Block) Serialize() []byte { 56 | var result bytes.Buffer 57 | encoder := gob.NewEncoder(&result) 58 | err := encoder.Encode(block) 59 | if err != nil { 60 | log.Panic(err) 61 | } 62 | return result.Bytes() 63 | } 64 | 65 | //反序列化 db中取出的byte 生成block对象 66 | func DeSerializeBlock(blockBytes []byte) *Block { 67 | var block Block 68 | decoder := gob.NewDecoder(bytes.NewReader(blockBytes)) 69 | err := decoder.Decode(&block) 70 | if err != nil { 71 | log.Panic(err) 72 | } 73 | return &block 74 | } 75 | func (block *Block) SetHash() { 76 | //拼接所以属性生成Hash 77 | 78 | //1、Height 转换 []byte数组 79 | heighBytes := IntToHex(block.Height) 80 | //fmt.Println(heighBytes) 81 | //2、preHash 转换 []byte数组 82 | 83 | //3、data 转换 []byte数组 84 | 85 | //4、TimesTamp 转换 []byte数组 86 | timeString := strconv.FormatInt(block.TimesTamp, 2) 87 | timeBytes := []byte(timeString) 88 | //fmt.Println(timeBytes) 89 | //5、拼接 90 | blockBytes := bytes.Join([][]byte{heighBytes, block.PreHash, block.Data, block.Hash, timeBytes}, []byte{}) 91 | // 生成hash 92 | hash := sha256.Sum256(blockBytes) 93 | 94 | block.Hash = hash[:] 95 | 96 | } 97 | -------------------------------------------------------------------------------- /part2/BLC/Block.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import ( 4 | "bytes" 5 | "crypto/sha256" 6 | "encoding/gob" 7 | "fmt" 8 | "log" 9 | "strconv" 10 | "time" 11 | ) 12 | 13 | type Block struct { 14 | //区块高度 15 | Height int64 16 | //上一个区块的hash 17 | PreHash []byte 18 | //交易数据 19 | Data []byte 20 | //区块Hash 21 | Hash []byte 22 | 23 | //交易时间戳 24 | TimesTamp int64 25 | //挖矿所需的 26 | Nonce int64 27 | } 28 | 29 | //创建创世区块 30 | func CreateGenensisBlock(data string) *Block { 31 | return NewBlock(1, []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, data) 32 | 33 | } 34 | 35 | //创建一个区块 36 | func NewBlock(Height int64, PreHash []byte, data string) *Block { 37 | //创建区块对象 38 | block := &Block{Height, PreHash, []byte(data), nil, time.Now().Unix(), 0} 39 | //设置Hash 40 | //block.SetHash() 41 | 42 | //工作量证明 生成有效Hash、nonce值 43 | pow := NewProofOfWork(block) 44 | hash, nonce := pow.Run() 45 | block.Hash = hash[:] 46 | block.Nonce = nonce 47 | 48 | fmt.Println(block) 49 | fmt.Println(hash) 50 | fmt.Println(nonce) 51 | return block 52 | } 53 | 54 | //序列化 便于存储到db中 55 | func (block *Block) Serialize() []byte { 56 | var result bytes.Buffer 57 | encoder := gob.NewEncoder(&result) 58 | err := encoder.Encode(block) 59 | if err != nil { 60 | log.Panic(err) 61 | } 62 | return result.Bytes() 63 | } 64 | 65 | //反序列化 db中取出的byte 生成block对象 66 | func DeSerializeBlock(blockBytes []byte) *Block { 67 | var block Block 68 | decoder := gob.NewDecoder(bytes.NewReader(blockBytes)) 69 | err := decoder.Decode(&block) 70 | if err != nil { 71 | log.Panic(err) 72 | } 73 | return &block 74 | } 75 | func (block *Block) SetHash() { 76 | //拼接所以属性生成Hash 77 | 78 | //1、Height 转换 []byte数组 79 | heighBytes := IntToHex(block.Height) 80 | //fmt.Println(heighBytes) 81 | //2、preHash 转换 []byte数组 82 | 83 | //3、data 转换 []byte数组 84 | 85 | //4、TimesTamp 转换 []byte数组 86 | timeString := strconv.FormatInt(block.TimesTamp, 2) 87 | timeBytes := []byte(timeString) 88 | //fmt.Println(timeBytes) 89 | //5、拼接 90 | blockBytes := bytes.Join([][]byte{heighBytes, block.PreHash, block.Data, block.Hash, timeBytes}, []byte{}) 91 | // 生成hash 92 | hash := sha256.Sum256(blockBytes) 93 | 94 | block.Hash = hash[:] 95 | 96 | } 97 | -------------------------------------------------------------------------------- /part3/BLC/CLI.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | "log" 7 | "os" 8 | ) 9 | 10 | type CLI struct { 11 | } 12 | 13 | func (cli *CLI) Send(from []string, to []string, acount []string) { 14 | GetBlockChainObj().MineNewBlock(from, to, acount) 15 | } 16 | 17 | func (cli *CLI) GetBalance(from string) { 18 | GetBlockChainObj().UnUTXOs(from) 19 | } 20 | 21 | func (cli *CLI) PrintChain() { 22 | GetBlockChainObj().PrintChainIterator() 23 | } 24 | 25 | func (cli *CLI) CreatBlockChainWithGenensis(data string) { 26 | CreatBlockChainWithGenensisCLI(data) 27 | } 28 | 29 | func (cli *CLI) RUN() { 30 | 31 | isValidArgs() 32 | sendBlockCmd := flag.NewFlagSet("send", flag.ExitOnError) 33 | printChainCmd := flag.NewFlagSet("print", flag.ExitOnError) 34 | createChainCmd := flag.NewFlagSet("create", flag.ExitOnError) 35 | getBalanceCmd := flag.NewFlagSet("get", flag.ExitOnError) 36 | 37 | flagFromData := sendBlockCmd.String("from", "", "输入地址") 38 | flagToData := sendBlockCmd.String("to", "", "输出地址") 39 | flagAcountData := sendBlockCmd.String("d", "交易数据", "交易金额") 40 | flagCreateGenensisData := createChainCmd.String("a", "Genensis Block ...", "创世区块地址值") 41 | flagGetBalanceData := getBalanceCmd.String("a", "", "") 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 | case "print": 49 | err := printChainCmd.Parse(os.Args[2:]) 50 | if err != nil { 51 | log.Panic(err) 52 | } 53 | case "create": 54 | err := createChainCmd.Parse(os.Args[2:]) 55 | if err != nil { 56 | log.Panic(err) 57 | } 58 | case "get": 59 | err := getBalanceCmd.Parse(os.Args[2:]) 60 | if err != nil { 61 | log.Panic(err) 62 | } 63 | default: 64 | printUsage() 65 | os.Exit(1) 66 | } 67 | 68 | if sendBlockCmd.Parsed() { 69 | if *flagFromData == "" || *flagToData == "" || *flagAcountData == "" { 70 | printUsage() 71 | os.Exit(1) 72 | } 73 | fmt.Println(*flagFromData) 74 | fmt.Println(*flagToData) 75 | fmt.Println(*flagAcountData) 76 | cli.Send(JSONToArray(*flagFromData), JSONToArray(*flagToData), JSONToArray(*flagAcountData)) 77 | } 78 | 79 | if printChainCmd.Parsed() { 80 | fmt.Println("输出所以区块数据") 81 | cli.PrintChain() 82 | } 83 | 84 | if createChainCmd.Parsed() { 85 | if *flagCreateGenensisData == "" { 86 | printUsage() 87 | os.Exit(1) 88 | } 89 | fmt.Println(*flagCreateGenensisData) 90 | cli.CreatBlockChainWithGenensis(*flagCreateGenensisData) 91 | } 92 | 93 | if getBalanceCmd.Parsed() { 94 | if *flagGetBalanceData == "" { 95 | printUsage() 96 | os.Exit(1) 97 | } 98 | fmt.Println(*flagGetBalanceData) 99 | cli.GetBalance(*flagGetBalanceData) 100 | } 101 | } 102 | 103 | func printUsage() { 104 | fmt.Println("Usage:") 105 | fmt.Println("\tsend -from Address -to Address -d Acount") 106 | fmt.Println("\tcreate -a Address - 创世区块地址值") 107 | fmt.Println("\tget -a Address - 获取地址值的余额") 108 | fmt.Println("\tprint - 打印所有区块信息") 109 | 110 | } 111 | 112 | func isValidArgs() { 113 | if len(os.Args) < 2 { 114 | printUsage() 115 | os.Exit(1) 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /part2/BLC/BlockChain.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import ( 4 | "PublicBlackChain/part1/BLC" 5 | "fmt" 6 | "github.com/boltdb/bolt" 7 | "log" 8 | "math/big" 9 | "os" 10 | ) 11 | 12 | const dbName = "block.db" 13 | const bucketName = "blocks" 14 | 15 | type BlockChain struct { 16 | //加入db 持久存储 17 | Tip []byte //最新区块的hash 18 | DB *bolt.DB //DB 19 | } 20 | 21 | //创建创世区块链 22 | func CreatBlockChainWithGenensis() (blcokChain *BlockChain) { 23 | db, err := bolt.Open(dbName, 0600, nil) 24 | if err != nil { 25 | log.Fatal(err) 26 | } 27 | if !dbExists() { 28 | fmt.Println("创世区块已经存在...") 29 | err = db.View(func(tx *bolt.Tx) error { 30 | b := tx.Bucket([]byte(bucketName)) 31 | blockHash := b.Get([]byte("l")) 32 | blcokChain = &BlockChain{blockHash, db} 33 | return nil 34 | }) 35 | } else { 36 | var blockHash []byte 37 | err = db.Update(func(tx *bolt.Tx) error { 38 | b := tx.Bucket([]byte(bucketName)) 39 | if b == nil { 40 | b, err = tx.CreateBucket([]byte(bucketName)) 41 | if err != nil { 42 | log.Panic(err) 43 | } 44 | } 45 | genensisBlock := CreateGenensisBlock("Genensis block ...") 46 | err = b.Put([]byte(genensisBlock.Hash), genensisBlock.Serialize()) 47 | if err != nil { 48 | log.Panic(err) 49 | } 50 | blockHash = genensisBlock.Hash 51 | err = b.Put([]byte("l"), genensisBlock.Hash) 52 | blcokChain = &BlockChain{blockHash, db} 53 | if err != nil { 54 | log.Panic(err) 55 | } 56 | return nil 57 | }) 58 | if err != nil { 59 | log.Panic(err) 60 | } 61 | 62 | } 63 | defer db.Close() 64 | return blcokChain 65 | } 66 | 67 | //创建创世区块链 68 | func CreatBlockChainWithGenensisCLI(data string) { 69 | db, err := bolt.Open(dbName, 0600, nil) 70 | if err != nil { 71 | log.Fatal(err) 72 | } 73 | err = db.Update(func(tx *bolt.Tx) error { 74 | b := tx.Bucket([]byte(bucketName)) 75 | if b == nil { 76 | b, err = tx.CreateBucket([]byte(bucketName)) 77 | if err != nil { 78 | log.Panic(err) 79 | } 80 | } 81 | genensisBlock := CreateGenensisBlock(data) 82 | err = b.Put([]byte(genensisBlock.Hash), genensisBlock.Serialize()) 83 | if err != nil { 84 | log.Panic(err) 85 | } 86 | err = b.Put([]byte("l"), genensisBlock.Hash) 87 | if err != nil { 88 | log.Panic(err) 89 | } 90 | return nil 91 | }) 92 | if err != nil { 93 | log.Panic(err) 94 | } 95 | defer db.Close() 96 | 97 | } 98 | 99 | //添加到区块到DB中 100 | func (blc *BlockChain) AddBlockToBlockChain(data string) { 101 | 102 | //添加到DB中 103 | err := blc.DB.Update(func(tx *bolt.Tx) error { 104 | b := tx.Bucket([]byte(bucketName)) 105 | if b == nil { 106 | _, err := tx.CreateBucket([]byte(bucketName)) 107 | if err != nil { 108 | log.Panic(err) 109 | } 110 | } 111 | //取出最 112 | blockBytes := b.Get(blc.Tip) 113 | preBlock := BLC.DeSerializeBlock(blockBytes) 114 | //创建新区块 115 | block := NewBlock(preBlock.Height+1, preBlock.Hash, data) 116 | err := b.Put([]byte(block.Hash), block.Serialize()) 117 | if err != nil { 118 | log.Panic(err) 119 | } 120 | err = b.Put([]byte("l"), block.Hash) 121 | blc.Tip = block.Hash 122 | if err != nil { 123 | log.Panic(err) 124 | } 125 | return nil 126 | }) 127 | if err != nil { 128 | log.Panic(err) 129 | } 130 | defer blc.DB.Close() 131 | } 132 | 133 | //遍历所有区块信息 134 | func (blc *BlockChain) PrintChain() { 135 | var block *Block 136 | var currentHash []byte = blc.Tip 137 | var genensisHashBytes = big.NewInt(0) 138 | for { 139 | err := blc.DB.View(func(tx *bolt.Tx) error { 140 | b := tx.Bucket([]byte(bucketName)) 141 | if b != nil { 142 | blockBytes := b.Get(currentHash) 143 | block = DeSerializeBlock(blockBytes) 144 | fmt.Println(block) 145 | } 146 | return nil 147 | 148 | }) 149 | if err != nil { 150 | log.Panic(err) 151 | } 152 | var hashInt big.Int 153 | hashInt.SetBytes(block.PreHash) 154 | if genensisHashBytes.Cmp(&hashInt) == 0 { 155 | break 156 | } 157 | currentHash = block.PreHash 158 | } 159 | defer blc.DB.Close() 160 | } 161 | 162 | //获取blockchain对象 163 | func GetBlockChainObj() *BlockChain { 164 | db, err := bolt.Open(dbName, 0600, nil) 165 | if err != nil { 166 | log.Fatal(err) 167 | } 168 | var tipHash []byte 169 | db.View(func(tx *bolt.Tx) error { 170 | b := tx.Bucket([]byte(bucketName)) 171 | if b != nil { 172 | tipHash = b.Get([]byte("l")) 173 | 174 | } else { 175 | fmt.Println("先创建创世区块") 176 | } 177 | return nil 178 | }) 179 | return &BlockChain{tipHash, db} 180 | } 181 | 182 | //迭代器 183 | func (blc *BlockChain) Iterator() *BlockChainIterator { 184 | return &BlockChainIterator{blc.Tip, blc.DB} 185 | } 186 | 187 | //迭代遍历 188 | func (blc *BlockChain) PrintChainIterator() { 189 | blockChainIterator := blc.Iterator() 190 | defer blockChainIterator.DB.Close() 191 | var hashInt big.Int 192 | var genensis = big.NewInt(0) 193 | for { 194 | block := blockChainIterator.Next() 195 | hashInt.SetBytes(block.PreHash) 196 | fmt.Println(block) 197 | if genensis.Cmp(&hashInt) == 0 { 198 | break 199 | } 200 | } 201 | } 202 | 203 | func dbExists() bool { 204 | if _, err := os.Stat(dbName); os.IsExist(err) { 205 | return false 206 | } 207 | return true 208 | } 209 | -------------------------------------------------------------------------------- /part3/BLC/BlockChain.go: -------------------------------------------------------------------------------- 1 | package BLC 2 | 3 | import ( 4 | "PublicBlackChain/part1/BLC" 5 | "encoding/hex" 6 | "fmt" 7 | "github.com/boltdb/bolt" 8 | "log" 9 | "math/big" 10 | "os" 11 | "strconv" 12 | ) 13 | 14 | const dbName = "block.db" 15 | const bucketName = "blocks" 16 | 17 | type BlockChain struct { 18 | //加入db 持久存储 19 | Tip []byte //最新区块的hash 20 | DB *bolt.DB //DB 21 | } 22 | 23 | //创建创世区块链 24 | func CreatBlockChainWithGenensisCLI(data string) { 25 | db, err := bolt.Open(dbName, 0600, nil) 26 | if err != nil { 27 | log.Fatal(err) 28 | } 29 | err = db.Update(func(tx *bolt.Tx) error { 30 | b := tx.Bucket([]byte(bucketName)) 31 | if b == nil { 32 | b, err = tx.CreateBucket([]byte(bucketName)) 33 | if err != nil { 34 | log.Panic(err) 35 | } 36 | } 37 | //创建一个基础交易 38 | transaction := NewCoinBaseTransaction(data) 39 | genensisBlock := CreateGenensisBlock([]*Transaction{transaction}) 40 | err = b.Put([]byte(genensisBlock.Hash), genensisBlock.Serialize()) 41 | if err != nil { 42 | log.Panic(err) 43 | } 44 | err = b.Put([]byte("l"), genensisBlock.Hash) 45 | if err != nil { 46 | log.Panic(err) 47 | } 48 | return nil 49 | }) 50 | if err != nil { 51 | log.Panic(err) 52 | } 53 | defer db.Close() 54 | 55 | } 56 | 57 | //转账 58 | func (blc *BlockChain) MineNewBlock(from []string, to []string, acount []string) { 59 | //通过相关算法建立Transaction数组 60 | var txs []*Transaction 61 | 62 | value, _ := strconv.Atoi(acount[0]) 63 | //建立一笔转账 64 | for _, address := range from { 65 | tx := NewNormalTransaction(address, to[0], int64(value), txs) 66 | txs = append(txs, tx) 67 | fmt.Println(tx) 68 | } 69 | 70 | //添加到DB中 71 | err := blc.DB.Update(func(tx *bolt.Tx) error { 72 | b := tx.Bucket([]byte(bucketName)) 73 | if b == nil { 74 | _, err := tx.CreateBucket([]byte(bucketName)) 75 | if err != nil { 76 | log.Panic(err) 77 | } 78 | } 79 | //取出最顶的block 80 | blockBytes := b.Get(blc.Tip) 81 | preBlock := BLC.DeSerializeBlock(blockBytes) 82 | //创建新区块 83 | block := NewBlock(preBlock.Height+1, preBlock.Hash, txs) 84 | err := b.Put([]byte(block.Hash), block.Serialize()) 85 | if err != nil { 86 | log.Panic(err) 87 | } 88 | err = b.Put([]byte("l"), block.Hash) 89 | blc.Tip = block.Hash 90 | if err != nil { 91 | log.Panic(err) 92 | } 93 | return nil 94 | }) 95 | if err != nil { 96 | log.Panic(err) 97 | } 98 | defer blc.DB.Close() 99 | } 100 | 101 | //获取blockchain对象 102 | func GetBlockChainObj() *BlockChain { 103 | db, err := bolt.Open(dbName, 0600, nil) 104 | if err != nil { 105 | log.Fatal(err) 106 | } 107 | var tipHash []byte 108 | db.View(func(tx *bolt.Tx) error { 109 | b := tx.Bucket([]byte(bucketName)) 110 | if b != nil { 111 | tipHash = b.Get([]byte("l")) 112 | 113 | } else { 114 | fmt.Println("先创建创世区块") 115 | } 116 | return nil 117 | }) 118 | return &BlockChain{tipHash, db} 119 | } 120 | 121 | //返回该地址下所有未花费交易输出 122 | func (blc *BlockChain) UnUTXOs(address string, txs []*Transaction) []*UTXO { 123 | blockChainIterator := blc.Iterator() 124 | defer blockChainIterator.DB.Close() 125 | 126 | var unUTXOs []*UTXO 127 | 128 | var hashInt big.Int 129 | var genensis = big.NewInt(0) 130 | var spentTXOutputs = make(map[string][]int64) 131 | 132 | for _, tx := range txs { 133 | if tx.IsConbaseTransaction() == false { 134 | for _, in := range tx.Vins { 135 | if in.UnLockWithAddress(address) { 136 | key := hex.EncodeToString(in.TxHash) 137 | 138 | spentTXOutputs[key] = append(spentTXOutputs[key], in.Vout) 139 | 140 | } 141 | } 142 | } 143 | 144 | } 145 | 146 | for _, tx := range txs { 147 | work1: 148 | for index, out := range tx.Vouts { 149 | if out.UnLockWithAddress(address) { 150 | if len(spentTXOutputs) == 0 { 151 | utxo := &UTXO{tx.TxHash, int64(index), out} 152 | unUTXOs = append(unUTXOs, utxo) 153 | } else { 154 | for hash, indexArray := range spentTXOutputs { 155 | txHashStr := hex.EncodeToString(tx.TxHash) 156 | if txHashStr == hash { 157 | var isUtxo bool 158 | for _, outIndex := range indexArray { 159 | if outIndex == int64(index) { 160 | isUtxo = true 161 | continue work1 162 | } 163 | 164 | if isUtxo == false { 165 | utxo := &UTXO{tx.TxHash, int64(index), out} 166 | unUTXOs = append(unUTXOs, utxo) 167 | } 168 | } 169 | } else { 170 | utxo := &UTXO{tx.TxHash, int64(index), out} 171 | unUTXOs = append(unUTXOs, utxo) 172 | } 173 | } 174 | } 175 | 176 | } 177 | 178 | } 179 | } 180 | 181 | for { 182 | block := blockChainIterator.Next() 183 | hashInt.SetBytes(block.PreHash) 184 | fmt.Println(block) 185 | 186 | for _, tx := range block.txs { 187 | if tx.IsConbaseTransaction() == false { 188 | for _, in := range tx.Vins { 189 | if in.UnLockWithAddress(address) { 190 | key := hex.EncodeToString(in.TxHash) 191 | 192 | spentTXOutputs[key] = append(spentTXOutputs[key], in.Vout) 193 | 194 | } 195 | } 196 | } 197 | work2: 198 | for index, out := range tx.Vouts { 199 | if out.UnLockWithAddress(address) { 200 | if spentTXOutputs != nil { 201 | if len(spentTXOutputs) != 0 { 202 | var isSpentUTXO bool 203 | for txHash, indexArray := range spentTXOutputs { 204 | for _, i := range indexArray { 205 | if int64(index) == i && txHash == hex.EncodeToString(tx.TxHash) { 206 | continue work2 207 | } else { 208 | 209 | } 210 | } 211 | } 212 | if isSpentUTXO == false { 213 | utxo := &UTXO{tx.TxHash, int64(index), out} 214 | unUTXOs = append(unUTXOs, utxo) 215 | } 216 | } else { 217 | utxo := &UTXO{tx.TxHash, int64(index), out} 218 | unUTXOs = append(unUTXOs, utxo) 219 | } 220 | 221 | } 222 | } 223 | } 224 | 225 | } 226 | 227 | if genensis.Cmp(&hashInt) == 0 { 228 | break 229 | } 230 | } 231 | return unUTXOs 232 | } 233 | 234 | func (blc *BlockChain) FindSpendableUTXOS(from string, amount int64, txs []*Transaction) (int64, map[string][]int64) { 235 | 236 | //获取我所以的钱UTXO 237 | utxos := blc.UnUTXOs(from, txs) 238 | 239 | var value int64 240 | var unSpendableUTXOS = make(map[string][]int64) 241 | for _, utxo := range utxos { 242 | value = value + utxo.Output.Value 243 | hash := hex.EncodeToString(utxo.TxHash) 244 | unSpendableUTXOS[hash] = append(unSpendableUTXOS[hash], utxo.Index) 245 | 246 | if value >= amount { 247 | break 248 | } 249 | } 250 | 251 | if value < amount { 252 | fmt.Println("余额不足") 253 | os.Exit(1) 254 | } 255 | return value, unSpendableUTXOS 256 | } 257 | 258 | //查询余额 259 | func (blc *BlockChain) GetBalance(address string) (amount int64) { 260 | utxos := blc.UnUTXOs(address, nil) 261 | for _, utxo := range utxos { 262 | amount = amount + utxo.Output.Value 263 | } 264 | return 265 | } 266 | 267 | //迭代器 268 | func (blc *BlockChain) Iterator() *BlockChainIterator { 269 | return &BlockChainIterator{blc.Tip, blc.DB} 270 | } 271 | 272 | //迭代遍历 273 | func (blc *BlockChain) PrintChainIterator() { 274 | blockChainIterator := blc.Iterator() 275 | defer blockChainIterator.DB.Close() 276 | var hashInt big.Int 277 | var genensis = big.NewInt(0) 278 | for { 279 | block := blockChainIterator.Next() 280 | hashInt.SetBytes(block.PreHash) 281 | //fmt.Println(block) 282 | fmt.Println("####################################################################################") 283 | fmt.Println() 284 | fmt.Println() 285 | fmt.Println("------------------------------------------------------------------------------------") 286 | fmt.Printf("Height------>| %d\n", block.Height) 287 | fmt.Println("------------------------------------------------------------------------------------") 288 | fmt.Printf("PreHash----->| %x\n", block.PreHash) 289 | fmt.Println("------------------------------------------------------------------------------------") 290 | fmt.Printf("Hash-------->| %x\n", block.Hash) 291 | fmt.Println("------------------------------------------------------------------------------------") 292 | fmt.Printf("Nonce------->| %d\n", block.Nonce) 293 | fmt.Println("------------------------------------------------------------------------------------") 294 | fmt.Printf("TimesTamp--->| %d\n", block.TimesTamp) 295 | fmt.Println("------------------------------------------------------------------------------------") 296 | fmt.Println("*********************************-> Txs <-**************************************") 297 | for _, tx := range block.txs { 298 | fmt.Printf("Hash-------->: %x\n", tx.TxHash) 299 | for _, in := range tx.Vins { 300 | fmt.Println(in) 301 | } 302 | for _, out := range tx.Vouts { 303 | fmt.Println(out) 304 | } 305 | fmt.Println() 306 | } 307 | fmt.Println() 308 | fmt.Println() 309 | fmt.Println("####################################################################################") 310 | if genensis.Cmp(&hashInt) == 0 { 311 | break 312 | } 313 | } 314 | } 315 | --------------------------------------------------------------------------------