forked from hyperledger-archives/burrow
/
validators.go
156 lines (141 loc) · 4.63 KB
/
validators.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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
package state
import (
"math/big"
"github.com/hyperledger/burrow/genesis"
"github.com/hyperledger/burrow/acm/validator"
"github.com/hyperledger/burrow/storage"
"github.com/hyperledger/burrow/crypto"
)
// Initialises the validator Ring from the validator storage in forest
func LoadValidatorRing(version int64, ringSize int,
getImmutable func(version int64) (*storage.ImmutableForest, error)) (*validator.Ring, error) {
// In this method we have to page through previous version of the tree in order to reconstruct the in-memory
// ring structure. The corner cases are a little subtle but printing the buckets helps
// The basic idea is to load each version of the tree ringSize back, work out the difference that must have occurred
// between each bucket in the ring, and apply each diff to the ring. Once the ring is full it is symmetrical (up to
// a reindexing). If we are loading a chain whose height is less than the ring size we need to get the initial state
// correct
startVersion := version - int64(ringSize)
if startVersion < 1 {
// The ring will not be fully populated
startVersion = 1
}
var err error
// Read state to pull immutable forests from
rs := &ReadState{}
// Start with an empty ring - we want the initial bucket to have no cumulative power
ring := validator.NewRing(nil, ringSize)
// Load the IAVL state
rs.Forest, err = getImmutable(startVersion)
// Write the validator state at startVersion from IAVL tree into the ring's current bucket delta
err = validator.Write(ring, rs)
if err != nil {
return nil, err
}
// Rotate, now we have [ {bucket 0: cum: {}, delta: {start version changes} }, {bucket 1: cum: {start version changes}, delta {}, ... ]
// which is what we need (in particular we need this initial state if we are loading into a incompletely populated ring
_, _, err = ring.Rotate()
if err != nil {
return nil, err
}
// Rebuild validator Ring
for v := startVersion + 1; v <= version; v++ {
// Update IAVL read state to version of interest
rs.Forest, err = getImmutable(v)
if err != nil {
return nil, err
}
// Calculate the difference between the rings current cum and what is in state at this version
diff, err := validator.Diff(ring.CurrentSet(), rs)
if err != nil {
return nil, err
}
// Write that diff into the ring (just like it was when it was originally written to setPower)
err = validator.Write(ring, diff)
if err != nil {
return nil, err
}
// Rotate just like it was on the original commit
_, _, err = ring.Rotate()
if err != nil {
return nil, err
}
}
// Our ring should be the same up to symmetry in its index so we reindex to regain equality with the version we are loading
// This is the head index we would have had if we had started from version 1 like the chain did
ring.ReIndex(int(version % int64(ringSize)))
return ring, err
}
func (ws *writeState) MakeGenesisValidators(genesisDoc *genesis.GenesisDoc) error {
for _, gv := range genesisDoc.Validators {
err := ws.SetPower(gv.PublicKey, new(big.Int).SetUint64(gv.Amount))
if err != nil {
return err
}
}
return nil
}
func (s *ReadState) Power(id crypto.Address) (*big.Int, error) {
tree, err := s.Forest.Reader(keys.Validator.Prefix())
if err != nil {
return nil, err
}
bs := tree.Get(keys.Validator.KeyNoPrefix(id))
if len(bs) == 0 {
return new(big.Int), nil
}
v, err := validator.Decode(bs)
if err != nil {
return nil, err
}
return v.BigPower(), nil
}
func (s *ReadState) IterateValidators(fn func(id crypto.Addressable, power *big.Int) error) error {
tree, err := s.Forest.Reader(keys.Validator.Prefix())
if err != nil {
return err
}
return tree.Iterate(nil, nil, true, func(_, value []byte) error {
v, err := validator.Decode(value)
if err != nil {
return err
}
return fn(v, v.BigPower())
})
}
func (ws *writeState) AlterPower(id crypto.PublicKey, power *big.Int) (*big.Int, error) {
// AlterPower in ring
flow, err := ws.ring.AlterPower(id, power)
if err != nil {
return nil, err
}
// Set power in versioned state
return flow, ws.setPower(id, power)
}
func (ws *writeState) SetPower(id crypto.PublicKey, power *big.Int) error {
// SetPower in ring
err := ws.ring.SetPower(id, power)
if err != nil {
return err
}
// Set power in versioned state
return ws.setPower(id, power)
}
func (ws *writeState) setPower(id crypto.PublicKey, power *big.Int) error {
tree, err := ws.forest.Writer(keys.Validator.Prefix())
if err != nil {
return err
}
key := keys.Validator.KeyNoPrefix(id.GetAddress())
if power.Sign() == 0 {
tree.Delete(key)
return nil
}
v := validator.New(id, power)
bs, err := v.Encode()
if err != nil {
return err
}
tree.Set(key, bs)
return nil
}