github.com/ebakus/go-ebakus@v1.0.5-0.20200520105415-dbccef9ec421/consensus/dpos/state.go (about)

     1  // Copyright 2019 The ebakus/go-ebakus Authors
     2  // This file is part of the ebakus/go-ebakus library.
     3  //
     4  // The ebakus/go-ebakus 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 ebakus/go-ebakus 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 ebakus/go-ebakus library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package dpos
    18  
    19  import (
    20  	"encoding/json"
    21  	"fmt"
    22  	"math/big"
    23  	"sort"
    24  
    25  	"github.com/ebakus/go-ebakus/common"
    26  	"github.com/ebakus/go-ebakus/consensus"
    27  	"github.com/ebakus/go-ebakus/core/types"
    28  	"github.com/ebakus/go-ebakus/ethdb"
    29  	"github.com/ebakus/go-ebakus/log"
    30  	"github.com/ebakus/go-ebakus/params"
    31  )
    32  
    33  const (
    34  	// The account wants to be witness and will be considered for block producer
    35  	// by stake delegation
    36  	ElectEnabledFlag uint64 = 1
    37  )
    38  
    39  type Witness struct {
    40  	Addr      common.Address
    41  	Flags     uint64
    42  	Stake     *big.Int
    43  	VoteCount uint64
    44  }
    45  
    46  func newWitness(addr common.Address) *Witness {
    47  	return &Witness{
    48  		Addr:      addr,
    49  		Flags:     0,
    50  		Stake:     big.NewInt(0),
    51  		VoteCount: 0,
    52  	}
    53  }
    54  
    55  type WitnessArray []*Witness
    56  
    57  func (s WitnessArray) Len() int { return len(s) }
    58  
    59  func (s WitnessArray) Less(i, j int) bool {
    60  	return s[i].Stake.Cmp(s[j].Stake) == -1
    61  }
    62  
    63  func (s WitnessArray) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
    64  
    65  func (s WitnessArray) Diff(b WitnessArray) types.DelegateDiff {
    66  	r := make(types.DelegateDiff, 0)
    67  
    68  	for i, d := range b {
    69  		found := false
    70  		for j, from := range s {
    71  			if from.Addr == d.Addr {
    72  				if i != j {
    73  					r = append(r, types.DelegateItem{Pos: byte(i), DelegateAddress: common.Address{}, DelegateNumber: byte(j)})
    74  				}
    75  				found = true
    76  				break
    77  			}
    78  		}
    79  		if !found {
    80  			r = append(r, types.DelegateItem{Pos: byte(i), DelegateAddress: d.Addr, DelegateNumber: 0})
    81  		}
    82  	}
    83  
    84  	return r
    85  }
    86  
    87  // getData returns a slice from the data based on the start and size and pads
    88  // up to size with zero's. This function is overflow safe.
    89  func getData(data []byte, start uint64, size uint64) []byte {
    90  	length := uint64(len(data))
    91  	if start > length {
    92  		start = length
    93  	}
    94  	end := start + size
    95  	if end > length {
    96  		end = length
    97  	}
    98  	return common.RightPadBytes(data[start:end], int(size))
    99  }
   100  
   101  // State holds the information for the current delegate sealing
   102  // procedure at a specific point in time
   103  type State struct {
   104  	config *params.DPOSConfig
   105  
   106  	BlockNum  uint64
   107  	Hash      common.Hash
   108  	Witnesses map[common.Address]*Witness
   109  }
   110  
   111  func newState(config *params.DPOSConfig, blockNum uint64, hash common.Hash) *State {
   112  	state := &State{
   113  		config: config,
   114  
   115  		BlockNum:  blockNum,
   116  		Hash:      hash,
   117  		Witnesses: make(map[common.Address]*Witness),
   118  	}
   119  	return state
   120  }
   121  
   122  func (s *State) copy() *State {
   123  	c := &State{
   124  		config: s.config,
   125  
   126  		BlockNum:  s.BlockNum,
   127  		Hash:      s.Hash,
   128  		Witnesses: make(map[common.Address]*Witness),
   129  	}
   130  
   131  	for wit := range s.Witnesses {
   132  		c.Witnesses[wit] = s.Witnesses[wit]
   133  	}
   134  
   135  	return c
   136  }
   137  
   138  func retrieve(config *params.DPOSConfig, db ethdb.Database, hash common.Hash) (*State, error) {
   139  	blob, err := db.Get(append([]byte("dpos-"), hash[:]...))
   140  	if err != nil {
   141  		return nil, err
   142  	}
   143  
   144  	state := new(State)
   145  	if err := json.Unmarshal(blob, state); err != nil {
   146  		return nil, err
   147  	}
   148  
   149  	return state, nil
   150  }
   151  
   152  func (s *State) store(db ethdb.Database, hash common.Hash) error {
   153  	blob, err := json.Marshal(s)
   154  	if err != nil {
   155  		return err
   156  	}
   157  	return db.Put(append([]byte("dpos-"), hash[:]...), blob)
   158  }
   159  
   160  func (s *State) apply(chain consensus.ChainReader, header *types.Header) (*State, error) {
   161  	if header == nil {
   162  		return s, nil
   163  	}
   164  
   165  	if header.Number.Uint64() != s.BlockNum+1 {
   166  		return nil, errInvalidStateHeaderAlignment
   167  	}
   168  
   169  	state := s.copy()
   170  
   171  	number := header.Number.Uint64()
   172  
   173  	block := chain.GetBlock(header.Hash(), number)
   174  	if block == nil {
   175  		log.Info("Failed GetBlock()")
   176  		return nil, fmt.Errorf("block not found")
   177  	}
   178  
   179  	state.BlockNum++
   180  	state.Hash = header.Hash()
   181  
   182  	return state, nil
   183  }
   184  
   185  func (s *State) addWitness(addr common.Address, stake *big.Int) {
   186  	w := &Witness{
   187  		Addr:  addr,
   188  		Stake: stake,
   189  	}
   190  	s.Witnesses[addr] = w
   191  }
   192  
   193  func (s *State) removeWitness(addr common.Address) {
   194  	delete(s.Witnesses, addr)
   195  }
   196  
   197  func (s *State) getDelegates(maxDelegates int) WitnessArray {
   198  	dels := make(WitnessArray, len(s.Witnesses))
   199  	i := 0
   200  	for _, w := range s.Witnesses {
   201  		dels[i] = w
   202  		i++
   203  	}
   204  	sort.Sort(dels)
   205  	start := len(dels) - maxDelegates
   206  	if start < 0 {
   207  		start = 0
   208  	}
   209  	return dels[start:len(dels)]
   210  }
   211  
   212  func (s *State) logDelegates(maxDelegates int) {
   213  	ds := s.getDelegates(maxDelegates)
   214  	for i, d := range ds {
   215  		log.Trace("Delegate", "i", i, "addr", d.Addr, "stake", d.Stake)
   216  	}
   217  }