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  }