挖矿机源代码
block.go
package core import ( "bytes" "encoding/gob" "log" "time" ) /** * 区块结构体 */ type Block struct { Timestamp int64 PreBlockHash []byte Hash []byte Data []byte Nonce int } func (b *Block)Serialize() []byte{ var result bytes.Buffer encoder := gob.NewEncoder(&result) err := encoder.Encode(b) if err != nil { log.Panic(err) } return result.Bytes() } /** * 创建区块函数 */ func CreateNewBlock(preBlockHash []byte, data string) *Block{ //初始化数组并赋值 newBlock := &Block{time.Now().Unix(),preBlockHash,[]byte{},[]byte(data),0} //创建工作量证明 pow := NewProofOfWork(newBlock) //运行工作量证明 nonce, hash := pow.Run() newBlock.Hash = hash[:] newBlock.Nonce = nonce //newBlock.setHash() return newBlock } /** *构建创世区块函数,由于创世区块没有前驱,所以preblockhash传空 */ func CreateGenesisBlcok() *Block{ return CreateNewBlock([]byte{}, "This is the genesisblock!") }
blockchain.go
package core import ( "fmt" "github.com/boltdb/bolt" "log" ) const dbFile = "blockchain.db" const blockBucket = "blcoks" /** *区块链结构体,以文件存储的形式存放区块,理论上可以建立无数个区块 */ type Blcokchain struct { tip []byte DB *bolt.DB } /** *添加区块函数 */ func (bc *Blcokchain)AddBlock(data string){ } /** * 创建区块链,并创建创世函数 */ func CreateNewBlcokchain() *Blcokchain{ var tip []byte db, err := bolt.Open(dbFile, 0600, nil) if err != nil { log.Panic(err) } err = db.Update(func(tx *bolt.Tx) error { b := tx.Bucket([]byte(blockBucket)) if b == nil { fmt.Println("No existing blockchain found. Create a new one ...") genesis := CreateGenesisBlcok() b, err := tx.CreateBucket([]byte(blockBucket)) if err != nil { log.Panic(err) } err = b.Put(genesis.Hash, genesis.Serialize()) if err != nil { log.Panic(err) } err = b.Put([]byte("1"), genesis.Hash) if err != nil { log.Panic(err) } tip = genesis.Hash }else { tip = b.Get([]byte("1")) } return nil }) if err != nil { log.Panic(err) } bc := Blcokchain{tip, db} return &bc }
cli.go
package core import ( "flag" "fmt" "log" "os" ) type CLI struct { Bc *Blcokchain } func (cli *CLI)showUsage() { fmt.Println("Usage:") fmt.Println(" addblock -data BLOCK_DATA *add a blcok to blockchain") fmt.Println(" showchain *show all the blocks of the blcokchain") } func (cli *CLI)validateArgs() { if len(os.Args) < 2 { cli.showUsage() os.Exit(1) } } func (cli *CLI) addBlock(data string){ cli.Bc.AddBlock(data) fmt.Println("Success!") } func (cli *CLI) showBlcokchain(){ } func (cli *CLI)Run() { cli.validateArgs() addBlockCmd := flag.NewFlagSet("addBlcok", flag.ExitOnError) showBlockchainCmd := flag.NewFlagSet("showBlockchain", flag.ExitOnError) addBlockData := addBlockCmd.String("data", "", "Block data") switch os.Args[1] { case "addBlock": err := addBlockCmd.Parse(os.Args[2:]) if err != nil { log.Panic(err) } case "showBlockchain": err := showBlockchainCmd.Parse(os.Args[2:]) if err != nil { log.Panic(err) } default: cli.showUsage() os.Exit(1) } if addBlockCmd.Parsed() { if *addBlockData == "" { addBlockCmd.Usage() os.Exit(1) } cli.addBlock(*addBlockData) } if showBlockchainCmd.Parsed() { cli.showUsage() } }
proofofwork.go
package core import ( "bytes" "crypto/sha256" "fmt" "math" "math/big" ) var ( //定义工作量证明最大值为64位整数的最大值 maxNonce = math.MaxInt64 ) //目标 const targetBits = 20 //定义工作量结构体 type ProofOfWork struct { //被计算的区块 block *Block //目标,对区块计算要满足这个目标 target *big.Int } /** * 创建工作量证明函数 */ func NewProofOfWork(b *Block) *ProofOfWork { target := big.NewInt(1) //对整数target前面的比特位进行移位操作,因为target是1,移位后前面的字节变为0 target.Lsh(target, uint(256 - targetBits)) //创建工作量证明并返回 pow := &ProofOfWork{b,target} return pow } /** *运行工作量证明的过程 */ func (pow *ProofOfWork)Run() (int, []byte) { var hashInt big.Int var hash [32]byte nonce := 0 //提示,显示这个区块值 fmt.Printf("Mining the block containing\"%s\"\n ", pow.block.Data) //通过循环反复计算 for nonce < maxNonce { //获取拼装好的byte数组格式的数据块 data := pow.prepareData(nonce) //对数据块进行加密返回byte字节数组 hash = sha256.Sum256(data) //显示这个hash值 fmt.Printf("\r%x", hash) //将hash转换为hash整数 hashInt.SetBytes(hash[:]) //使用这个hash整数与target进行对比 if hashInt.Cmp(pow.target) == -1{ break }else { nonce ++ } } fmt.Printf("\n\n") return nonce, hash[:] } //将各个数据拼凑大数据返回byte数组 func (pow *ProofOfWork)prepareData(nonce int) []byte{ data := bytes.Join( [][]byte{ pow.block.PreBlockHash, pow.block.Data, IntToHex(pow.block.Timestamp), IntToHex(int64(targetBits)), //nonce为可变值,所以循环中每轮的hash都不同 IntToHex(int64(nonce)), }, []byte{}, ) return data } func (pow *ProofOfWork)Validate() bool{ var hashInt big.Int data := pow.prepareData(pow.block.Nonce) hash := sha256.Sum256(data) hashInt.SetBytes(hash[:]) isValidate := hashInt.Cmp(pow.target) == -1 return isValidate }
package core import ( "bytes" "encoding/binary" "log" ) // 将一个 int64 转化为一个字节数组(byte array) func IntToHex(num int64) []byte { buff := new(bytes.Buffer) err := binary.Write(buff, binary.BigEndian, num) if err != nil { log.Panic(err) } return buff.Bytes() }