├── network ├── network_instant.go ├── README.md └── net.go ├── block ├── blockchain_instant.go ├── constant.go ├── README.md ├── block_test.go ├── transaction_test.go ├── blockchain_test.go ├── transaction.go ├── block.go └── blockchain.go ├── bitcoinLiteLite ├── consensus ├── README.md ├── pow.go ├── hash.go ├── uint256.go ├── target.go └── target_test.go ├── crypto ├── constant.go ├── README.md ├── key_test.go ├── key.go └── base58.go ├── message ├── README.md ├── constant.go └── message.go ├── .gitignore ├── blockchainuser └── user.go ├── LICENSE ├── README.md ├── tool └── tool.go └── main.go /network/network_instant.go: -------------------------------------------------------------------------------- 1 | package network 2 | 3 | var NetworkInstant *Network 4 | -------------------------------------------------------------------------------- /block/blockchain_instant.go: -------------------------------------------------------------------------------- 1 | package block 2 | 3 | var BlockChainInstant *BlockChain 4 | -------------------------------------------------------------------------------- /bitcoinLiteLite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonsenssylvain/bitcoinLiteLite/HEAD/bitcoinLiteLite -------------------------------------------------------------------------------- /consensus/README.md: -------------------------------------------------------------------------------- 1 | ### 共识算法 POW 2 | 3 | *** 4 | 5 | POW算法:节点根据一定规则产生HASH数据,系统设置prefixToMatch,根据不同难度需求调整prefixToMatch -------------------------------------------------------------------------------- /crypto/constant.go: -------------------------------------------------------------------------------- 1 | package crypto 2 | 3 | const ( 4 | SignRLen = 28 5 | SignSLen = 28 6 | PublicKeyLen = 230 7 | ) 8 | -------------------------------------------------------------------------------- /message/README.md: -------------------------------------------------------------------------------- 1 | # Message 2 | 3 | *** 4 | 5 | * 用于不同节点传递消息 6 | * 目前用于: 7 | * 发起交易,传递给其他节点 8 | * 收到交易,验证交易合法,发回确认消息 9 | * 打包Block,广播给其他及诶按 10 | * 收到Block,验证POW合法, 发回确认写入消息 -------------------------------------------------------------------------------- /message/constant.go: -------------------------------------------------------------------------------- 1 | package message 2 | 3 | const ( 4 | MessageTypeSendTransaction = 1 5 | MessageTypeSendBlock = 2 6 | MessageTypeConfirmTransaction = 3 7 | MessageTypeConfirmBlock = 4 8 | MessageTypePort = 9 9 | 10 | MessageTypeSize = 1 11 | ) 12 | -------------------------------------------------------------------------------- /consensus/pow.go: -------------------------------------------------------------------------------- 1 | package consensus 2 | 3 | import ( 4 | "reflect" 5 | ) 6 | 7 | //CheckProofOfWork 确认POW是否匹配 8 | func CheckProofOfWork(prefixToMatch []byte, hash []byte) bool { 9 | if len(prefixToMatch) > 0 { 10 | return reflect.DeepEqual(prefixToMatch, hash[:len(prefixToMatch)]) 11 | } 12 | return true 13 | } 14 | -------------------------------------------------------------------------------- /network/README.md: -------------------------------------------------------------------------------- 1 | * Node 2 | * Net 连接实例 3 | * ConnectTime 获取连接的时间 4 | 5 | * Network 6 | * Nodes 当前节点连接的所有外部节点 7 | * ConnectionChan 新的连接接入,通过该chan触发处理机制 8 | * Address 当前节点的地址 9 | * NodeCallback 新的节点连接完成,调用该chan 10 | * BroadCastChan 当前节点产生的Message丢入该chan,该chan会广播 11 | * IncomingChan 如果接收到外部消息,丢入到该chan -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files, Static and Dynamic libs (Shared Objects) 2 | *.o 3 | *.a 4 | *.so 5 | 6 | # Folders 7 | _obj 8 | _test 9 | 10 | # Architecture specific extensions/prefixes 11 | *.[568vq] 12 | [568vq].out 13 | 14 | *.cgo1.go 15 | *.cgo2.c 16 | _cgo_defun.c 17 | _cgo_gotypes.go 18 | _cgo_export.* 19 | 20 | _testmain.go 21 | 22 | *.exe 23 | *.test 24 | *.prof 25 | -------------------------------------------------------------------------------- /blockchainuser/user.go: -------------------------------------------------------------------------------- 1 | package blockchainuser 2 | 3 | import ( 4 | "github.com/jasoncodingnow/bitcoinLiteLite/crypto" 5 | ) 6 | 7 | var key *crypto.Key 8 | 9 | //GetKey 获取当前用户私钥公钥 10 | func GetKey() *crypto.Key { 11 | if key == nil || key.PrivateKey == "" { 12 | key = crypto.GenerateKey() 13 | } 14 | return key 15 | } 16 | 17 | func SetKey(k *crypto.Key) { 18 | key = k 19 | } 20 | -------------------------------------------------------------------------------- /crypto/README.md: -------------------------------------------------------------------------------- 1 | ### 椭圆加密算法 crypto/key.go 2 | 3 | 贴上一篇介绍: [椭圆加密算法](http://blog.csdn.net/qq_30866297/article/details/51175305 "") 4 | 5 | *** 6 | 7 | 在blockchain中,该算法主要用于公钥和私钥。当各个节点接受到数据的时候,需要拿出该transaction的owner的公钥,对交易内容进行验证,验证成功则说明的的确确是该owner发起的交易。 8 | 9 | 所以目前程序里面的逻辑是: 10 | 11 | 1. 用户初始化的时候,分配给该用户一个公钥和私钥。bitcoin里面一个私钥对应着多个公钥,并且是base58编码,golang原生并不是(或者我没看到,谁给解答下),所以暂时就一个公钥一个私钥。后期会考虑用上 secp256k1 方案。 12 | 13 | 2. 用户签名的时候,用私钥签名,验证的时候,用的是公钥验证。因为不同的用户是不会拥有对方的私钥的。 14 | 15 | 3. 公钥和私钥都是采用base58编码,[base58编码](https://zh.wikipedia.org/zh-hans/Base58 "") -------------------------------------------------------------------------------- /block/constant.go: -------------------------------------------------------------------------------- 1 | package block 2 | 3 | import "github.com/jasoncodingnow/bitcoinLiteLite/crypto" 4 | 5 | const PayloadHashSize = 80 6 | const TransactionSignatureSize = 80 7 | 8 | const TransactionHeaderSize = crypto.PublicKeyLen + crypto.PublicKeyLen + PayloadHashSize + 4 + 4 + 4 9 | 10 | const MaxInt = int(^uint(0) >> 1) 11 | 12 | const BlockSignatureSize = 80 13 | const MerkleRootSize = 80 14 | const BlockHeaderSize = crypto.PublicKeyLen + BlockSignatureSize + MerkleRootSize + 4 + 4 15 | 16 | var BlockPowPrefix = 2 // 该参数应该随着难度调整,打包的难度 17 | var TransactionPowPrefix = 1 // 交易的难度,这个目前应该没什么太大用处 18 | 19 | const PackageTimespan = 1 //1分钟打一个block 20 | -------------------------------------------------------------------------------- /crypto/key_test.go: -------------------------------------------------------------------------------- 1 | package crypto 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | ) 7 | 8 | func Test_All(t *testing.T) { 9 | 10 | keypair := GenerateKey() 11 | fmt.Println(string(keypair.PrivateKey)) 12 | fmt.Println(len(keypair.PrivateKey)) 13 | fmt.Println(string(keypair.PublicKey)) 14 | fmt.Println(len(keypair.PublicKey)) 15 | message := "fwfwwwwwwwfooooooooooooooooooo33333wf" 16 | signature, _ := Sign([]byte(message), keypair.PrivateKey) 17 | fmt.Println(string(signature)) 18 | fmt.Println(len(signature)) 19 | result := Verify([]byte(message), signature, keypair.PublicKey) 20 | fmt.Println(result) 21 | 22 | // a := 1 23 | 24 | // buf := bytes.Buffer{} 25 | // binary.Write(&buf, binary.BigEndian, a) 26 | // fmt.Println(buf.Bytes()) 27 | 28 | // var newB = make([]byte, 4) 29 | // binary.LittleEndian.PutUint32(newB, uint32(a)) 30 | // fmt.Println(newB) 31 | 32 | // b := int(binary.LittleEndian.Uint32(newB)) 33 | // fmt.Println(b) 34 | } 35 | -------------------------------------------------------------------------------- /message/message.go: -------------------------------------------------------------------------------- 1 | package message 2 | 3 | import ( 4 | "bytes" 5 | "encoding/binary" 6 | "errors" 7 | ) 8 | 9 | type Message struct { 10 | Type int 11 | Data []byte 12 | Reply chan Message // Message到达之后,可能需要根据该Channel返回确认消息 13 | } 14 | 15 | func NewMessage(messageType int) (*Message, error) { 16 | m := &Message{} 17 | if messageType != MessageTypeConfirmBlock && 18 | messageType != MessageTypeConfirmTransaction && 19 | messageType != MessageTypeSendBlock && 20 | messageType != MessageTypeSendTransaction && 21 | messageType != MessageTypePort { 22 | return m, errors.New("type error") 23 | } 24 | m.Type = messageType 25 | return m, nil 26 | } 27 | 28 | func (m *Message) MarshalBinary() []byte { 29 | var newB = make([]byte, 4) 30 | binary.LittleEndian.PutUint32(newB, uint32(m.Type)) 31 | 32 | buf := &bytes.Buffer{} 33 | buf.Write(newB) 34 | buf.Write(m.Data) 35 | return buf.Bytes() 36 | } 37 | 38 | func (m *Message) UnmarshalBinary(data []byte) { 39 | buf := bytes.NewBuffer(data) 40 | m.Type = int(binary.LittleEndian.Uint32(buf.Next(4))) 41 | m.Data = buf.Next(len(data) - 1) 42 | return 43 | } 44 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Jason 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /block/README.md: -------------------------------------------------------------------------------- 1 | ### btc的几个内容: transaction, block 2 | 3 | *** 4 | 5 | #### 流程 6 | 7 | * BlockChain,有个属性 Block,该属性放的是当前持有的Block,还未写入到Chain里。当符合一定条件,目前设定是5个Block或者十分钟到了数量还未到5个,就打包。 8 | * 打包的时候有个注意事项,因为打包的BLock可能是自己产生的,也可能是别人产生的,所以很可能打包进入的Block里的Transaction与自己当前的Block里的Transaction不相同,所以需要取出不同放到下一个Block 9 | 10 | ##### Transaction 11 | 12 | * Header: 13 | * From 从哪个地址发出 14 | * To 发到哪个地址 15 | * PayloadHash 对交易内容进行SHA256 16 | * PayloadLen 交易内容的长度,用于最终解码 17 | * Timestamp 交易产生时间 18 | * Nonce 可以理解为不断递增的数字,用于跟交易内容合并,产生HASH,然后匹配是否符合POW 19 | 20 | * Transaction: 21 | * Header 交易Header 22 | * Signature 交易发起者使用私钥进行签名 23 | * Payload 交易内容 24 | 25 | #### Block 26 | 27 | * BlockHeader 28 | * Origin 打包者的地址/公钥 29 | * PrevBlock 上一个Block的地址 30 | * MerkleRoot 包含的交易形成的Merkle 31 | * Timestamp 打包时间 32 | * Nonce 可以理解为不断递增的数字,用于跟交易内容合并,产生HASH,然后匹配是否符合POW 33 | 34 | * Block 35 | * Header 包的具体内容 36 | * Signature 打包者用自己私钥对当前的block的Hash进行签名 37 | * Transactions 该区块包含的所有transaction 38 | 39 | #### BlockChain 40 | 41 | * BlockChain 42 | * Block 当前所持有的Block,还未写入到BlockSlice里 43 | * BlockSlice 当前的Blockchain 44 | * BlockChan 接收外界产生的以及自己产生的Block的channel 45 | * TransactionChan 接收外界或者自己产生的Transaction -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # bitcoinLiteLite 2 | a simple crypto currency implementation like bitcoin 3 | 4 | *** 5 | * doc 6 | * [block](https://github.com/jasoncodingnow/bitcoinLiteLite/blob/master/block/README.md "") 7 | * [crypto](https://github.com/jasoncodingnow/bitcoinLiteLite/blob/master/crypto/README.md "") 8 | * [consensus](https://github.com/jasoncodingnow/bitcoinLiteLite/blob/master/consensus/README.md "") 9 | * [network](https://github.com/jasoncodingnow/bitcoinLiteLite/blob/master/network/README.md "") 10 | 11 | *** 12 | 13 | * 说明: 14 | * 该项目是基于bitcoin的设计来写的,目前v0.1.0目标是完成一个最小的可运行的bitcoin网络 15 | 16 | *** 17 | 18 | #### 运行 19 | 20 | 目前暂定首个节点 端口是 8091,在代码 https://github.com/jasoncodingnow/bitcoinLiteLite/blob/master/main.go L 110,请自行修改为当前机器的局域网地址 21 | 22 | ```GO 23 | git clone https://github.com/jasoncodingnow/bitcoinLiteLite.git 24 | cd github.com/jasoncodingnow/bitcoinLiteLite 25 | 26 | go build . 27 | // 启动第一个节点 28 | ./bitcoinLiteLite port 8091 29 | // 查看console可以看到第一个节点的 publicKey, 假设是 8091PUBLISKEY 30 | 31 | // 启动第二个节点 32 | ./bitcoinLiteLite port 8092 33 | 34 | // 测试 由第二个节点生成一笔Transaction,并广播 35 | // 目前,5个Transaction会打包,或者比如1个Transaction,会在1分钟内打包 36 | // 在第二个节点的console输入Transaction命令。第一个参数是要传播给谁,第二个参数是消息是什么 37 | 8091PUBLISKEY hi 38 | 39 | // 等待一分钟打包 40 | 41 | ``` 42 | 43 | 44 | -------------------------------------------------------------------------------- /consensus/hash.go: -------------------------------------------------------------------------------- 1 | package consensus 2 | 3 | import ( 4 | "crypto/sha256" 5 | 6 | "golang.org/x/crypto/ripemd160" 7 | ) 8 | 9 | func ShaHash(b []byte, out []byte) { 10 | s := sha256.New() 11 | s.Write(b[:]) 12 | tmp := s.Sum(nil) 13 | s.Reset() 14 | s.Write(tmp) 15 | copy(out[:], s.Sum(nil)) 16 | } 17 | 18 | // Returns hash: SHA256( SHA256( data ) ) 19 | // Where possible, using ShaHash() should be a bit faster 20 | func Sha2Sum(b []byte) (out [32]byte) { 21 | ShaHash(b, out[:]) 22 | return 23 | } 24 | 25 | func RimpHash(in []byte, out []byte) { 26 | sha := sha256.New() 27 | sha.Write(in) 28 | rim := ripemd160.New() 29 | rim.Write(sha.Sum(nil)[:]) 30 | copy(out, rim.Sum(nil)) 31 | } 32 | 33 | // Returns hash: RIMP160( SHA256( data ) ) 34 | // Where possible, using RimpHash() should be a bit faster 35 | func Rimp160AfterSha256(b []byte) (out [20]byte) { 36 | RimpHash(b, out[:]) 37 | return 38 | } 39 | 40 | // This function is used to sign and verify messages using the bitcoin standard. 41 | // The second paramater must point to a 32-bytes buffer, where hash will be stored. 42 | // func HashFromMessage(msg []byte, out []byte) { 43 | // b := new(bytes.Buffer) 44 | // WriteVlen(b, uint64(len(MessageMagic))) 45 | // b.Write([]byte(MessageMagic)) 46 | // WriteVlen(b, uint64(len(msg))) 47 | // b.Write(msg) 48 | // ShaHash(b.Bytes(), out) 49 | // } 50 | -------------------------------------------------------------------------------- /consensus/uint256.go: -------------------------------------------------------------------------------- 1 | package consensus 2 | 3 | import ( 4 | "bytes" 5 | "encoding/hex" 6 | "fmt" 7 | "math/big" 8 | ) 9 | 10 | const Uint256IdxLen = 8 // The bigger it is, the more memory is needed, but lower chance of a collision 11 | 12 | type Uint256 struct { 13 | Hash [32]byte 14 | } 15 | 16 | func NewUint256(h []byte) (res *Uint256) { 17 | res = new(Uint256) 18 | copy(res.Hash[:], h) 19 | return 20 | } 21 | 22 | // Get from MSB hexstring 23 | func NewUint256FromString(s string) (res *Uint256) { 24 | d, e := hex.DecodeString(s) 25 | if e != nil { 26 | println("NewUint256FromString", s, e.Error()) 27 | return 28 | } 29 | if len(d) != 32 { 30 | println("NewUint256FromString", s, "not 32 bytes long") 31 | return 32 | } 33 | res = new(Uint256) 34 | for i := 0; i < 32; i++ { 35 | res.Hash[31-i] = d[i] 36 | } 37 | return 38 | } 39 | 40 | func NewSha2Hash(data []byte) (res *Uint256) { 41 | res = new(Uint256) 42 | ShaHash(data, res.Hash[:]) 43 | return 44 | } 45 | 46 | func (u *Uint256) Bytes() []byte { 47 | return u.Hash[:] 48 | } 49 | 50 | func (u *Uint256) String() (s string) { 51 | for i := 0; i < 32; i++ { 52 | s += fmt.Sprintf("%02x", u.Hash[31-i]) 53 | } 54 | return 55 | } 56 | 57 | func (u *Uint256) Equal(o *Uint256) bool { 58 | return bytes.Equal(u.Hash[:], o.Hash[:]) 59 | } 60 | 61 | func (u *Uint256) BIdx() (o [Uint256IdxLen]byte) { 62 | copy(o[:], u.Hash[:Uint256IdxLen]) 63 | return 64 | } 65 | 66 | func (u *Uint256) BigInt() *big.Int { 67 | var buf [32]byte 68 | for i := range buf { 69 | buf[i] = u.Hash[31-i] 70 | } 71 | return new(big.Int).SetBytes(buf[:]) 72 | } 73 | -------------------------------------------------------------------------------- /consensus/target.go: -------------------------------------------------------------------------------- 1 | package consensus 2 | 3 | import ( 4 | "fmt" 5 | "math/big" 6 | ) 7 | 8 | func SetCompact(nCompact uint32) (res *big.Int) { 9 | size := nCompact >> 24 10 | neg := (nCompact & 0x00800000) != 0 11 | word := nCompact & 0x007fffff 12 | if size <= 3 { 13 | word >>= 8 * (3 - size) 14 | res = big.NewInt(int64(word)) 15 | } else { 16 | res = big.NewInt(int64(word)) 17 | res.Lsh(res, uint(8*(size-3))) 18 | } 19 | if neg { 20 | res.Neg(res) 21 | } 22 | return res 23 | } 24 | 25 | func GetDifficulty(bits uint32) (diff float64) { 26 | shift := int(bits>>24) & 0xff 27 | fmt.Println(shift) 28 | diff = float64(0x0000ffff) / float64(bits&0x00ffffff) 29 | for shift < 29 { 30 | diff *= 256.0 31 | shift++ 32 | } 33 | for shift > 29 { 34 | diff /= 256.0 35 | shift-- 36 | } 37 | return 38 | } 39 | 40 | func GetCompact(b *big.Int) uint32 { 41 | 42 | size := uint32(len(b.Bytes())) 43 | fmt.Println("size is ") 44 | fmt.Println(size) 45 | var compact uint32 46 | 47 | if size <= 3 { 48 | compact = uint32(b.Int64() << uint(8*(3-size))) 49 | } else { 50 | b = new(big.Int).Rsh(b, uint(8*(size-3))) 51 | fmt.Println("new b is ") 52 | fmt.Println(b) 53 | compact = uint32(b.Int64()) 54 | } 55 | 56 | // The 0x00800000 bit denotes the sign. 57 | // Thus, if it is already set, divide the mantissa by 256 and increase the exponent. 58 | if (compact & 0x00800000) != 0 { 59 | compact >>= 8 60 | size++ 61 | } 62 | compact |= size << 24 63 | if b.Cmp(big.NewInt(0)) < 0 { 64 | compact |= 0x00800000 65 | } 66 | return compact 67 | } 68 | 69 | func POWCheckProofOfWork(hash *Uint256, bits uint32) bool { 70 | return hash.BigInt().Cmp(SetCompact(bits)) <= 0 71 | } 72 | -------------------------------------------------------------------------------- /tool/tool.go: -------------------------------------------------------------------------------- 1 | package tool 2 | 3 | import ( 4 | "crypto/rand" 5 | "crypto/sha256" 6 | "net" 7 | "os" 8 | "time" 9 | ) 10 | 11 | //FillBytesToFront 把数据截取/填充到指定长度 12 | func FillBytesToFront(data []byte, totalLen int) []byte { 13 | if len(data) < totalLen { 14 | delta := totalLen - len(data) 15 | appendByte := []byte{} 16 | for delta != 0 { 17 | appendByte = append(appendByte, 0) 18 | delta-- 19 | } 20 | return append(appendByte, data...) 21 | } 22 | return data[:totalLen] 23 | } 24 | 25 | //SHA256 对数据进行SHA256 Hash 26 | func SHA256(data []byte) []byte { 27 | hash := sha256.New() 28 | hash.Write(data) 29 | return hash.Sum(nil) 30 | } 31 | 32 | //SliceByteWhenEncount 如果遇到了 33 | func SliceByteWhenEncount(d []byte, encount byte) []byte { 34 | for i, bb := range d { 35 | if bb != encount { 36 | return d[i:] 37 | } 38 | } 39 | return nil 40 | } 41 | 42 | //RandomString 产生随机字符串 43 | func RandomString(n int) string { 44 | alphanum := "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" 45 | var bytes = make([]byte, n) 46 | rand.Read(bytes) 47 | for i, b := range bytes { 48 | bytes[i] = alphanum[b%byte(len(alphanum))] 49 | } 50 | return string(bytes) 51 | } 52 | 53 | //GenerateBytes 根据长度和每个byte的数据,产生bytes 54 | func GenerateBytes(length int, b byte) []byte { 55 | bytes := []byte{} 56 | for length != 0 { 57 | bytes = append(bytes, b) 58 | length-- 59 | } 60 | return bytes 61 | } 62 | 63 | //Timeout 定时任务,时间到触发channel 64 | func Timeout(t time.Duration) chan bool { 65 | i := make(chan bool) 66 | go func() { 67 | time.Sleep(t) 68 | i <- true 69 | }() 70 | return i 71 | } 72 | 73 | //GetIpAddress 获取当前ip 74 | func GetIpAddress() ([]string, error) { 75 | name, err := os.Hostname() 76 | if err != nil { 77 | return nil, err 78 | } 79 | addrs, err := net.LookupHost(name) 80 | if err != nil { 81 | return nil, err 82 | } 83 | return addrs, nil 84 | } 85 | -------------------------------------------------------------------------------- /consensus/target_test.go: -------------------------------------------------------------------------------- 1 | package consensus 2 | 3 | import ( 4 | // "fmt" 5 | "fmt" 6 | "math/big" 7 | "testing" 8 | ) 9 | 10 | type onevec struct { 11 | b uint32 12 | e string 13 | d float64 14 | } 15 | 16 | var testvecs = []onevec{ 17 | {b: 0x1D00FFFF, e: "00000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"}, 18 | {b: 0x1b0404cb, e: "00000000000404CB000000000000000000000000000000000000000000000000"}, 19 | {b: 0x1d00ffff, e: "00000000FFFF0000000000000000000000000000000000000000000000000000"}, 20 | {b: 436330132, d: 8974296.01488785}, 21 | {b: 436543292, d: 3275464.59}, 22 | {b: 436591499, d: 2864140.51}, 23 | {b: 436841986, d: 1733207.51}, 24 | {b: 437155514, d: 1159929.50}, 25 | {b: 436789733, d: 1888786.71}, 26 | {b: 453031340, d: 92347.59}, 27 | {b: 453281356, d: 14484.16}, 28 | {b: 470771548, d: 16.62}, 29 | {b: 486604799, d: 1.00}, 30 | } 31 | 32 | func TestTarget(t *testing.T) { 33 | yd, _ := new(big.Int).SetString(testvecs[0].e, 16) 34 | cs := GetCompact(yd) 35 | fmt.Println(cs) 36 | 37 | fmt.Println("=====================") 38 | // for i := range testvecs { 39 | // fmt.Println(testvecs[i].b) 40 | // x := SetCompact(testvecs[i].b) 41 | // fmt.Println(x) 42 | // fmt.Println(x.Bits()) 43 | // d := GetDifficulty(testvecs[i].b) 44 | // fmt.Println(d) 45 | // c := GetCompact(x) 46 | // fmt.Println(c) 47 | // //fmt.Printf("%d. %d/%d -> %.8f / %.8f\n", i, testvecs[i].b, c, d, testvecs[i].d) 48 | // if testvecs[i].b != c { 49 | // t.Error("Set/GetCompact mismatch at alement", i) 50 | // } 51 | 52 | // if testvecs[i].e != "" { 53 | // y, _ := new(big.Int).SetString(testvecs[i].e, 16) 54 | // if x.Cmp(y) != 0 { 55 | // t.Error("Target mismatch at alement", i) 56 | // } 57 | // } 58 | 59 | // if testvecs[i].d != 0 && math.Abs(d-testvecs[i].d) > 0.1 { 60 | // t.Error("Difficulty mismatch at alement", i) 61 | // } 62 | // } 63 | } 64 | -------------------------------------------------------------------------------- /crypto/key.go: -------------------------------------------------------------------------------- 1 | package crypto 2 | 3 | import ( 4 | "crypto/ecdsa" 5 | "crypto/elliptic" 6 | "crypto/rand" 7 | "crypto/x509" 8 | "encoding/pem" 9 | "math/big" 10 | 11 | "bytes" 12 | 13 | "github.com/jasoncodingnow/bitcoinLiteLite/tool" 14 | ) 15 | 16 | type Key struct { 17 | PrivateKey string 18 | PublicKey string 19 | } 20 | 21 | var b58 = NewBitcoinBase58() 22 | 23 | //GenerateKey 生成对应的公钥和私钥 24 | func GenerateKey() *Key { 25 | key := &Key{} 26 | pk, _ := ecdsa.GenerateKey(elliptic.P224(), rand.Reader) 27 | x509encoded, _ := x509.MarshalECPrivateKey(pk) 28 | key.PrivateKey, _ = b58.EncodeToString(pem.EncodeToMemory(&pem.Block{Type: "EC PRIVATE KEY", Bytes: x509encoded})) 29 | 30 | x509encodedpub, _ := x509.MarshalPKIXPublicKey(&pk.PublicKey) 31 | key.PublicKey, _ = b58.EncodeToString(pem.EncodeToMemory(&pem.Block{Type: "EC PUBLIC KEY", Bytes: x509encodedpub})) 32 | return key 33 | } 34 | 35 | //Sign 通过私钥对数据进行签名 36 | func Sign(payload []byte, privateKey string) (string, error) { 37 | pk, _ := b58.DecodeString(privateKey) 38 | block, _ := pem.Decode(pk) 39 | x509encoded := block.Bytes 40 | realPrivateKey, err := x509.ParseECPrivateKey(x509encoded) 41 | if err != nil { 42 | return "", err 43 | } 44 | r, s, err := ecdsa.Sign(rand.Reader, realPrivateKey, payload) 45 | rBytes := tool.FillBytesToFront(r.Bytes(), SignRLen) 46 | sBytes := tool.FillBytesToFront(s.Bytes(), SignSLen) 47 | signature := append(rBytes, sBytes...) 48 | 49 | return b58.EncodeToString(signature) 50 | } 51 | 52 | //Verify 验证签名对否 53 | func Verify(payload []byte, signature string, publicKey string) bool { 54 | pk, _ := b58.DecodeString(publicKey) 55 | 56 | blockPub, _ := pem.Decode(pk) 57 | x509EncodedPub := blockPub.Bytes 58 | genericPublicKey, _ := x509.ParsePKIXPublicKey(x509EncodedPub) 59 | genericPublicKeyA := genericPublicKey.(*ecdsa.PublicKey) 60 | 61 | sign, _ := b58.DecodeString(signature) 62 | buf := bytes.NewBuffer(sign) 63 | rBytes := new(big.Int).SetBytes(buf.Next(SignRLen)) 64 | sBytes := new(big.Int).SetBytes(buf.Next(SignSLen)) 65 | verifystatus := ecdsa.Verify(genericPublicKeyA, payload, rBytes, sBytes) 66 | return verifystatus 67 | } 68 | -------------------------------------------------------------------------------- /block/block_test.go: -------------------------------------------------------------------------------- 1 | package block 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | 7 | "github.com/jasoncodingnow/bitcoinLiteLite/crypto" 8 | "github.com/jasoncodingnow/bitcoinLiteLite/tool" 9 | ) 10 | 11 | func Test_Block(t *testing.T) { 12 | 13 | fmt.Println("Test_Block start") 14 | key := crypto.GenerateKey() 15 | t1 := NewTransaction([]byte(key.PublicKey), nil, []byte(tool.RandomString(100))) 16 | t2 := NewTransaction([]byte(key.PublicKey), nil, []byte(tool.RandomString(100))) 17 | t3 := NewTransaction([]byte(key.PublicKey), nil, []byte(tool.RandomString(100))) 18 | t4 := NewTransaction([]byte(key.PublicKey), nil, []byte(tool.RandomString(100))) 19 | t5 := NewTransaction([]byte(key.PublicKey), nil, []byte(tool.RandomString(100))) 20 | t6 := NewTransaction([]byte(key.PublicKey), nil, []byte(tool.RandomString(100))) 21 | t7 := NewTransaction([]byte(key.PublicKey), nil, []byte(tool.RandomString(100))) 22 | 23 | b := NewBlock(nil) 24 | b.Header.Origin = []byte(key.PublicKey) 25 | b.Transactions = &TransactionSlice{*t1, *t2, *t3, *t4, *t5, *t6, *t7} 26 | 27 | prefixMatch := tool.GenerateBytes(1, 0) 28 | 29 | b.Header.MerkleRoot = b.GenrateMerkleRoot() 30 | b.GenerateNonce(prefixMatch) 31 | b.Signature = b.Sign(key.PrivateKey) 32 | 33 | verifyResult := b.VerifyBlock(prefixMatch) 34 | fmt.Println(verifyResult) 35 | 36 | blockBytes, err := b.MarshalBinary() 37 | fmt.Println("len of blockBytes") 38 | fmt.Println(len(blockBytes)) 39 | if err != nil { 40 | fmt.Println(err) 41 | } 42 | newBlock := NewBlock(nil) 43 | newBlock.UnmarshalBinary(blockBytes) 44 | 45 | //对比 46 | fmt.Println("block Merkle Root ") 47 | fmt.Println(b.Header.MerkleRoot) 48 | fmt.Println("newBlock Merkle Root ") 49 | fmt.Println(newBlock.Header.MerkleRoot) 50 | 51 | fmt.Println("block Origin ") 52 | fmt.Println(len(b.Header.Origin)) 53 | fmt.Println(b.Header.Origin) 54 | fmt.Println("newBlock Origin ") 55 | fmt.Println(newBlock.Header.Origin) 56 | 57 | fmt.Println("block PrevBlock ") 58 | fmt.Println(len(b.Header.PrevBlock)) 59 | fmt.Println(b.Header.PrevBlock) 60 | fmt.Println("newBlock PrevBlock ") 61 | fmt.Println(newBlock.Header.PrevBlock) 62 | } 63 | -------------------------------------------------------------------------------- /block/transaction_test.go: -------------------------------------------------------------------------------- 1 | package block 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func Test_All(t *testing.T) { 8 | // key := crypto.GenerateKey() 9 | // transaction := NewTransaction([]byte(key.PublicKey), nil, []byte(tool.RandomString(100))) 10 | 11 | // // 模拟难度 12 | // prefixMatch := tool.GenerateBytes(1, 0) 13 | // transaction.Header.Nonce = transaction.GenerateNonce(prefixMatch) 14 | // transaction.Signature = transaction.Sign(key.PrivateKey) 15 | 16 | // data, err := transaction.MarshalBinary() 17 | // if err != nil { 18 | // t.Error(err) 19 | // } 20 | 21 | // // 从data还原回transaction 22 | // tr2 := &Transaction{} 23 | // _, err = tr2.UnmarshalBinary(data) 24 | // if err != nil { 25 | // t.Error(err) 26 | // } 27 | 28 | // // 对比是否一致 29 | // if !reflect.DeepEqual(tr2.Signature, transaction.Signature) || 30 | // !reflect.DeepEqual(tr2.Payload, transaction.Payload) || 31 | // !reflect.DeepEqual(tr2.Header.From, transaction.Header.From) || 32 | // !reflect.DeepEqual(tr2.Header.To, transaction.Header.To) || 33 | // tr2.Header.Nonce != transaction.Header.Nonce || 34 | // tr2.Header.Timestamp != transaction.Header.Timestamp || 35 | // !reflect.DeepEqual(tr2.Header.PayloadHash, transaction.Header.PayloadHash) || 36 | // tr2.Header.PayloadLen != transaction.Header.PayloadLen { 37 | 38 | // fmt.Println(reflect.DeepEqual(tr2.Signature, transaction.Signature)) 39 | // fmt.Println(reflect.DeepEqual(tr2.Payload, transaction.Payload)) 40 | // fmt.Println(reflect.DeepEqual(tr2.Header.From, transaction.Header.From)) 41 | // fmt.Println(reflect.DeepEqual(tr2.Header.To, transaction.Header.To)) 42 | // fmt.Println(tr2.Header.Nonce != transaction.Header.Nonce) 43 | // fmt.Println(tr2.Header.Timestamp != transaction.Header.Timestamp) 44 | // fmt.Println(tr2.Header.Timestamp) 45 | // fmt.Println(transaction.Header.Timestamp) 46 | 47 | // fmt.Println("tr2.Signature: " + string(tr2.Signature)) 48 | // fmt.Println("transaction.Signature: " + string(transaction.Signature)) 49 | // t.Error("error") 50 | // } 51 | 52 | // // 检测交易是否合法 53 | // verifyResult := transaction.VerifyTransaction(prefixMatch) 54 | // if !verifyResult { 55 | // t.Error("verify failed") 56 | // } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /block/blockchain_test.go: -------------------------------------------------------------------------------- 1 | package block 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | 7 | "time" 8 | 9 | "github.com/jasoncodingnow/bitcoinLiteLite/blockchainuser" 10 | "github.com/jasoncodingnow/bitcoinLiteLite/tool" 11 | ) 12 | 13 | func Test_BlockChain(t *testing.T) { 14 | fmt.Println("start test blockchain") 15 | b := NewBlockChain() 16 | newB := b.NewBlock() 17 | b.Block = newB 18 | 19 | t1 := NewTransaction([]byte(blockchainuser.GetKey().PublicKey), nil, []byte(tool.RandomString(100))) 20 | t2 := NewTransaction([]byte(blockchainuser.GetKey().PublicKey), nil, []byte(tool.RandomString(100))) 21 | t3 := NewTransaction([]byte(blockchainuser.GetKey().PublicKey), nil, []byte(tool.RandomString(100))) 22 | t4 := NewTransaction([]byte(blockchainuser.GetKey().PublicKey), nil, []byte(tool.RandomString(100))) 23 | t5 := NewTransaction([]byte(blockchainuser.GetKey().PublicKey), nil, []byte(tool.RandomString(100))) 24 | t6 := NewTransaction([]byte(blockchainuser.GetKey().PublicKey), nil, []byte(tool.RandomString(100))) 25 | t7 := NewTransaction([]byte(blockchainuser.GetKey().PublicKey), nil, []byte(tool.RandomString(100))) 26 | 27 | prefixMatch := tool.GenerateBytes(1, 0) 28 | 29 | t1.Header.Nonce = t1.GenerateNonce(prefixMatch) 30 | t1.Signature = t1.Sign(blockchainuser.GetKey().PrivateKey) 31 | t2.Header.Nonce = t2.GenerateNonce(prefixMatch) 32 | t2.Signature = t2.Sign(blockchainuser.GetKey().PrivateKey) 33 | t3.Header.Nonce = t3.GenerateNonce(prefixMatch) 34 | t3.Signature = t3.Sign(blockchainuser.GetKey().PrivateKey) 35 | t4.Header.Nonce = t4.GenerateNonce(prefixMatch) 36 | t4.Signature = t4.Sign(blockchainuser.GetKey().PrivateKey) 37 | t5.Header.Nonce = t5.GenerateNonce(prefixMatch) 38 | t5.Signature = t5.Sign(blockchainuser.GetKey().PrivateKey) 39 | t6.Header.Nonce = t6.GenerateNonce(prefixMatch) 40 | t6.Signature = t6.Sign(blockchainuser.GetKey().PrivateKey) 41 | t7.Header.Nonce = t7.GenerateNonce(prefixMatch) 42 | t7.Signature = t7.Sign(blockchainuser.GetKey().PrivateKey) 43 | 44 | b.Run() 45 | fmt.Println("bc start run") 46 | b.TransactionChan <- *t1 47 | b.TransactionChan <- *t2 48 | b.TransactionChan <- *t3 49 | b.TransactionChan <- *t4 50 | b.TransactionChan <- *t5 51 | b.TransactionChan <- *t6 52 | b.TransactionChan <- *t7 53 | 54 | // before test, should change block time span to 10s 55 | time.Sleep(20 * time.Second) 56 | 57 | for _, bc := range *b.BlockSlice { 58 | fmt.Println(bc.Signature) 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /crypto/base58.go: -------------------------------------------------------------------------------- 1 | package crypto 2 | 3 | import ( 4 | "bytes" 5 | "errors" 6 | "math/big" 7 | ) 8 | 9 | const ( 10 | BitcoinBase58Chars = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz" 11 | Base = 58 12 | ) 13 | 14 | var ( 15 | ErrInvalidLengthBytes = errors.New("invalid length bytes") 16 | ErrInvalidChar = errors.New("invalid char") 17 | ) 18 | 19 | type Base58 struct { 20 | chars [58]byte 21 | charIdxMap map[byte]int64 22 | } 23 | 24 | func NewBase58(charsStr string) (*Base58, error) { 25 | b58 := &Base58{} 26 | 27 | if err := b58.initChars(charsStr); err != nil { 28 | return nil, err 29 | } 30 | 31 | if err := b58.initCharIdxMap(charsStr); err != nil { 32 | return nil, err 33 | } 34 | 35 | return b58, nil 36 | } 37 | 38 | func NewBitcoinBase58() *Base58 { 39 | b58, _ := NewBase58(BitcoinBase58Chars) 40 | 41 | return b58 42 | } 43 | 44 | func (b58 *Base58) initChars(charsStr string) error { 45 | if len(charsStr) != 58 { 46 | return ErrInvalidLengthBytes 47 | } 48 | 49 | chars := []byte(charsStr) 50 | copy(b58.chars[:], chars[:]) 51 | 52 | return nil 53 | } 54 | 55 | func (b58 *Base58) initCharIdxMap(charsStr string) error { 56 | if len(charsStr) != 58 { 57 | return ErrInvalidLengthBytes 58 | } 59 | 60 | b58.charIdxMap = map[byte]int64{} 61 | for i, b := range []byte(charsStr) { 62 | b58.charIdxMap[b] = int64(i) 63 | } 64 | 65 | return nil 66 | } 67 | 68 | func (b58 *Base58) EncodeToString(b []byte) (string, error) { 69 | n := &big.Int{} 70 | n.SetBytes(b) 71 | 72 | buf := &bytes.Buffer{} 73 | for _, c := range b { 74 | if c == 0x00 { 75 | if err := buf.WriteByte(b58.chars[0]); err != nil { 76 | return "", err 77 | } 78 | } else { 79 | break 80 | } 81 | } 82 | 83 | zero := big.NewInt(0) 84 | div := big.NewInt(Base) 85 | mod := &big.Int{} 86 | 87 | tmpBuf := &bytes.Buffer{} 88 | for { 89 | if n.Cmp(zero) == 0 { 90 | tmpBytes := tmpBuf.Bytes() 91 | for i := len(tmpBytes) - 1; i >= 0; i-- { 92 | buf.WriteByte(tmpBytes[i]) 93 | } 94 | return buf.String(), nil 95 | } 96 | 97 | n.DivMod(n, div, mod) 98 | if err := tmpBuf.WriteByte(b58.chars[mod.Int64()]); err != nil { 99 | return "", err 100 | } 101 | } 102 | } 103 | 104 | func (b58 *Base58) DecodeString(s string) ([]byte, error) { 105 | b := []byte(s) 106 | 107 | startIdx := 0 108 | buf := &bytes.Buffer{} 109 | for i, c := range b { 110 | if c == b58.chars[0] { 111 | if err := buf.WriteByte(0x00); err != nil { 112 | return nil, err 113 | } 114 | } else { 115 | startIdx = i 116 | break 117 | } 118 | } 119 | 120 | n := big.NewInt(0) 121 | div := big.NewInt(Base) 122 | 123 | for _, c := range b[startIdx:] { 124 | charIdx, ok := b58.charIdxMap[c] 125 | if !ok { 126 | return nil, ErrInvalidChar 127 | } 128 | 129 | n.Add(n.Mul(n, div), big.NewInt(charIdx)) 130 | } 131 | 132 | buf.Write(n.Bytes()) 133 | 134 | return buf.Bytes(), nil 135 | } 136 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bufio" 5 | "flag" 6 | "fmt" 7 | "os" 8 | 9 | "strings" 10 | 11 | "github.com/jasoncodingnow/bitcoinLiteLite/block" 12 | "github.com/jasoncodingnow/bitcoinLiteLite/blockchainuser" 13 | "github.com/jasoncodingnow/bitcoinLiteLite/crypto" 14 | "github.com/jasoncodingnow/bitcoinLiteLite/message" 15 | "github.com/jasoncodingnow/bitcoinLiteLite/network" 16 | "github.com/jasoncodingnow/bitcoinLiteLite/tool" 17 | ) 18 | 19 | var port = flag.String("port", "0", "server port") 20 | 21 | func init() { 22 | flag.Parse() 23 | } 24 | 25 | func main() { 26 | if len(flag.Args()) != 2 { 27 | fmt.Println(flag.Args()) 28 | fmt.Println("[ERROR] input error") 29 | return 30 | } 31 | 32 | port := flag.Args()[1] 33 | 34 | addresses, _ := tool.GetIpAddress() 35 | Start(addresses[0], port) 36 | for { 37 | str := <-ReadStdin() 38 | if len(str) < 2 { 39 | fmt.Println("input error") 40 | fmt.Println(str) 41 | continue 42 | } 43 | block.BlockChainInstant.TransactionChan <- *CreateTransaction(str[0], str[1]) 44 | } 45 | } 46 | 47 | func Start(address, port string) { 48 | fmt.Println("start at " + address + ":" + port) 49 | //TODO: 需要从有本地保存key的机制 50 | key := crypto.GenerateKey() 51 | blockchainuser.SetKey(key) 52 | fmt.Println("public key is " + key.PublicKey) 53 | 54 | network.NetworkInstant = network.CreateNetwork(address, port) 55 | go network.Run(network.NetworkInstant, port) 56 | for _, node := range RootNodes() { 57 | network.NetworkInstant.ConnectionChan <- node 58 | } 59 | 60 | block.BlockChainInstant = block.NewBlockChain() 61 | go block.BlockChainInstant.Run() 62 | 63 | ReceiveMessage() 64 | } 65 | 66 | func CreateTransaction(toAddr, msg string) *block.Transaction { 67 | t := block.NewTransaction([]byte(blockchainuser.GetKey().PublicKey), []byte(toAddr), []byte(msg)) 68 | t.Header.Nonce = t.GenerateNonce(tool.GenerateBytes(block.TransactionPowPrefix, 0)) 69 | t.Signature = t.Sign(blockchainuser.GetKey().PrivateKey) 70 | 71 | return t 72 | } 73 | 74 | //接收到外部节点的消息 75 | func ReceiveMessage() { 76 | go func() { 77 | for { 78 | select { 79 | case msg := <-network.NetworkInstant.IncomingChan: 80 | HandleIncomingMessage(msg) 81 | } 82 | } 83 | }() 84 | } 85 | 86 | //HandleIncomingMessage 处理消息 87 | func HandleIncomingMessage(m message.Message) { 88 | switch m.Type { 89 | case message.MessageTypeSendBlock: 90 | b := block.NewBlock(nil) 91 | err := b.UnmarshalBinary(m.Data) 92 | if err != nil { 93 | fmt.Println("unmarshal binary to block err: " + err.Error()) 94 | break 95 | } 96 | block.BlockChainInstant.BlockChan <- *b 97 | case message.MessageTypeSendTransaction: 98 | t := block.Transaction{} 99 | _, err := t.UnmarshalBinary(m.Data) 100 | if err != nil { 101 | fmt.Println("unmarshal binary to transaction err: " + err.Error()) 102 | break 103 | } 104 | block.BlockChainInstant.TransactionChan <- t 105 | } 106 | } 107 | 108 | //RootNodes 写死的固定服务器,用于接入,暂时先写死自己的一台 109 | func RootNodes() []string { 110 | nodes := []string{"192.168.11.101:8091"} 111 | return nodes 112 | } 113 | 114 | //ReadStdin 读取命令行 115 | func ReadStdin() chan []string { 116 | cb := make(chan []string) 117 | sc := bufio.NewScanner(os.Stdin) 118 | 119 | go func() { 120 | for { 121 | if sc.Scan() { 122 | line := sc.Text() 123 | fmt.Println("input is " + line) 124 | lines := strings.Split(line, " ") 125 | cb <- lines 126 | } 127 | } 128 | }() 129 | 130 | return cb 131 | } 132 | -------------------------------------------------------------------------------- /block/transaction.go: -------------------------------------------------------------------------------- 1 | package block 2 | 3 | import ( 4 | "errors" 5 | "time" 6 | 7 | "bytes" 8 | 9 | "encoding/binary" 10 | 11 | "reflect" 12 | 13 | "github.com/jasoncodingnow/bitcoinLiteLite/consensus" 14 | "github.com/jasoncodingnow/bitcoinLiteLite/crypto" 15 | "github.com/jasoncodingnow/bitcoinLiteLite/tool" 16 | ) 17 | 18 | type TransactionHeader struct { 19 | From []byte 20 | To []byte 21 | PayloadHash []byte 22 | PayloadLen uint32 23 | Timestamp uint32 24 | Nonce uint32 25 | } 26 | 27 | type Transaction struct { 28 | Header TransactionHeader 29 | Signature []byte 30 | Payload []byte 31 | } 32 | 33 | type TransactionSlice []Transaction 34 | 35 | //NewTransaction create new transaction 36 | func NewTransaction(from, to, payload []byte) *Transaction { 37 | t := &Transaction{Header: TransactionHeader{From: from, To: to}, Payload: payload} 38 | t.Header.Timestamp = uint32(time.Now().Unix()) 39 | t.Header.PayloadHash = tool.SHA256(payload) 40 | t.Header.PayloadLen = uint32(len(payload)) 41 | return t 42 | } 43 | 44 | func (t *Transaction) Hash() []byte { 45 | headerBytes, _ := t.Header.MarshalBinary() 46 | return tool.SHA256(headerBytes) 47 | } 48 | 49 | func (t *Transaction) Sign(privateKey string) []byte { 50 | s, _ := crypto.Sign(t.Hash(), privateKey) 51 | return []byte(s) 52 | } 53 | 54 | func (t *Transaction) VerifyTransaction(powPrefix []byte) bool { 55 | h := t.Hash() 56 | payloadHash := tool.SHA256(t.Payload) 57 | return reflect.DeepEqual(payloadHash, t.Header.PayloadHash) && consensus.CheckProofOfWork(powPrefix, h) && crypto.Verify(h, string(t.Signature), string(t.Header.From)) 58 | } 59 | 60 | //GenerateNonce pow过程,这里是每次交易需要消耗一定量的计算 61 | func (t *Transaction) GenerateNonce(powPrefix []byte) uint32 { 62 | for { 63 | if consensus.CheckProofOfWork(powPrefix, t.Hash()) { 64 | break 65 | } 66 | t.Header.Nonce++ 67 | } 68 | return t.Header.Nonce 69 | } 70 | 71 | func (t *Transaction) MarshalBinary() ([]byte, error) { 72 | headerBinary, err := t.Header.MarshalBinary() 73 | if err != nil { 74 | return nil, err 75 | } 76 | if len(headerBinary) != TransactionHeaderSize { 77 | return nil, errors.New("header marshal len error") 78 | } 79 | return append(append(headerBinary, tool.FillBytesToFront(t.Signature, TransactionSignatureSize)...), t.Payload...), nil 80 | } 81 | 82 | func (t *Transaction) UnmarshalBinary(data []byte) ([]byte, error) { 83 | buf := bytes.NewBuffer(data) 84 | 85 | if len(data) < (TransactionHeaderSize + TransactionSignatureSize) { 86 | return nil, errors.New("data length error when unmarshal binary to transaction") 87 | } 88 | 89 | h := TransactionHeader{} 90 | if err := h.UnmarshalBinary(buf.Next(TransactionHeaderSize)); err != nil { 91 | return nil, err 92 | } 93 | 94 | t.Header = h 95 | t.Signature = tool.SliceByteWhenEncount(buf.Next(TransactionSignatureSize), 0) 96 | t.Payload = buf.Next(int(t.Header.PayloadLen)) 97 | return buf.Next(MaxInt), nil 98 | } 99 | 100 | func (t *TransactionHeader) MarshalBinary() ([]byte, error) { 101 | buf := new(bytes.Buffer) 102 | 103 | buf.Write(tool.FillBytesToFront(t.From, crypto.PublicKeyLen)) 104 | buf.Write(tool.FillBytesToFront(t.To, crypto.PublicKeyLen)) 105 | buf.Write(tool.FillBytesToFront(t.PayloadHash, PayloadHashSize)) 106 | binary.Write(buf, binary.LittleEndian, t.PayloadLen) 107 | binary.Write(buf, binary.LittleEndian, t.Timestamp) 108 | binary.Write(buf, binary.LittleEndian, t.Nonce) 109 | return buf.Bytes(), nil 110 | } 111 | 112 | func (t *TransactionHeader) UnmarshalBinary(data []byte) error { 113 | buf := bytes.NewBuffer(data) 114 | t.From = tool.SliceByteWhenEncount(buf.Next(crypto.PublicKeyLen), 0) 115 | t.To = tool.SliceByteWhenEncount(buf.Next(crypto.PublicKeyLen), 0) 116 | t.PayloadHash = tool.SliceByteWhenEncount(buf.Next(PayloadHashSize), 0) 117 | binary.Read(bytes.NewBuffer(buf.Next(4)), binary.LittleEndian, &t.PayloadLen) 118 | binary.Read(bytes.NewBuffer(buf.Next(4)), binary.LittleEndian, &t.Timestamp) 119 | binary.Read(bytes.NewBuffer(buf.Next(4)), binary.LittleEndian, &t.Nonce) 120 | return nil 121 | } 122 | 123 | func (t *TransactionSlice) MarshalBinary() ([]byte, error) { 124 | buf := new(bytes.Buffer) 125 | 126 | for _, tr := range *t { 127 | b, err := tr.MarshalBinary() 128 | if err != nil { 129 | return nil, err 130 | } 131 | buf.Write(b) 132 | } 133 | return buf.Bytes(), nil 134 | } 135 | 136 | func (t *TransactionSlice) UnmarshalBinary(data []byte) error { 137 | d := data 138 | 139 | for len(d) > TransactionHeaderSize+TransactionSignatureSize { 140 | tr := &Transaction{} 141 | remain, err := tr.UnmarshalBinary(d) 142 | if err != nil { 143 | return err 144 | } 145 | *t = append(*t, *tr) 146 | d = remain 147 | } 148 | return nil 149 | } 150 | 151 | func (t TransactionSlice) Exists(newTr *Transaction) bool { 152 | for _, tr := range t { 153 | if reflect.DeepEqual(tr.Signature, newTr.Signature) { 154 | return true 155 | } 156 | } 157 | return false 158 | } 159 | 160 | func (t TransactionSlice) AddTransaction(newTr *Transaction) TransactionSlice { 161 | for i, tr := range t { 162 | if tr.Header.Timestamp >= newTr.Header.Timestamp { 163 | return append(append(t[:i], *newTr), t[i:]...) 164 | } 165 | } 166 | return append(t, *newTr) 167 | } 168 | -------------------------------------------------------------------------------- /block/block.go: -------------------------------------------------------------------------------- 1 | package block 2 | 3 | import ( 4 | "bytes" 5 | "encoding/binary" 6 | "fmt" 7 | "time" 8 | 9 | "reflect" 10 | 11 | "github.com/jasoncodingnow/bitcoinLiteLite/consensus" 12 | "github.com/jasoncodingnow/bitcoinLiteLite/crypto" 13 | "github.com/jasoncodingnow/bitcoinLiteLite/tool" 14 | ) 15 | 16 | type Block struct { 17 | Header *BlockHeader 18 | Signature []byte 19 | Transactions *TransactionSlice 20 | } 21 | 22 | type BlockHeader struct { 23 | Origin []byte // public key or address 24 | PrevBlock []byte 25 | MerkleRoot []byte 26 | Timestamp uint32 27 | Nonce uint32 28 | } 29 | 30 | type BlockSlice []Block 31 | 32 | func NewBlock(prevBlock []byte) *Block { 33 | b := &Block{} 34 | b.Header = &BlockHeader{PrevBlock: prevBlock} 35 | b.Header.Timestamp = uint32(time.Now().Unix()) 36 | b.Transactions = &TransactionSlice{} 37 | return b 38 | } 39 | 40 | func (b *Block) AddTransaction(t *Transaction) { 41 | newSlice := b.Transactions.AddTransaction(t) 42 | b.Transactions = &newSlice 43 | } 44 | 45 | func (b *Block) Hash() []byte { 46 | headerBytes := b.Header.MarshalBinary() 47 | return tool.SHA256(headerBytes) 48 | } 49 | 50 | func (b *Block) GenerateNonce(powPrefix []byte) uint32 { 51 | for { 52 | if consensus.CheckProofOfWork(powPrefix, b.Hash()) { 53 | break 54 | } 55 | b.Header.Nonce++ 56 | } 57 | return b.Header.Nonce 58 | } 59 | 60 | func (b *Block) VerifyBlock(powPrefix []byte) bool { 61 | h := b.Hash() 62 | m := b.GenrateMerkleRoot() 63 | 64 | //test 65 | if !reflect.DeepEqual(m, b.Header.MerkleRoot) { 66 | fmt.Println("m not equal to b.Header.MerkleRoot") 67 | fmt.Println("m is %x", m) 68 | fmt.Println("m is %x", b.Header.MerkleRoot) 69 | fmt.Println("MerkleRoot validate error") 70 | return false 71 | } 72 | if !consensus.CheckProofOfWork(powPrefix, h) { 73 | fmt.Println("pow error") 74 | return false 75 | } 76 | if !crypto.Verify(h, string(b.Signature), string(b.Header.Origin)) { 77 | fmt.Println("verify err") 78 | return false 79 | } 80 | return true 81 | } 82 | 83 | func (b *Block) Sign(privateKey string) []byte { 84 | sign, _ := crypto.Sign(b.Hash(), privateKey) 85 | return []byte(sign) 86 | } 87 | 88 | func (b *Block) GenrateMerkleRoot() []byte { 89 | l := len(*b.Transactions) 90 | tree := make([][]byte, l) 91 | for _, t := range *b.Transactions { 92 | tree = append(tree, t.Hash()) 93 | } 94 | merkleRoot := b.generateMerkleRoot(tree) 95 | return merkleRoot 96 | } 97 | 98 | // 通过递归生成MerkleTree的最终hash 99 | func (b *Block) generateMerkleRoot(tree [][]byte) []byte { 100 | l := len(tree) 101 | if l == 0 { 102 | return nil 103 | } 104 | if l == 1 { 105 | return tree[0] 106 | } 107 | lastTreeNode := []byte{} 108 | half := 0 109 | if l%2 == 1 { 110 | // 奇数,把最后一个拿出来 111 | lastTreeNode = tree[l-1] 112 | half = (l - 1) / 2 113 | } else { 114 | half = l / 2 115 | } 116 | 117 | newTree := make([][]byte, 0) 118 | for i := 0; i < half; i++ { 119 | prevNode, nextNode := tree[i*2], tree[i*2+1] 120 | hash := tool.SHA256(append(prevNode, nextNode...)) 121 | newTree = append(newTree, hash) 122 | } 123 | 124 | if len(lastTreeNode) == 0 { 125 | return b.generateMerkleRoot(newTree) 126 | } 127 | newTree = append(newTree, lastTreeNode) 128 | return b.generateMerkleRoot(newTree) 129 | } 130 | 131 | func (b *Block) MarshalBinary() ([]byte, error) { 132 | binary := b.Header.MarshalBinary() 133 | signature := tool.FillBytesToFront(b.Signature, BlockSignatureSize) 134 | transactionBytes, err := b.Transactions.MarshalBinary() 135 | if err != nil { 136 | return nil, err 137 | } 138 | return append(append(binary, signature...), transactionBytes...), nil 139 | } 140 | 141 | func (b *Block) UnmarshalBinary(data []byte) error { 142 | buf := bytes.NewBuffer(data) 143 | 144 | err := b.Header.UnmarshalBinary(buf.Next(BlockHeaderSize)) 145 | if err != nil { 146 | return err 147 | } 148 | 149 | b.Signature = tool.SliceByteWhenEncount(buf.Next(BlockSignatureSize), 0) 150 | err = b.Transactions.UnmarshalBinary(buf.Next(MaxInt)) 151 | if err != nil { 152 | return err 153 | } 154 | return nil 155 | } 156 | 157 | func (h *BlockHeader) MarshalBinary() []byte { 158 | buf := &bytes.Buffer{} 159 | 160 | buf.Write(tool.FillBytesToFront(h.Origin, crypto.PublicKeyLen)) 161 | buf.Write(tool.FillBytesToFront(h.PrevBlock, BlockSignatureSize)) 162 | buf.Write(tool.FillBytesToFront(h.MerkleRoot, MerkleRootSize)) 163 | binary.Write(buf, binary.LittleEndian, h.Timestamp) 164 | binary.Write(buf, binary.LittleEndian, h.Nonce) 165 | return buf.Bytes() 166 | } 167 | 168 | func (h *BlockHeader) UnmarshalBinary(data []byte) error { 169 | buf := bytes.NewBuffer(data) 170 | h.Origin = tool.SliceByteWhenEncount(buf.Next(crypto.PublicKeyLen), 0) 171 | h.PrevBlock = tool.SliceByteWhenEncount(buf.Next(BlockSignatureSize), 0) 172 | h.MerkleRoot = tool.SliceByteWhenEncount(buf.Next(MerkleRootSize), 0) 173 | binary.Read(bytes.NewBuffer(buf.Next(4)), binary.LittleEndian, &h.Timestamp) 174 | binary.Read(bytes.NewBuffer(buf.Next(4)), binary.LittleEndian, &h.Nonce) 175 | return nil 176 | } 177 | 178 | func (slice *BlockSlice) Exists(b *Block) bool { 179 | for i := len(*slice) - 1; i >= 0; i-- { 180 | currB := (*slice)[i] 181 | if reflect.DeepEqual(currB.Signature, b.Signature) { 182 | return true 183 | } 184 | } 185 | return false 186 | } 187 | -------------------------------------------------------------------------------- /network/net.go: -------------------------------------------------------------------------------- 1 | package network 2 | 3 | import ( 4 | "fmt" 5 | "net" 6 | 7 | "time" 8 | 9 | "io" 10 | 11 | "strings" 12 | 13 | "github.com/jasoncodingnow/bitcoinLiteLite/message" 14 | "github.com/jasoncodingnow/bitcoinLiteLite/tool" 15 | ) 16 | 17 | type Node struct { 18 | Net *net.TCPConn //连接实例 19 | Port string //端口 20 | ConnectTime int //获取连接的时间 21 | } 22 | 23 | type Nodes map[string]*Node //存放所有的连接 24 | 25 | type NodeChan chan *Node 26 | 27 | type ConnectionChan chan string // 包含 地址:端口 28 | 29 | type Network struct { 30 | Nodes Nodes 31 | ConnectionChan ConnectionChan //新的连接接入,通过该chan触发处理机制 32 | Address string //当前节点的地址 33 | Port string //端口 34 | NodeCallback NodeChan //新的节点连接完成,调用该chan 35 | BroadCastChan chan message.Message //所有Message丢入该chan,该chan会广播 36 | IncomingChan chan message.Message //如果接收到外部消息,丢入到该chan 37 | } 38 | 39 | //CreateNetwork 创建新的网络 40 | func CreateNetwork(address, port string) *Network { 41 | n := &Network{} 42 | 43 | n.BroadCastChan, n.IncomingChan = make(chan message.Message), make(chan message.Message) 44 | n.ConnectionChan, n.NodeCallback = CreateConnectHandlerForReceive() 45 | n.Nodes = Nodes{} 46 | n.Address = address 47 | n.Port = port 48 | 49 | return n 50 | } 51 | 52 | func Run(n *Network, port string) { 53 | fmt.Println("net start run: " + NetworkInstant.Address) 54 | listencb := StartListening(NetworkInstant.Address, port) 55 | for { 56 | select { 57 | case node := <-listencb: 58 | NetworkInstant.Nodes.AddNode(node) 59 | case node := <-n.NodeCallback: 60 | NetworkInstant.Nodes.AddNode(node) 61 | case m := <-n.BroadCastChan: 62 | go n.BroadCastMessage(&m) 63 | } 64 | } 65 | } 66 | 67 | //CreateConnectHandlerForReceive 新的地址接入,处理连接机制 68 | func CreateConnectHandlerForReceive() (ConnectionChan, NodeChan) { 69 | incomingAddr := make(ConnectionChan) 70 | connCb := make(NodeChan) 71 | go func() { 72 | for { 73 | address := <-incomingAddr 74 | fmt.Println("start connect to node: " + address) 75 | s := strings.Split(address, ":") 76 | if len(s) != 2 { 77 | fmt.Println("incoming address error: " + address) 78 | continue 79 | } 80 | localAddress := NetworkInstant.Address + ":" + NetworkInstant.Port 81 | if localAddress != address && NetworkInstant.Nodes[address] == nil { 82 | go ConnectNode(s[0], s[1], 10*time.Second, false, connCb) 83 | } 84 | } 85 | }() 86 | return incomingAddr, connCb 87 | } 88 | 89 | //StartListening 当前主机开始接受其他节点发来的消息 90 | func StartListening(address, port string) NodeChan { 91 | cb := make(NodeChan) 92 | addr, err := net.ResolveTCPAddr("tcp4", address+":"+port) 93 | if err != nil { 94 | fmt.Println("resolve tcp address error: " + err.Error()) 95 | } 96 | listening, err := net.ListenTCP("tcp4", addr) 97 | if err != nil { 98 | fmt.Println("listen tcp address error: " + err.Error()) 99 | } 100 | go func(listener *net.TCPListener) { 101 | for { 102 | conn, err := listener.AcceptTCP() 103 | if err != nil { 104 | fmt.Println("accept tcp address error: " + err.Error()) 105 | } 106 | cb <- &Node{conn, "0", int(time.Now().Unix())} 107 | } 108 | }(listening) 109 | return cb 110 | } 111 | 112 | //ConnectNode 连接到某个节点 113 | func ConnectNode(nodehost string, port string, timeout time.Duration, retry bool, cb NodeChan) { 114 | host := nodehost + ":" + port 115 | fmt.Println("try to connect to node " + host) 116 | addr, err := net.ResolveTCPAddr("tcp4", host) 117 | if err != nil { 118 | fmt.Println(err.Error()) 119 | } 120 | tryConnecting := true 121 | for tryConnecting { 122 | go func() { 123 | conn, err := net.DialTCP("tcp", nil, addr) 124 | if err != nil { 125 | fmt.Println("DialTCP " + host + " err: " + err.Error()) 126 | } 127 | if conn != nil { 128 | cb <- &Node{conn, port, int(time.Now().Unix())} 129 | 130 | // 发送自己端口 131 | portMsg, _ := message.NewMessage(message.MessageTypePort) 132 | portMsg.Data = []byte(NetworkInstant.Port) 133 | NetworkInstant.BroadCastChan <- *portMsg 134 | 135 | tryConnecting = false 136 | } 137 | }() 138 | select { 139 | case <-tool.Timeout(timeout): 140 | if tryConnecting && !retry { 141 | tryConnecting = false 142 | } 143 | } 144 | } 145 | } 146 | 147 | //BroadCastMessage 广播所有信息 148 | func (n *Network) BroadCastMessage(m *message.Message) { 149 | b := m.MarshalBinary() 150 | for _, node := range n.Nodes { 151 | fmt.Println("broadcast message to " + node.Net.RemoteAddr().String()) 152 | go func() { 153 | _, err := node.Net.Write(b) 154 | if err != nil { 155 | fmt.Println("err when broadcast message to " + node.Net.RemoteAddr().String()) 156 | } 157 | }() 158 | } 159 | } 160 | 161 | //AddNode 有新的 162 | func (n Nodes) AddNode(node *Node) bool { 163 | addr := node.Net.RemoteAddr().String() 164 | if addr != NetworkInstant.Address && NetworkInstant.Nodes[addr] == nil { 165 | fmt.Println("node connect from: " + addr) 166 | // n[addr] = node // 这里不加入,等到对方传来port的时候,再加入 167 | if node.Port != "0" { 168 | n[addr+":"+node.Port] = node 169 | } 170 | go HandleNode(n, node) 171 | return true 172 | } 173 | return false 174 | } 175 | 176 | //HandleNode 接收Node的消息,并且如果有返回则传递回去 177 | func HandleNode(nodes Nodes, node *Node) { 178 | for { 179 | data := make([]byte, 1024*1000) 180 | l, err := node.Net.Read(data[0:]) 181 | if err != nil { 182 | fmt.Println("err when read byte from node, err: " + err.Error()) 183 | } 184 | if err == io.EOF { 185 | fmt.Println("EOF") 186 | node.Net.Close() 187 | NetworkInstant.Nodes[node.Net.RemoteAddr().String()] = nil 188 | break 189 | } 190 | 191 | m := message.Message{} 192 | m.UnmarshalBinary(data[0:l]) 193 | if err != nil { 194 | fmt.Println("err when convert bytes to Message, err: " + err.Error()) 195 | continue 196 | } 197 | 198 | // 如果Type只是传递port,则不需要对传递给其他方法处理了 199 | if m.Type == message.MessageTypePort { 200 | node.Port = string(m.Data) 201 | nodeAddr := node.Net.RemoteAddr().String() 202 | s := strings.Split(nodeAddr, ":") 203 | if len(s) > 1 { 204 | nodeAddr = s[0] 205 | } 206 | fmt.Println("add new node to Nodes: " + nodeAddr + ":" + node.Port) 207 | nodes[nodeAddr+":"+node.Port] = node 208 | continue 209 | } 210 | 211 | m.Reply = make(chan message.Message) 212 | //TODO: 如果出错导致返回消息没有传递过来,需要有个timeout机制 213 | go func(cb chan message.Message) { 214 | for { 215 | reply, ok := <-cb 216 | if !ok { 217 | close(cb) 218 | break 219 | } 220 | 221 | replyBytes := reply.MarshalBinary() 222 | i := 0 223 | for i < 1 { 224 | writeResult, _ := node.Net.Write(replyBytes[i:]) 225 | i += writeResult 226 | } 227 | } 228 | }(m.Reply) 229 | 230 | NetworkInstant.IncomingChan <- m 231 | } 232 | } 233 | -------------------------------------------------------------------------------- /block/blockchain.go: -------------------------------------------------------------------------------- 1 | package block 2 | 3 | import ( 4 | "fmt" 5 | "strconv" 6 | "time" 7 | 8 | "reflect" 9 | 10 | "github.com/jasoncodingnow/bitcoinLiteLite/blockchainuser" 11 | "github.com/jasoncodingnow/bitcoinLiteLite/consensus" 12 | "github.com/jasoncodingnow/bitcoinLiteLite/message" 13 | "github.com/jasoncodingnow/bitcoinLiteLite/network" 14 | "github.com/jasoncodingnow/bitcoinLiteLite/tool" 15 | ) 16 | 17 | type BlockChan chan Block 18 | type TransactionChan chan Transaction 19 | 20 | type BlockChain struct { 21 | Block *Block // 当前的Block,属于未广播未确认状态 22 | BlockSlice *BlockSlice 23 | 24 | BlockChan BlockChan // 接收Block 25 | TransactionChan TransactionChan // 接收Transaction,验证,加入到Block 26 | RemainTransactins TransactionSlice // 正在打包,或者正在验证区块,如果整个时候有新的Transaction进入,则暂时放入这里 27 | } 28 | 29 | var isPackaging = false // 是否当前正在打包 30 | 31 | func NewBlockChain() *BlockChain { 32 | b := &BlockChain{} 33 | b.Block = NewBlock(nil) 34 | b.BlockSlice = &BlockSlice{} 35 | b.BlockChan = make(BlockChan) 36 | b.TransactionChan = make(TransactionChan) 37 | b.RemainTransactins = TransactionSlice{} 38 | return b 39 | } 40 | 41 | //NewBlock 产生新的区块 42 | func (b *BlockChain) NewBlock() *Block { 43 | prevBlockHash := []byte{} 44 | if *b.BlockSlice == nil || len(*b.BlockSlice) == 0 { 45 | prevBlockHash = nil 46 | } else { 47 | prevBlock := (*b.BlockSlice)[len(*b.BlockSlice)-1] 48 | prevBlockHash = prevBlock.Hash() 49 | } 50 | 51 | newB := NewBlock(prevBlockHash) 52 | newB.Header.Origin = []byte(blockchainuser.GetKey().PublicKey) 53 | return newB 54 | } 55 | 56 | //AppendBlock 并且设置Hash 57 | func (bc *BlockChain) AppendBlock(b *Block) { 58 | l := len(*bc.BlockSlice) 59 | if l != 0 { 60 | b.Header.PrevBlock = (*bc.BlockSlice)[l-1].Hash() 61 | } 62 | newBlockSlice := append(*bc.BlockSlice, *b) 63 | bc.BlockSlice = &newBlockSlice 64 | } 65 | 66 | func (bc *BlockChain) Run() { 67 | go func() { 68 | newBlockChan := bc.GenerateBlock() 69 | bc.newTicker(newBlockChan) 70 | for { 71 | select { 72 | case tr := <-bc.TransactionChan: 73 | fmt.Println("[INFO] receive new transaction, Signature is : ") 74 | fmt.Println(tr.Signature) 75 | 76 | if bc.Block.Transactions.Exists(&tr) { 77 | continue 78 | } 79 | if !tr.VerifyTransaction(tool.GenerateBytes(TransactionPowPrefix, 0)) { 80 | fmt.Println("not valid transaction") 81 | continue 82 | } 83 | if isPackaging { 84 | // 如果正在打包 85 | // 如果直接加入的时候,有可能导致检验不通过。这里处理只是减少概率而已,没治本 86 | bc.RemainTransactins = append(bc.RemainTransactins, tr) 87 | bc.broadCastTransaction(&tr) 88 | continue 89 | } 90 | bc.Block.AddTransaction(&tr) 91 | bc.broadCastTransaction(&tr) 92 | if bc.checkNeedToPackageBlock() { 93 | bc.addTrToBlock(bc.Block, &bc.RemainTransactins) 94 | newBlockChan <- *(bc.Block) 95 | } 96 | case b := <-bc.BlockChan: 97 | fmt.Println("receive new block") 98 | if bc.BlockSlice.Exists(&b) { 99 | fmt.Println("block exists") 100 | continue 101 | } 102 | if !b.VerifyBlock(tool.GenerateBytes(BlockPowPrefix, 0)) { 103 | fmt.Println("block not validate") 104 | continue 105 | } 106 | if reflect.DeepEqual(bc.Block.Hash(), b.Header.PrevBlock) { 107 | fmt.Println("block not match") 108 | } else { 109 | fmt.Println("block success validate") 110 | bc.AppendBlock(&b) 111 | 112 | diffTransactions := bc.getDiffTransactions(bc.Block.Transactions, b.Transactions, &bc.RemainTransactins) 113 | 114 | bc.broadCastBlock(&b) 115 | 116 | bc.Block = bc.NewBlock() 117 | bc.addTrToBlock(bc.Block, &diffTransactions) 118 | bc.RemainTransactins = diffTransactions 119 | 120 | fmt.Println("[INFO] after Block package, the len of bc.Block.Transactions is " + strconv.Itoa(len(*bc.Block.Transactions))) 121 | fmt.Println("[INFO] after Block package, the len of bc.RemainTransactions is " + strconv.Itoa(len(bc.RemainTransactins))) 122 | if isPackaging { 123 | isPackaging = false 124 | } 125 | } 126 | } 127 | } 128 | }() 129 | } 130 | 131 | // 获取两个Transaction之间的不同 132 | func (bc *BlockChain) getDiffTransactions(tr1, tr2, tr3 *TransactionSlice) TransactionSlice { 133 | result := TransactionSlice{} 134 | tr1Map := make(map[string]Transaction) 135 | for _, t := range *tr1 { 136 | tr1Map[string(t.Signature)] = t 137 | } 138 | 139 | for _, t := range *tr2 { 140 | if v, ok := tr1Map[string(t.Signature)]; !ok { 141 | result = append(result, v) 142 | } 143 | } 144 | 145 | for _, t := range *tr3 { 146 | if v, ok := tr1Map[string(t.Signature)]; !ok { 147 | result = append(result, v) 148 | } 149 | } 150 | 151 | return result 152 | } 153 | 154 | // 把trs里面的交易,取出一部分放到Block里 155 | func (bc *BlockChain) addTrToBlock(b *Block, trs *TransactionSlice) { 156 | 157 | tr1Map := make(map[string]Transaction) 158 | for _, t := range *b.Transactions { 159 | tr1Map[string(t.Signature)] = t 160 | } 161 | 162 | result := TransactionSlice{} 163 | 164 | for _, t := range *trs { 165 | if v, ok := tr1Map[string(t.Signature)]; !ok { 166 | result = append(result, v) 167 | } 168 | } 169 | 170 | trl := len(*b.Transactions) 171 | noEnough := false 172 | if trl < 5 { 173 | for i := 0; i < (5 - trl); i++ { 174 | if i < len(result) { 175 | t := append(*b.Transactions, result[i]) 176 | b.Transactions = &t 177 | } else { 178 | noEnough = true 179 | } 180 | } 181 | } 182 | if !noEnough { 183 | result = result[(5 - trl):] 184 | trs = &result 185 | } else { 186 | trs = &TransactionSlice{} 187 | } 188 | } 189 | 190 | // 当前需要打包有3个条件: 191 | // 1. 当前不是正在打包阶段 192 | // 2. 当前交易数量达到5,但是等待时间无所谓 193 | // // 3. 当前交易数量无所谓,但是距离上一个打包已经十分钟了 194 | func (bc *BlockChain) checkNeedToPackageBlock() bool { 195 | if isPackaging { 196 | return false 197 | } 198 | if (len(*bc.Block.Transactions) + len(bc.RemainTransactins)) >= 5 { 199 | return true 200 | } 201 | return false 202 | } 203 | 204 | // 3. 当前交易数量无所谓,但是距离上一个打包已经十分钟了 205 | func (bc *BlockChain) newTicker(newBlockChan chan Block) { 206 | go func() { 207 | timer := time.NewTicker(PackageTimespan * time.Minute) 208 | // timer := time.NewTicker(10 * time.Second) // test 209 | for { 210 | select { 211 | case <-timer.C: 212 | l := len(*(bc.BlockSlice)) 213 | if len(*(bc.Block.Transactions)) > 0 { 214 | if l == 0 { 215 | newBlockChan <- *(bc.Block) 216 | } else { 217 | lastBlock := (*(bc.BlockSlice))[l-1] 218 | now := uint32(time.Now().Unix()) 219 | if (now - lastBlock.Header.Timestamp) >= PackageTimespan*60 { 220 | newBlockChan <- *(bc.Block) 221 | } 222 | } 223 | } 224 | } 225 | } 226 | }() 227 | } 228 | 229 | //GenerateBlock 产生新的block,即 打包 230 | //TODO: 需要有详细的打包规则,比如打包是交易达到一定数量开始打包,后续的交易进入下个区块? 231 | func (bc *BlockChain) GenerateBlock() chan Block { 232 | isPackaging = false 233 | b := make(chan Block) 234 | go func() { 235 | for true { 236 | newBlock := <-b 237 | fmt.Println("new block! start pow") 238 | calNewBlockFinish := false 239 | for !calNewBlockFinish { 240 | isPackaging = true 241 | 242 | // 初始化Block Header 243 | if newBlock.Header.Origin == nil { 244 | newBlock.Header.Origin = []byte(blockchainuser.GetKey().PublicKey) 245 | } 246 | newBlock.Header.MerkleRoot = newBlock.GenrateMerkleRoot() 247 | newBlock.Header.Timestamp = uint32(time.Now().Unix()) 248 | newBlock.Header.Nonce = 0 249 | 250 | powSuccess := false 251 | // POW 252 | // 如果有新的Block进入,并且正好在isPackaging,则从外界打断该过程 253 | //TODO: 这里应该有更好的机制,需要完善POW过程中,有新的Block验证完成,如何处理 254 | for isPackaging { 255 | if consensus.CheckProofOfWork(tool.GenerateBytes(BlockPowPrefix, 0), newBlock.Hash()) { 256 | newBlock.Signature = newBlock.Sign(blockchainuser.GetKey().PrivateKey) 257 | bc.BlockChan <- newBlock // 自己产生的区块也发给同一个channel进行验证和写入 258 | calNewBlockFinish = true 259 | fmt.Println("new block packaged!") 260 | powSuccess = true 261 | break 262 | } 263 | newBlock.Header.Nonce++ 264 | } 265 | 266 | if !powSuccess { 267 | // 说明pow被打断了 268 | // 判断是否有足够的Transaction,有的话开始打包 269 | trl := len(*(bc.Block.Transactions)) 270 | if trl >= 5 { 271 | b <- *(bc.Block) 272 | } 273 | } 274 | } 275 | isPackaging = false 276 | } 277 | }() 278 | return b 279 | } 280 | 281 | // 程序运行到这里,POW完成,需要广播 282 | func (bc *BlockChain) broadCastBlock(b *Block) { 283 | m, _ := message.NewMessage(message.MessageTypeSendBlock) 284 | m.Data, _ = b.MarshalBinary() 285 | network.NetworkInstant.BroadCastChan <- *m 286 | } 287 | 288 | // 广播Transaction 289 | func (bc *BlockChain) broadCastTransaction(t *Transaction) { 290 | m, _ := message.NewMessage(message.MessageTypeSendTransaction) 291 | m.Data, _ = t.MarshalBinary() 292 | network.NetworkInstant.BroadCastChan <- *m 293 | } 294 | --------------------------------------------------------------------------------