OSDN Git Service

Add the basic framework for voting processing for dpos
[bytom/vapor.git] / consensus / consensus / vote.go
1 package consensus
2
3 import (
4         "encoding/json"
5         "os"
6         "path/filepath"
7         "sync"
8
9         "github.com/vapor/config"
10
11         "github.com/vapor/consensus"
12         "github.com/vapor/protocol/bc"
13 )
14
15 const (
16         VoteFile                 = "vote.dat"
17         DelegateFile             = "delegate.dat"
18         BalanceFile              = "balance.dat"
19         ControlFile              = "control.dat"
20         InvalidVoteTxFile        = "invalidvotetx.dat"
21         DelegateMultiAddressFile = "delegatemultiaddress.dat"
22
23         ForgerFile = "forger.data"
24 )
25
26 type AddressBalance struct {
27         Address string
28         Balance int64
29 }
30
31 type Vote struct {
32         DelegateVoters            map[string]map[string]bool
33         VoterDelegates            map[string]map[string]bool
34         lockVoter                 sync.Mutex
35         DelegateName              map[string]string
36         NameDelegate              map[string]string
37         lockRegister              sync.Mutex
38         HashHeightInvalidVote     map[bc.Hash]uint64
39         lockHashHeightInvalidVote sync.Mutex
40         AddressBalances           map[string]uint64
41         DelegateMultiaddress      map[string]uint64
42
43         filePath                 string
44         delegateFileName         string
45         voteFileName             string
46         balanceFileName          string
47         controlFileName          string
48         invalidVoteTxFileName    string
49         delegateMultiaddressName string
50
51         forgerFileName string
52
53         oldBlockHeight uint64
54         oldBlockHash   bc.Hash
55 }
56
57 var DposVote = Vote{}
58
59 func (v *Vote) new(blockHeight uint64, blockHash bc.Hash) error {
60         //DefaultDataDir
61         v.filePath = filepath.Join(config.DefaultDataDir(), "dpos")
62         v.delegateFileName = filepath.Join(v.filePath, DelegateFile)
63         v.balanceFileName = filepath.Join(v.filePath, BalanceFile)
64         v.controlFileName = filepath.Join(v.filePath, ControlFile)
65         v.invalidVoteTxFileName = filepath.Join(v.filePath, InvalidVoteTxFile)
66         v.delegateMultiaddressName = filepath.Join(v.filePath, DelegateMultiAddressFile)
67         v.forgerFileName = filepath.Join(v.filePath, ForgerFile)
68         if blockHeight == 0 {
69                 if _, err := os.Stat(v.filePath); os.IsNotExist(err) {
70                         err := os.MkdirAll(v.filePath, 0700)
71                         if err != nil {
72                                 //return fmt.Errorf("Could not create directory %v. %v", dir, err)
73                                 return err
74                         }
75                 }
76         } else {
77                 if err := v.load(blockHeight, blockHash); err != nil {
78                         return err
79                 }
80         }
81         return nil
82 }
83
84 func (v *Vote) ProcessRegister(delegateAddress string, delegateName string, hash bc.Hash, height uint64) bool {
85         v.lockRegister.Lock()
86         defer v.lockRegister.Unlock()
87         if _, ok := v.DelegateName[delegateAddress]; !ok {
88                 v.AddInvalidVote(hash, height)
89                 return false
90         }
91
92         if _, ok := v.NameDelegate[delegateName]; !ok {
93                 v.AddInvalidVote(hash, height)
94                 return false
95         }
96
97         v.DelegateName[delegateAddress] = delegateName
98         v.NameDelegate[delegateName] = delegateAddress
99         return true
100 }
101
102 func (v *Vote) ProcessVote(voterAddress string, delegates []string, hash bc.Hash, height uint64) bool {
103         v.lockVoter.Lock()
104         defer v.lockVoter.Unlock()
105
106         votes := 0
107
108         if delegates, ok := v.VoterDelegates[voterAddress]; ok {
109                 votes = len(delegates)
110         }
111
112         if votes+len(delegates) > consensus.MaxNumberOfVotes {
113                 v.AddInvalidVote(hash, height)
114                 return false
115         }
116
117         for _, delegate := range delegates {
118                 if _, ok := v.DelegateName[delegate]; !ok {
119                         v.AddInvalidVote(hash, height)
120                         return false
121                 }
122                 if voters, ok := v.DelegateVoters[delegate]; ok {
123                         if _, ok = voters[voterAddress]; ok {
124                                 v.AddInvalidVote(hash, height)
125                                 return false
126                         } else {
127                                 v.DelegateVoters[delegate][voterAddress] = true
128                         }
129                 } else {
130                         v.DelegateVoters[delegate][voterAddress] = true
131                 }
132                 v.VoterDelegates[voterAddress][delegate] = true
133         }
134
135         return true
136 }
137
138 func (v *Vote) ProcessCancelVote(voterAddress string, delegates []string, hash bc.Hash, height uint64) bool {
139         v.lockVoter.Lock()
140         defer v.lockVoter.Unlock()
141
142         for _, delegate := range delegates {
143                 if voters, ok := v.DelegateVoters[delegate]; ok {
144                         if _, ok = voters[voterAddress]; !ok {
145                                 v.AddInvalidVote(hash, height)
146                                 return false
147                         } else {
148                                 if len(voters) == 1 {
149                                         delete(v.DelegateVoters, delegate)
150                                 } else {
151                                         delete(v.DelegateVoters[delegate], voterAddress)
152                                 }
153                         }
154                 } else {
155                         v.AddInvalidVote(hash, height)
156                         return false
157                 }
158         }
159
160         if item, ok := v.VoterDelegates[voterAddress]; ok {
161                 for _, delegate := range delegates {
162                         delete(v.VoterDelegates[voterAddress], delegate)
163                 }
164                 if len(item) == 0 {
165                         delete(v.VoterDelegates, voterAddress)
166                 }
167         }
168
169         return true
170 }
171
172 func (v *Vote) AddInvalidVote(hash bc.Hash, height uint64) {
173         v.lockHashHeightInvalidVote.Lock()
174         defer v.lockHashHeightInvalidVote.Unlock()
175         v.HashHeightInvalidVote[hash] = height
176 }
177
178 func (v *Vote) load(blockHeight uint64, blockHash bc.Hash) error {
179         if err := v.repairFile(blockHeight, blockHash); err != nil {
180                 return err
181         }
182         return v.read()
183 }
184
185 func (v *Vote) Delete(blockHash bc.Hash) {
186         os.Remove(v.delegateFileName + "-" + blockHash.String())
187         os.Remove(v.voteFileName + "-" + blockHash.String())
188         os.Remove(v.balanceFileName + "-" + blockHash.String())
189 }
190
191 func (v *Vote) Store(blockHeight uint64, blockHash bc.Hash) error {
192         if blockHeight == 0 {
193                 return nil
194         }
195         if err := v.Write(blockHash); err != nil {
196                 return err
197         }
198
199         if err := v.WriteControlFile(blockHeight, blockHash, v.controlFileName+"-temp"); err != nil {
200                 return err
201         }
202
203         var (
204                 blockHeightTemp uint64
205                 blockHashTemp   bc.Hash
206         )
207
208         if err := v.ReadControlFile(&blockHeightTemp, &blockHashTemp, v.controlFileName); err != nil {
209                 return err
210         }
211
212         os.Rename(v.controlFileName, v.controlFileName+"-old")
213         os.Rename(v.controlFileName+"-temp", v.controlFileName)
214         os.Remove(v.controlFileName + "-old")
215
216         return nil
217 }
218
219 type forger struct {
220         DelegateVoters        map[string]map[string]bool `json:"delegate_voters"`
221         VoterDelegates        map[string]map[string]bool `json:"voter_delegates"`
222         DelegateName          map[string]string          `json:"delegate_name"`
223         NameDelegate          map[string]string          `json:"name_delegate"`
224         HashHeightInvalidVote map[bc.Hash]uint64         `json:"hash_height_invalid_vote"`
225         AddressBalances       map[string]uint64          `json:"address_balance"`
226         DelegateMultiaddress  map[string]uint64          `json:"delegate_multiaddress"`
227 }
228
229 func (v *Vote) Write(blockHash bc.Hash) error {
230
231         f := forger{
232                 DelegateVoters:        v.DelegateVoters,
233                 VoterDelegates:        v.VoterDelegates,
234                 DelegateName:          v.DelegateName,
235                 NameDelegate:          v.NameDelegate,
236                 HashHeightInvalidVote: v.HashHeightInvalidVote,
237                 AddressBalances:       v.AddressBalances,
238                 DelegateMultiaddress:  v.DelegateMultiaddress,
239         }
240
241         fileObj, err := os.OpenFile(v.forgerFileName+"-"+blockHash.String(), os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644)
242         if err != nil {
243                 return err
244         }
245         defer fileObj.Close()
246
247         var data []byte
248
249         if data, err = json.Marshal(&f); err != nil {
250                 return err
251         }
252
253         if _, err = fileObj.Write(data); err != nil {
254                 return err
255         }
256
257         return nil
258 }
259
260 func (v *Vote) read() error {
261
262         if err := v.ReadControlFile(&v.oldBlockHeight, &v.oldBlockHash, v.controlFileName); err != nil {
263                 return err
264         }
265
266         fileObj, err := os.OpenFile(v.forgerFileName+"-"+v.oldBlockHash.String(), os.O_RDONLY, 0644)
267         if err != nil {
268                 return err
269         }
270
271         var data []byte
272
273         if _, err = fileObj.Read(data); err != nil {
274                 return err
275         }
276
277         f := &forger{}
278
279         if err = json.Unmarshal(data, f); err != nil {
280                 return err
281         }
282
283         v.DelegateVoters = f.DelegateVoters
284         v.VoterDelegates = f.VoterDelegates
285         v.DelegateName = f.DelegateName
286         v.NameDelegate = f.NameDelegate
287         v.HashHeightInvalidVote = f.HashHeightInvalidVote
288         v.AddressBalances = f.AddressBalances
289         v.DelegateMultiaddress = f.DelegateMultiaddress
290
291         return nil
292 }
293
294 func (v *Vote) repairFile(blockHeight uint64, blockHash bc.Hash) error {
295         return nil
296 }
297
298 func (v *Vote) GetTopDelegateInfo(minHoldBalance uint64, delegateNum uint64) []Delegate {
299         var result []Delegate
300
301         return result
302 }
303
304 type control struct {
305         BlockHeight uint64  `json:"block_height"`
306         BlockHash   bc.Hash `json:"block_hash"`
307 }
308
309 func (v *Vote) ReadControlFile(blockHeight *uint64, blockHash *bc.Hash, fileName string) error {
310
311         fileObj, err := os.OpenFile(fileName, os.O_RDONLY, 0644)
312         if err != nil {
313                 return err
314         }
315
316         var data []byte
317
318         if _, err = fileObj.Read(data); err != nil {
319                 return err
320         }
321
322         c := &control{}
323
324         if err = json.Unmarshal(data, c); err != nil {
325                 return err
326         }
327
328         *blockHash = c.BlockHash
329         *blockHeight = c.BlockHeight
330         return nil
331 }
332
333 func (v *Vote) WriteControlFile(blockHeight uint64, blockHash bc.Hash, fileName string) error {
334
335         fileObj, err := os.OpenFile(fileName, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644)
336         if err != nil {
337                 return err
338         }
339         defer fileObj.Close()
340
341         c := control{
342                 BlockHeight: blockHeight,
343                 BlockHash:   blockHash,
344         }
345
346         var data []byte
347
348         if data, err = json.Marshal(&c); err != nil {
349                 return err
350         }
351
352         if _, err = fileObj.Write(data); err != nil {
353                 return err
354         }
355
356         return nil
357 }
358
359 func (v *Vote) UpdateAddressBalance(AddressBalance []AddressBalance) {
360
361 }