├── .github └── workflows │ └── go.yml ├── DPOS.go ├── LICENSE └── README.md /.github/workflows/go.yml: -------------------------------------------------------------------------------- 1 | name: Go 2 | on: [push] 3 | jobs: 4 | 5 | build: 6 | name: Build 7 | runs-on: ubuntu-latest 8 | steps: 9 | 10 | - name: Set up Go 1.13 11 | uses: actions/setup-go@v1 12 | with: 13 | go-version: 1.13 14 | id: go 15 | 16 | - name: Check out code into the Go module directory 17 | uses: actions/checkout@v1 18 | 19 | - name: Get dependencies 20 | run: | 21 | go get -v -t -d ./... 22 | if [ -f Gopkg.toml ]; then 23 | curl https://raw.githubusercontent.com/golang/dep/master/install.sh | sh 24 | dep ensure 25 | fi 26 | 27 | - name: Build 28 | run: go build -v . 29 | -------------------------------------------------------------------------------- /DPOS.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "crypto/sha256" 5 | "encoding/hex" 6 | "fmt" 7 | "math/rand" 8 | "sort" 9 | "time" 10 | ) 11 | 12 | type Block struct { 13 | Index int 14 | TimeStamp string 15 | BPM int 16 | Hash string 17 | PrevHash string 18 | Delegate string 19 | } 20 | 21 | // 产生新的区块 22 | func generateBlock(oldBlock Block, _BMP int , address string)(Block, error){ 23 | var newBlock Block 24 | t := time.Now() 25 | 26 | newBlock.Index = oldBlock.Index + 1 27 | newBlock.TimeStamp = t.String() 28 | newBlock.BPM = _BMP 29 | newBlock.PrevHash = oldBlock.Hash 30 | newBlock.Hash = createBlockHash(newBlock) 31 | newBlock.Delegate = address 32 | fmt.Println("NewBlock: ", newBlock) 33 | return newBlock, nil 34 | } 35 | 36 | // 生成区块的hash = sha256('当前区块的index序号' + '时间戳' + '区块的BPM' + '上一个区块的hash').string() 37 | func createBlockHash(block Block) string{ 38 | record := string(block.Index) + block.TimeStamp + string(block.BPM) + block.PrevHash 39 | sha3 := sha256.New() 40 | sha3.Write([] byte(record)) 41 | hash := sha3.Sum(nil) 42 | fmt.Println("NewHash: ",hex.EncodeToString(hash)) 43 | return hex.EncodeToString(hash) 44 | } 45 | 46 | //检视区块是否合法 47 | func isBlockValid(newBlock, oldBlock Block) bool{ 48 | if oldBlock.Index + 1 != newBlock.Index{ 49 | fmt.Println("失败!!index非法") 50 | return false 51 | } 52 | if newBlock.PrevHash != oldBlock.Hash{ 53 | fmt.Println("失败!!PrevHash非法") 54 | return false 55 | } 56 | fmt.Println("合法") 57 | return true 58 | } 59 | 60 | var blockChain []Block 61 | type Trustee struct{ 62 | name string 63 | votes int 64 | } 65 | 66 | type trusteeList [] Trustee 67 | 68 | func (_trusteeList trusteeList) Len() int{ 69 | return len(_trusteeList) 70 | } 71 | 72 | func (_trusteeList trusteeList) Swap(i,j int){ 73 | _trusteeList[i],_trusteeList[j] = _trusteeList[j],_trusteeList[i] 74 | } 75 | 76 | func (_trusteeList trusteeList) Less(i,j int) bool{ 77 | return _trusteeList[j].votes < _trusteeList[i].votes 78 | } 79 | 80 | func selecTrustee()([]Trustee){ 81 | _trusteeList := []Trustee{ 82 | {"node1", rand.Intn(100)}, 83 | {"node2", rand.Intn(100)}, 84 | {"node3", rand.Intn(100)}, 85 | {"node4", rand.Intn(100)}, 86 | {"node5", rand.Intn(100)}, 87 | {"node6", rand.Intn(100)}, 88 | {"node7", rand.Intn(100)}, 89 | {"node8", rand.Intn(100)}, 90 | {"node9", rand.Intn(100)}, 91 | {"node10", rand.Intn(100)}, 92 | {"node11", rand.Intn(100)}, 93 | {"node12", rand.Intn(100)}, 94 | } 95 | sort.Sort(trusteeList(_trusteeList)) 96 | result := _trusteeList[:5] 97 | _trusteeList = result[1:] 98 | _trusteeList = append(_trusteeList, result[0]) 99 | fmt.Println("当前超级节点代表列表是:",_trusteeList) 100 | return _trusteeList 101 | } 102 | 103 | func main(){ 104 | t := time.Now() 105 | genesisBlock := Block{0, t.String(),0,createBlockHash(Block{}),"",""} 106 | fmt.Println("创世块block: ", genesisBlock) 107 | blockChain = append(blockChain, genesisBlock) 108 | var trustee Trustee 109 | for _, trustee = range selecTrustee(){ 110 | _BPM := rand.Intn(100) 111 | blockHeight := len(blockChain) 112 | oldBlock := blockChain[blockHeight-1] 113 | newBlock,err := generateBlock(oldBlock, _BPM, trustee.name) 114 | if err!=nil{ 115 | fmt.Println("新生成区块失败:",err) 116 | continue 117 | } 118 | if isBlockValid(newBlock, oldBlock){ 119 | blockChain = append(blockChain, newBlock) 120 | fmt.Println("当前操作区块节点为:", trustee.name) 121 | fmt.Println("当前区块数:", len(blockChain)) 122 | fmt.Println("当前区块信息:", blockChain[len(blockChain)-1]) 123 | } 124 | } 125 | } 126 | 127 | 128 | 129 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 zdYng 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DPOS 2 | Delegated proof of Stake 3 | > ### DPOS原理 4 | 5 | DPOS全称Delegated proof of Stake,中文是委托权益证明。 6 | 7 | 可以理解为整个区块链网络有许多节点,我们需要选出一些节点作为代表来维护整个区块链网络,这些代表需要保证区块链的安全和性能,不需要通过POS算力竞争了,节约能源。 8 | 9 | > ### DPOS规则 10 | 他们可以生产区块,如果不称职就会被踢出代表列表重新选举。这里的选举最少需要整个网络一半的节点通过则证明去中心化的有效投票。 11 | 12 | DPOS算法要求随机指定代表列表的顺序,不按照顺序生成区块的是无效的,每个周期会重新洗牌一次,打乱原有顺序。代表之间不存在争夺情况,不会遗漏区块,定时会出现一个区块,这就使共识达成的时间周期大大缩短,这也是相对于POS,POW的优点所在。 13 | 14 | > ### DPOS奖励机制 15 | 16 | DPOS因为每秒可以处理确认比POW和POS大上几个数量级的交易量,会将一部分交易作为奖励给网络维护节点和投票者,作为代表选举维护的奖励,让更多的节点参与进来。 17 | 18 | > ### Golang实现DPOS算法 19 | 20 | #### 包引入 21 | 22 | ``` 23 | package main 24 | 25 | import ( 26 | "crypto/sha256" 27 | "encoding/hex" 28 | "fmt" 29 | "math/rand" 30 | "sort" 31 | "time" 32 | ) 33 | ``` 34 | 35 | #### 区块结构体定义 36 | 37 | ``` golang 38 | type Block struct { 39 | Index int 40 | TimeStamp string 41 | BPM int 42 | Hash string 43 | PrevHash string 44 | Delegate string 45 | } 46 | ``` 47 | 48 | #### 创建新区块 49 | 50 | ```golang 51 | func generateBlock(oldBlock Block, _BMP int , address string)(Block, error){ 52 | var newBlock Block 53 | t := time.Now() 54 | 55 | newBlock.Index = oldBlock.Index + 1 56 | newBlock.TimeStamp = t.String() 57 | newBlock.BPM = _BMP 58 | newBlock.PrevHash = oldBlock.Hash 59 | newBlock.Hash = createBlockHash(newBlock) 60 | newBlock.Delegate = address 61 | fmt.Println("NewBlock: ", newBlock) 62 | return newBlock, nil 63 | } 64 | ``` 65 | 66 | #### 生成区块的hash 67 | 68 | ```golang 69 | 70 | func createBlockHash(block Block) string{ 71 | record := string(block.Index) + block.TimeStamp + string(block.BPM) + block.PrevHash 72 | sha3 := sha256.New() 73 | sha3.Write([] byte(record)) 74 | hash := sha3.Sum(nil) 75 | fmt.Println("NewHash: ",hex.EncodeToString(hash)) 76 | return hex.EncodeToString(hash) 77 | } 78 | ``` 79 | 80 | #### 检查新区块是否合法 81 | 82 | ``` 83 | func isBlockValid(newBlock, oldBlock Block) bool{ 84 | if oldBlock.Index + 1 != newBlock.Index{ 85 | fmt.Println("失败!!index非法") 86 | return false 87 | } 88 | if newBlock.PrevHash != oldBlock.Hash{ 89 | fmt.Println("失败!!PrevHash非法") 90 | return false 91 | } 92 | fmt.Println("合法") 93 | return true 94 | } 95 | ``` 96 | 97 | #### 定义区块链,代表,代表列表 98 | 99 | ``` 100 | var blockChain []Block 101 | type Trustee struct{ 102 | name string 103 | votes int 104 | } 105 | 106 | type trusteeList [] Trustee 107 | ``` 108 | 109 | #### 代表排序 110 | ``` 111 | func (_trusteeList trusteeList) Len() int{ 112 | return len(_trusteeList) 113 | } 114 | 115 | func (_trusteeList trusteeList) Swap(i,j int){ 116 | _trusteeList[i],_trusteeList[j] = _trusteeList[j],_trusteeList[i] 117 | } 118 | 119 | func (_trusteeList trusteeList) Less(i,j int) bool{ 120 | return _trusteeList[j].votes < _trusteeList[i].votes 121 | } 122 | ``` 123 | 124 | #### 代表列表生成 125 | 126 | ``` 127 | 128 | func selecTrustee()([]Trustee){ 129 | _trusteeList := []Trustee{ 130 | {"node1", rand.Intn(100)}, 131 | {"node2", rand.Intn(100)}, 132 | {"node3", rand.Intn(100)}, 133 | {"node4", rand.Intn(100)}, 134 | {"node5", rand.Intn(100)}, 135 | {"node6", rand.Intn(100)}, 136 | {"node7", rand.Intn(100)}, 137 | {"node8", rand.Intn(100)}, 138 | {"node9", rand.Intn(100)}, 139 | {"node10", rand.Intn(100)}, 140 | {"node11", rand.Intn(100)}, 141 | {"node12", rand.Intn(100)}, 142 | } 143 | sort.Sort(trusteeList(_trusteeList)) 144 | result := _trusteeList[:5] 145 | _trusteeList = result[1:] 146 | _trusteeList = append(_trusteeList, result[0]) 147 | fmt.Println("当前超级节点代表列表是:",_trusteeList) 148 | return _trusteeList 149 | } 150 | ``` 151 | 152 | #### main函数部分 153 | 154 | ``` 155 | func main(){ 156 | t := time.Now() 157 | //模拟创世块的生成,实际要复杂一些 158 | genesisBlock := Block{0, t.String(),0,createBlockHash(Block{}),"",""} 159 | fmt.Println("创世块block: ", genesisBlock) 160 | blockChain = append(blockChain, genesisBlock) 161 | var trustee Trustee 162 | for _, trustee = range selecTrustee(){ 163 | _BPM := rand.Intn(100) 164 | blockHeight := len(blockChain) 165 | oldBlock := blockChain[blockHeight-1] 166 | newBlock,err := generateBlock(oldBlock, _BPM, trustee.name) 167 | if err!=nil{ 168 | fmt.Println("新生成区块失败:",err) 169 | continue 170 | } 171 | if isBlockValid(newBlock, oldBlock){ 172 | blockChain = append(blockChain, newBlock) 173 | fmt.Println("当前操作区块节点为:", trustee.name) 174 | fmt.Println("当前区块数:", len(blockChain)) 175 | fmt.Println("当前区块信息:", blockChain[len(blockChain)-1]) 176 | } 177 | } 178 | } 179 | ``` 180 | 181 | #### 运行截图 182 | 183 | ![](https://user-gold-cdn.xitu.io/2019/11/7/16e439af726def57?w=1810&h=609&f=png&s=110717) 184 | 185 | ![](https://user-gold-cdn.xitu.io/2019/11/7/16e439b469dd1ffc?w=1786&h=412&f=png&s=62870) 186 | 187 | #### 结尾 188 | 大家也可以试试,区块链还是很有意思的啊~~~~~ 189 | --------------------------------------------------------------------------------