/
epoch_vote.go
135 lines (115 loc) · 3.59 KB
/
epoch_vote.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
package epoch
import (
"fmt"
"math/big"
"sync"
"github.com/Gessiux/go-crypto"
"github.com/Gessiux/go-db"
"github.com/Gessiux/go-wire"
"github.com/Gessiux/neatchain/chain/log"
"github.com/Gessiux/neatchain/utilities/common"
)
var voteRWMutex sync.RWMutex
// Epoch Validator Vote Set
// Store in the Level DB will be Key + EpochValidatorVoteSet
// Key = string EpochValidatorVoteKey
// Value = []byte EpochValidatorVoteSet
// eg. Key: EpochValidatorVote_1, EpochValidatorVote_2
func calcEpochValidatorVoteKey(epochNumber uint64) []byte {
return []byte(fmt.Sprintf("EpochValidatorVote_%v", epochNumber))
}
type EpochValidatorVoteSet struct {
// Store the Votes
Votes []*EpochValidatorVote
// For fast searching, key = Address Hex (not export)
votesByAddress map[common.Address]*EpochValidatorVote
}
type EpochValidatorVote struct {
Address common.Address
PubKey crypto.PubKey
Amount *big.Int
Salt string
VoteHash common.Hash // VoteHash = Sha3(Address + PubKey + Amount + Salt)
TxHash common.Hash
}
func NewEpochValidatorVoteSet() *EpochValidatorVoteSet {
return &EpochValidatorVoteSet{
Votes: make([]*EpochValidatorVote, 0),
votesByAddress: make(map[common.Address]*EpochValidatorVote),
}
}
// GetVoteByAddress get the Vote from VoteSet by Address Hex Key
func (voteSet *EpochValidatorVoteSet) GetVoteByAddress(address common.Address) (vote *EpochValidatorVote, exist bool) {
voteRWMutex.RLock()
defer voteRWMutex.RUnlock()
vote, exist = voteSet.votesByAddress[address]
return
}
// StoreVote insert or update the Vote into VoteSet by Address Hex Key
func (voteSet *EpochValidatorVoteSet) StoreVote(vote *EpochValidatorVote) {
voteRWMutex.Lock()
defer voteRWMutex.Unlock()
oldVote, exist := voteSet.votesByAddress[vote.Address]
if exist {
// Exist, remove it
index := -1
for i := 0; i < len(voteSet.Votes); i++ {
if voteSet.Votes[i] == oldVote {
index = i
break
}
}
voteSet.Votes = append(voteSet.Votes[:index], voteSet.Votes[index+1:]...)
}
voteSet.votesByAddress[vote.Address] = vote
voteSet.Votes = append(voteSet.Votes, vote)
}
func SaveEpochVoteSet(epochDB db.DB, epochNumber uint64, voteSet *EpochValidatorVoteSet) {
voteRWMutex.Lock()
defer voteRWMutex.Unlock()
epochDB.SetSync(calcEpochValidatorVoteKey(epochNumber), wire.BinaryBytes(*voteSet))
}
func LoadEpochVoteSet(epochDB db.DB, epochNumber uint64) *EpochValidatorVoteSet {
voteRWMutex.RLock()
defer voteRWMutex.RUnlock()
data := epochDB.Get(calcEpochValidatorVoteKey(epochNumber))
if len(data) == 0 {
return nil
} else {
var voteSet EpochValidatorVoteSet
err := wire.ReadBinaryBytes(data, &voteSet)
if err != nil {
log.Error("Load Epoch Vote Set failed", "error", err)
return nil
}
// Fulfill the Vote Map
voteSet.votesByAddress = make(map[common.Address]*EpochValidatorVote)
for _, v := range voteSet.Votes {
voteSet.votesByAddress[v.Address] = v
}
return &voteSet
}
}
func (voteSet *EpochValidatorVoteSet) Copy() *EpochValidatorVoteSet {
if voteSet == nil {
return nil
}
votes_copy := make([]*EpochValidatorVote, 0, len(voteSet.Votes))
votesByAddress_copy := make(map[common.Address]*EpochValidatorVote, len(voteSet.Votes))
for _, vote := range voteSet.Votes {
v := vote.Copy()
votes_copy = append(votes_copy, v)
votesByAddress_copy[vote.Address] = v
}
return &EpochValidatorVoteSet{
Votes: votes_copy,
votesByAddress: votesByAddress_copy,
}
}
func (voteSet *EpochValidatorVoteSet) IsEmpty() bool {
return voteSet == nil || len(voteSet.Votes) == 0
}
func (vote *EpochValidatorVote) Copy() *EpochValidatorVote {
vCopy := *vote
return &vCopy
}