This repository has been archived by the owner on Aug 27, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathinca.go
133 lines (111 loc) · 3.98 KB
/
inca.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
package inca
import (
"bytes"
"crypto/sha1"
"encoding/binary"
"hash/crc32"
"math"
"sort"
"github.com/aperturerobotics/pbobject"
"github.com/golang/protobuf/proto"
"github.com/libp2p/go-libp2p-crypto"
lpeer "github.com/libp2p/go-libp2p-peer"
)
// GetObjectTypeID returns the object type string, used to identify types.
func (g *Genesis) GetObjectTypeID() *pbobject.ObjectTypeID {
return pbobject.NewObjectTypeID("/inca/genesis")
}
// GetObjectTypeID returns the object type string, used to identify types.
func (g *NodeMessage) GetObjectTypeID() *pbobject.ObjectTypeID {
return pbobject.NewObjectTypeID("/inca/node-message")
}
// GetObjectTypeID returns the object type string, used to identify types.
func (g *ValidatorSet) GetObjectTypeID() *pbobject.ObjectTypeID {
return pbobject.NewObjectTypeID("/inca/validator-set")
}
// GetObjectTypeID returns the object type string, used to identify types.
func (g *ChainConfig) GetObjectTypeID() *pbobject.ObjectTypeID {
return pbobject.NewObjectTypeID("/inca/chain-config")
}
// GetObjectTypeID returns the object type string, used to identify types.
func (b *BlockHeader) GetObjectTypeID() *pbobject.ObjectTypeID {
return &pbobject.ObjectTypeID{TypeUuid: "/inca/block-header"}
}
// GetObjectTypeID returns the object type string, used to identify types.
func (b *Block) GetObjectTypeID() *pbobject.ObjectTypeID {
return &pbobject.ObjectTypeID{TypeUuid: "/inca/block"}
}
// GetObjectTypeID returns the object type string, used to identify types.
func (b *Vote) GetObjectTypeID() *pbobject.ObjectTypeID {
return &pbobject.ObjectTypeID{TypeUuid: "/inca/vote"}
}
// Computes the sort heuristic.
// Validators are sorted by crc32 of address and voting power concatinated.
func (v *Validator) ComputeSortHeuristic() uint32 {
votingPowerBin := proto.EncodeVarint(v.GetVotingPower())
appn := make([]byte, len(v.GetPubKey())+len(votingPowerBin))
copy(appn, v.GetPubKey())
copy(appn[len(v.GetPubKey()):], votingPowerBin)
return crc32.ChecksumIEEE(appn)
}
// SortValidators sorts the validator set correctly.
// Validators are sorted by crc32 of address and voting power concatinated.
func (g *ValidatorSet) SortValidators() {
if len(g.GetValidators()) < 2 {
return
}
// less function
validators := g.GetValidators()
sort.Slice(validators, func(i int, j int) bool {
return validators[i].ComputeSortHeuristic() < validators[j].ComputeSortHeuristic()
})
}
func hashBytesUint64(buf []byte, num uint64) [sha1.Size]byte {
var datBuf bytes.Buffer
// TODO: determine if this is consistent
datBuf.Write(buf)
binary.Write(&datBuf, binary.LittleEndian, num)
return sha1.Sum(datBuf.Bytes())
}
// SelectProposer selects a validator from the set to propose.
func (g *ValidatorSet) SelectProposer(lastBlockDigest []byte, height, round uint64) (*Validator, int32) {
var buf bytes.Buffer
h1 := hashBytesUint64(lastBlockDigest[:8], height)
buf.Write(h1[:])
h2 := hashBytesUint64(lastBlockDigest[8:16], round)
buf.Write(h2[:])
var validators []*Validator
var weightSum int32
for _, v := range g.GetValidators() {
if v.GetOperationMode() != Validator_OperationMode_OPERATING {
continue
}
weightSum += int32(v.GetVotingPower())
validators = append(validators, v)
}
// bufCrcK will be between 0 and maxWeight
bufCrcK := int32((float32(crc32.ChecksumIEEE(buf.Bytes())) / float32(math.MaxUint32)) * float32(weightSum))
for _, validator := range validators {
bufCrcK -= int32(validator.GetVotingPower())
if bufCrcK <= 0 {
return validator, weightSum
}
}
return nil, weightSum
}
// ParsePublicKey parses the validator's public key.
func (v *Validator) ParsePublicKey() (crypto.PubKey, error) {
return crypto.UnmarshalPublicKey(v.GetPubKey())
}
// ParsePeerID parses the peer id and public key.
func (v *Validator) ParsePeerID() (lpeer.ID, crypto.PubKey, error) {
pubKey, err := v.ParsePublicKey()
if err != nil {
return lpeer.ID(""), nil, err
}
id, err := lpeer.IDFromPublicKey(pubKey)
if err != nil {
return lpeer.ID(""), nil, err
}
return id, pubKey, nil
}