github.com/n1ghtfa1l/go-vnt@v0.6.4-alpha.6/consensus/dpos/manager.go (about) 1 // Copyright 2019 The go-vnt Authors 2 // This file is part of the go-vnt library. 3 // 4 // The go-vnt library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-vnt library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-vnt library. If not, see <http://www.gnu.org/licenses/>. 16 17 package dpos 18 19 import ( 20 "bytes" 21 "errors" 22 "fmt" 23 "github.com/vntchain/go-vnt/common" 24 "github.com/vntchain/go-vnt/log" 25 "math/big" 26 ) 27 28 // Manager is used to judge weather a witness is block producer or not. 29 // - Check weather a witness is block producer or not 30 // - Check weather a witness is in witness list 31 type Manager struct { 32 blockPeriod uint64 // Period of producing a block 33 Witnesses []common.Address // Witness list, all current witness 34 } 35 36 // NewManager creating a dpos witness manager 37 func NewManager(period uint64, witnesses []common.Address) *Manager { 38 wm := &Manager{ 39 blockPeriod: period, 40 Witnesses: witnesses, 41 } 42 return wm 43 } 44 45 // inTurn check whether witness is the block producer at witTime 46 func (m *Manager) inTurn(witness, pWitness common.Address, witTime, pWitTime *big.Int) bool { 47 // sanity check 48 if witTime.Cmp(pWitTime) <= 0 { 49 log.Debug("Time is early") 50 return false 51 } 52 witIndex := m.indexOf(witness) 53 pIndex := m.indexOf(pWitness) 54 if witIndex == -1 { 55 log.Warn("You are not in the witnesses list", "addr", witness) 56 return false 57 } 58 if pIndex == -1 { 59 log.Warn("Previous witness is not in the witnesses list", "preWitness", pWitness) 60 return false 61 } 62 63 // calc offset with timestamp 64 dur := new(big.Int).Sub(witTime, pWitTime) 65 period := new(big.Int).SetUint64(m.blockPeriod) 66 left := big.NewInt(0) 67 nPeriod, left := new(big.Int).DivMod(dur, period, left) 68 if left.Cmp(big.NewInt(0)) != 0 { 69 nPeriod.Add(nPeriod, big.NewInt(1)) // witTime in next period 70 } 71 72 // make sure offset in an safety range:[0, len(m.Witnesses)) 73 offset := big.NewInt(0) 74 nWitness := big.NewInt(int64(len(m.Witnesses))) 75 _, offset = new(big.Int).DivMod(nPeriod, nWitness, offset) 76 77 iOffset := int(offset.Int64()) 78 79 // get block producer's index by offset 80 targetIndex, err := m.moveIndex(pIndex, iOffset) 81 if err != nil { 82 log.Warn(err.Error()) 83 return false 84 } 85 86 // match curIndex and witIndex 87 if targetIndex == witIndex { 88 return true 89 } 90 91 log.Debug("witness index is not match", "targetIndex", targetIndex, "witIndex", witIndex) 92 return false 93 } 94 95 // indexOf get the index of witness in witness list 96 func (m *Manager) indexOf(witness common.Address) int { 97 for i := 0; i < len(m.Witnesses); i++ { 98 if addressEqual(m.Witnesses[i], witness) { 99 return i 100 } 101 } 102 return -1 103 } 104 105 // has check whether witness is in witness list 106 func (m *Manager) has(witness common.Address) bool { 107 return -1 != m.indexOf(witness) 108 } 109 110 // moveIndex move the index with offset 111 func (m *Manager) moveIndex(cur int, off int) (int, error) { 112 if cur < 0 || cur > len(m.Witnesses) { 113 log.Warn("Current index is out of range", "index", cur, "range", len(m.Witnesses)-1) 114 return -1, errors.New("invalid current index") 115 } 116 117 cur += off 118 cur = cur % len(m.Witnesses) 119 return cur, nil 120 } 121 122 // dump witness list 123 func (m *Manager) dump() { 124 fmt.Println("Witness list:") 125 for _, wit := range m.Witnesses { 126 fmt.Printf("%x \n", wit) 127 } 128 } 129 130 // addressEqual check wether two address is queal 131 func addressEqual(addr1, addr2 common.Address) bool { 132 return bytes.Equal(addr1[:], addr2[:]) 133 }