-
Notifications
You must be signed in to change notification settings - Fork 247
/
candidates.go
119 lines (104 loc) · 3.09 KB
/
candidates.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
// Copyright (c) 2019 The VeChainThor developers
// Distributed under the GNU Lesser General Public License v3.0 software license, see the accompanying
// file LICENSE or <https://www.gnu.org/licenses/lgpl-3.0.html>
package poa
import (
"github.com/vechain/thor/v2/builtin"
"github.com/vechain/thor/v2/builtin/authority"
"github.com/vechain/thor/v2/state"
"github.com/vechain/thor/v2/thor"
)
// Candidates holds candidates list in memory, and tends to be reused in PoA stage without querying from contract.
type Candidates struct {
list []*authority.Candidate
masters map[thor.Address]int // map master address to list index
endorsors map[thor.Address]bool // endorsor bitset
satisfied []int
referenced bool
}
// NewCandidates creates candidates list.
func NewCandidates(list []*authority.Candidate) *Candidates {
masters := make(map[thor.Address]int)
endorsors := make(map[thor.Address]bool)
// enable fast check address role
for i, c := range list {
masters[c.NodeMaster] = i
endorsors[c.Endorsor] = true
}
return &Candidates{
list,
masters,
endorsors,
nil,
false,
}
}
// Copy make a copy.
func (c *Candidates) Copy() *Candidates {
c.referenced = true
copy := *c
return ©
}
// Pick picks a list of proposers, which satisfy preset conditions.
func (c *Candidates) Pick(state *state.State) ([]Proposer, error) {
satisfied := c.satisfied
if len(satisfied) == 0 {
// re-pick
endorsement, err := builtin.Params.Native(state).Get(thor.KeyProposerEndorsement)
if err != nil {
return nil, err
}
mbp, err := builtin.Params.Native(state).Get(thor.KeyMaxBlockProposers)
if err != nil {
return nil, err
}
maxBlockProposers := mbp.Uint64()
if maxBlockProposers == 0 || maxBlockProposers > thor.InitialMaxBlockProposers {
maxBlockProposers = thor.InitialMaxBlockProposers
}
satisfied = make([]int, 0, len(c.list))
for i := 0; i < len(c.list) && uint64(len(satisfied)) < maxBlockProposers; i++ {
bal, err := state.GetBalance(c.list[i].Endorsor)
if err != nil {
return nil, err
}
if bal.Cmp(endorsement) >= 0 {
satisfied = append(satisfied, i)
}
}
c.satisfied = satisfied
}
proposers := make([]Proposer, 0, len(satisfied))
for _, i := range satisfied {
proposers = append(proposers, Proposer{
Address: c.list[i].NodeMaster,
Active: c.list[i].Active,
})
}
return proposers, nil
}
// Update update candidate activity status, by its master address.
// It returns false if the given address is not a master.
func (c *Candidates) Update(addr thor.Address, active bool) bool {
if i, exist := c.masters[addr]; exist {
// something like COW
if c.referenced {
// shallow copy the list
c.list = append([]*authority.Candidate(nil), c.list...)
c.referenced = false
}
copy := *c.list[i]
copy.Active = active
c.list[i] = ©
return true
}
return false
}
// IsEndorsor returns whether an address is an endorsor.
func (c *Candidates) IsEndorsor(addr thor.Address) bool {
return c.endorsors[addr]
}
// InvalidateCache invalidate the result cache of Pick method.
func (c *Candidates) InvalidateCache() {
c.satisfied = nil
}