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 }