13 cmn "github.com/tendermint/tmlibs/common"
15 "github.com/vapor/config"
16 "github.com/vapor/consensus"
17 engine "github.com/vapor/consensus/consensus"
18 "github.com/vapor/protocol/bc"
23 DelegateFile = "delegate.dat"
24 BalanceFile = "balance.dat"
25 ControlFile = "control.dat"
26 InvalidVoteTxFile = "invalidvotetx.dat"
27 DelegateMultiAddressFile = "delegatemultiaddress.dat"
29 ForgerFile = "forger.data"
33 DelegateVoters map[string]map[string]bool
34 VoterDelegates map[string]map[string]bool
36 DelegateName map[string]string
37 NameDelegate map[string]string
38 lockRegister sync.Mutex
39 HashHeightInvalidVote map[bc.Hash]uint64
40 lockHashHeightInvalidVote sync.Mutex
41 AddressBalances map[string]uint64
42 DelegateMultiaddress map[string]uint64
45 delegateFileName string
47 balanceFileName string
48 controlFileName string
49 invalidVoteTxFileName string
50 delegateMultiaddressName string
60 DelegateVoters: make(map[string]map[string]bool),
61 VoterDelegates: make(map[string]map[string]bool),
62 DelegateName: make(map[string]string),
63 NameDelegate: make(map[string]string),
64 HashHeightInvalidVote: make(map[bc.Hash]uint64),
65 AddressBalances: make(map[string]uint64),
66 DelegateMultiaddress: make(map[string]uint64),
69 func newVote(blockHeight uint64, blockHash bc.Hash) (*Vote, error) {
71 DelegateVoters: make(map[string]map[string]bool),
72 VoterDelegates: make(map[string]map[string]bool),
73 DelegateName: make(map[string]string),
74 NameDelegate: make(map[string]string),
75 HashHeightInvalidVote: make(map[bc.Hash]uint64),
76 AddressBalances: make(map[string]uint64),
77 DelegateMultiaddress: make(map[string]uint64),
80 if err := vote.New(blockHeight, blockHash); err != nil {
87 func (v *Vote) New(blockHeight uint64, blockHash bc.Hash) error {
88 v.filePath = filepath.Join(config.CommonConfig.RootDir, "dpos")
89 v.delegateFileName = filepath.Join(v.filePath, DelegateFile)
90 v.balanceFileName = filepath.Join(v.filePath, BalanceFile)
91 v.controlFileName = filepath.Join(v.filePath, ControlFile)
92 v.invalidVoteTxFileName = filepath.Join(v.filePath, InvalidVoteTxFile)
93 v.delegateMultiaddressName = filepath.Join(v.filePath, DelegateMultiAddressFile)
94 v.forgerFileName = filepath.Join(v.filePath, ForgerFile)
96 if err := cmn.EnsureDir(v.filePath, 0700); err != nil {
100 if err := v.load(blockHeight, blockHash); err != nil {
107 func (v *Vote) ProcessRegister(delegateAddress string, delegateName string, hash bc.Hash, height uint64) bool {
108 v.lockRegister.Lock()
109 defer v.lockRegister.Unlock()
111 if _, ok := v.DelegateName[delegateAddress]; ok {
112 v.AddInvalidVote(hash, height)
115 if _, ok := v.NameDelegate[delegateName]; ok {
116 v.AddInvalidVote(hash, height)
119 v.DelegateName[delegateAddress] = delegateName
120 v.NameDelegate[delegateName] = delegateAddress
124 func (v *Vote) ProcessVote(voterAddress string, delegates []string, hash bc.Hash, height uint64) bool {
126 defer v.lockVoter.Unlock()
130 if delegates, ok := v.VoterDelegates[voterAddress]; ok {
131 votes = len(delegates)
134 if votes+len(delegates) > consensus.MaxNumberOfVotes {
135 v.AddInvalidVote(hash, height)
139 for _, delegate := range delegates {
140 if _, ok := v.DelegateName[delegate]; !ok {
141 v.AddInvalidVote(hash, height)
144 if voters, ok := v.DelegateVoters[delegate]; ok {
145 if _, ok = voters[voterAddress]; ok {
146 v.AddInvalidVote(hash, height)
149 voters[voterAddress] = true
150 v.DelegateVoters[delegate] = voters
153 voters := make(map[string]bool)
154 voters[voterAddress] = true
155 v.DelegateVoters[delegate] = voters
157 if dg, ok := v.VoterDelegates[voterAddress]; ok {
159 v.VoterDelegates[voterAddress] = dg
161 dg := make(map[string]bool)
163 v.VoterDelegates[voterAddress] = dg
169 func (v *Vote) ProcessCancelVote(voterAddress string, delegates []string, hash bc.Hash, height uint64) bool {
171 defer v.lockVoter.Unlock()
173 for _, delegate := range delegates {
174 if voters, ok := v.DelegateVoters[delegate]; ok {
175 if _, ok = voters[voterAddress]; !ok {
176 v.AddInvalidVote(hash, height)
179 if len(voters) == 1 {
180 delete(v.DelegateVoters, delegate)
182 delete(v.DelegateVoters[delegate], voterAddress)
186 v.AddInvalidVote(hash, height)
191 if item, ok := v.VoterDelegates[voterAddress]; ok {
192 for _, delegate := range delegates {
193 delete(v.VoterDelegates[voterAddress], delegate)
196 delete(v.VoterDelegates, voterAddress)
203 func (v *Vote) load(blockHeight uint64, blockHash bc.Hash) error {
204 if err := v.repairFile(blockHeight, blockHash); err != nil {
210 func (v *Vote) Delete(blockHash bc.Hash) {
211 os.Remove(v.delegateFileName + "-" + blockHash.String())
212 os.Remove(v.voteFileName + "-" + blockHash.String())
213 os.Remove(v.balanceFileName + "-" + blockHash.String())
216 func (v *Vote) Store(blockHeight uint64, blockHash bc.Hash) error {
217 if blockHeight == 0 {
220 if err := v.Write(blockHash); err != nil {
224 if err := v.WriteControlFile(blockHeight, blockHash, v.controlFileName+"-temp"); err != nil {
230 blockHeightTemp uint64
231 blockHashTemp bc.Hash
234 if err := v.ReadControlFile(&blockHeightTemp, &blockHashTemp, v.controlFileName); err != nil {
235 os.Rename(v.controlFileName, v.controlFileName+"-old")
236 os.Rename(v.controlFileName+"-temp", v.controlFileName)
237 os.Remove(v.controlFileName + "-old")
239 v.Delete(blockHashTemp)
246 DelegateVoters map[string]map[string]bool `json:"delegate_voters"`
247 VoterDelegates map[string]map[string]bool `json:"voter_delegates"`
248 DelegateName map[string]string `json:"delegate_name"`
249 NameDelegate map[string]string `json:"name_delegate"`
250 HashHeightInvalidVote map[bc.Hash]uint64 `json:"hash_height_invalid_vote"`
251 AddressBalances map[string]uint64 `json:"address_balance"`
252 DelegateMultiaddress map[string]uint64 `json:"delegate_multiaddress"`
255 func (v *Vote) Write(blockHash bc.Hash) error {
258 DelegateVoters: v.DelegateVoters,
259 VoterDelegates: v.VoterDelegates,
260 DelegateName: v.DelegateName,
261 NameDelegate: v.NameDelegate,
262 HashHeightInvalidVote: v.HashHeightInvalidVote,
263 AddressBalances: v.AddressBalances,
264 DelegateMultiaddress: v.DelegateMultiaddress,
266 fileObj, err := os.OpenFile(v.forgerFileName+"-"+blockHash.String(), os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644)
270 defer fileObj.Close()
274 if data, err = json.Marshal(&f); err != nil {
278 if _, err = fileObj.Write(data); err != nil {
285 func (v *Vote) read() error {
287 if err := v.ReadControlFile(&v.oldBlockHeight, &v.oldBlockHash, v.controlFileName); err != nil {
291 data, err := ioutil.ReadFile(v.forgerFileName + "-" + v.oldBlockHash.String())
298 if err = json.Unmarshal(data, f); err != nil {
302 v.DelegateVoters = f.DelegateVoters
303 v.VoterDelegates = f.VoterDelegates
304 v.DelegateName = f.DelegateName
305 v.NameDelegate = f.NameDelegate
306 v.HashHeightInvalidVote = f.HashHeightInvalidVote
307 v.AddressBalances = f.AddressBalances
308 v.DelegateMultiaddress = f.DelegateMultiaddress
313 func (v *Vote) repairFile(blockHeight uint64, blockHash bc.Hash) error {
315 cmn.EnsureDir(v.filePath, 0700)
317 fileName := v.controlFileName + "-temp"
320 blockHeightTmp uint64
324 if cmn.FileExists(fileName) {
325 if err := v.ReadControlFile(&blockHeightTmp, &blockHashTmp, fileName); err != nil {
328 if cmn.FileExists(v.forgerFileName + "-" + blockHashTmp.String()) {
329 os.Rename(fileName, v.controlFileName)
335 fileName = v.controlFileName + "-old"
337 if cmn.FileExists(fileName) {
338 if err := v.ReadControlFile(&blockHeightTmp, &blockHashTmp, fileName); err != nil {
341 if cmn.FileExists(v.forgerFileName + "-" + blockHashTmp.String()) {
342 os.Rename(fileName, v.controlFileName)
348 fileName = v.controlFileName
349 if cmn.FileExists(fileName) {
350 if err := v.ReadControlFile(&blockHeightTmp, &blockHashTmp, fileName); err != nil {
353 if cmn.FileExists(v.forgerFileName + "-" + blockHashTmp.String()) {
358 return fmt.Errorf("repairFile fail in %d height", blockHeightTmp)
361 func (v *Vote) GetTopDelegateInfo(minHoldBalance uint64, delegateNum uint64) []Delegate {
363 defer v.lockVoter.Unlock()
365 var result []Delegate
366 for k, value := range v.DelegateVoters {
368 for address := range value {
369 votes += v.GetAddressBalance(address)
371 if v.GetAddressBalance(k) >= minHoldBalance {
372 result = append(result, Delegate{k, votes})
375 sort.Sort(DelegateWrapper{result, func(p, q *Delegate) bool {
376 if p.Votes < q.Votes {
378 } else if p.Votes > q.Votes {
381 if strings.Compare(p.DelegateAddress, p.DelegateAddress) >= 0 {
388 for k := range v.DelegateName {
389 if uint64(len(result)) >= delegateNum {
392 if v.GetAddressBalance(k) < consensus.MinHoldBalance {
395 if _, ok := v.DelegateVoters[k]; !ok {
396 result = append(result, Delegate{k, 0})
400 result = result[:delegateNum]
404 func (v *Vote) GetAddressBalance(address string) uint64 {
406 if votes, ok := v.AddressBalances[address]; ok {
413 type control struct {
414 BlockHeight uint64 `json:"block_height"`
415 BlockHash bc.Hash `json:"block_hash"`
418 func (v *Vote) ReadControlFile(blockHeight *uint64, blockHash *bc.Hash, fileName string) error {
419 data, err := ioutil.ReadFile(fileName)
425 if err = json.Unmarshal(data, c); err != nil {
429 *blockHash = c.BlockHash
430 *blockHeight = c.BlockHeight
434 func (v *Vote) WriteControlFile(blockHeight uint64, blockHash bc.Hash, fileName string) error {
436 fileObj, err := os.OpenFile(fileName, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644)
440 defer fileObj.Close()
443 BlockHeight: blockHeight,
444 BlockHash: blockHash,
449 if data, err = json.Marshal(&c); err != nil {
453 if _, err = fileObj.Write(data); err != nil {
460 func (v *Vote) UpdateAddressBalance(addressBalance []engine.AddressBalance) {
462 defer v.lockVoter.Unlock()
464 mapBalance := make(map[string]int64)
466 for _, value := range addressBalance {
467 if value.Balance == 0 {
470 mapBalance[value.Address] += value.Balance
472 for addr, balance := range mapBalance {
473 v.updateAddressBalance(addr, balance)
477 func (v *Vote) updateAddressBalance(address string, value int64) {
478 if val, ok := v.AddressBalances[address]; ok {
479 banlance := int64(val) + value
481 cmn.Exit("The balance was negative")
484 delete(v.AddressBalances, address)
486 v.AddressBalances[address] = uint64(banlance)
490 cmn.Exit("The balance was negative")
493 v.AddressBalances[address] = uint64(value)
498 func (v *Vote) AddInvalidVote(hash bc.Hash, height uint64) {
499 v.lockHashHeightInvalidVote.Lock()
500 defer v.lockHashHeightInvalidVote.Unlock()
501 v.HashHeightInvalidVote[hash] = height
503 func (v *Vote) DeleteInvalidVote(height uint64) {
504 v.lockHashHeightInvalidVote.Lock()
505 defer v.lockHashHeightInvalidVote.Unlock()
506 for k, value := range v.HashHeightInvalidVote {
508 delete(v.HashHeightInvalidVote, k)
513 func (v *Vote) GetOldBlockHeight() uint64 {
514 return v.oldBlockHeight
517 func (v *Vote) GetOldBlockHash() bc.Hash {
518 return v.oldBlockHash
521 func (v *Vote) GetDelegate(name string) string {
523 defer v.lockVoter.Unlock()
525 if delegate, ok := v.NameDelegate[name]; ok {
531 func (v *Vote) GetDelegateName(address string) string {
533 defer v.lockVoter.Unlock()
534 if name, ok := v.DelegateName[address]; ok {
540 func (v *Vote) HaveVote(voter string, delegate string) bool {
542 defer v.lockVoter.Unlock()
544 if voters, ok := v.DelegateVoters[delegate]; ok {
545 if _, ok := voters[voter]; ok {
553 func (v *Vote) HaveDelegate(name string, delegate string) bool {
555 defer v.lockVoter.Unlock()
557 if n, ok := v.DelegateName[delegate]; ok {
566 func (v *Vote) GetVotedDelegates(voter string) []string {
568 defer v.lockVoter.Unlock()
570 if delegates, ok := v.VoterDelegates[voter]; ok {
571 for delegate, _ := range delegates {
572 results = append(results, delegate)
578 func (v *Vote) ListDelegates() map[string]string {
580 defer v.lockVoter.Unlock()
581 return v.NameDelegate
584 func (v *Vote) GetDelegateVotes(delegate string) uint64 {
586 if voters, ok := v.DelegateVoters[delegate]; ok {
587 for voter := range voters {
588 votes += v.GetAddressBalance(voter)
594 func (v *Vote) GetDelegateVoters(delegate string) []string {
596 defer v.lockVoter.Unlock()
600 if voters, ok := v.DelegateVoters[delegate]; ok {
601 for voter := range voters {
602 result = append(result, voter)