-
Notifications
You must be signed in to change notification settings - Fork 60
/
besu.go
122 lines (110 loc) · 3 KB
/
besu.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
package chains
import (
"bytes"
"fmt"
"github.com/ethereum/go-ethereum/common"
gethtypes "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/rlp"
)
type ConsensusType uint8
const (
Unspecified ConsensusType = iota
IBFT2
QBFT
)
func (c ConsensusType) String() string {
switch c {
case IBFT2:
return "IBFT2"
case QBFT:
return "QBFT"
default:
return "Unspecified"
}
}
type ParsedHeader struct {
Base *gethtypes.Header
Vanity []byte
Validators []common.Address
Vote interface{}
Round []byte
Seals [][]byte
}
func ParseHeader(header *gethtypes.Header) (*ParsedHeader, error) {
parsed := ParsedHeader{Base: header}
r := bytes.NewReader(header.Extra)
stream := rlp.NewStream(r, 0)
if _, err := stream.List(); err != nil {
return nil, fmt.Errorf("failed to decode list: %w", err)
}
if err := stream.Decode(&parsed.Vanity); err != nil {
return nil, fmt.Errorf("failed to decode vanity: %w", err)
}
if err := stream.Decode(&parsed.Validators); err != nil {
return nil, fmt.Errorf("failed to decode validators: %w", err)
}
if err := stream.Decode(&parsed.Vote); err != nil {
return nil, fmt.Errorf("failed to decode vote: %w", err)
}
if err := stream.Decode(&parsed.Round); err != nil {
return nil, fmt.Errorf("failed to decode round: %w", err)
}
if err := stream.Decode(&parsed.Seals); err != nil {
return nil, fmt.Errorf("failed to decode seals: %w", err)
}
if err := stream.ListEnd(); err != nil {
return nil, fmt.Errorf("failed to decode list end: %w", err)
}
return &parsed, nil
}
func (h ParsedHeader) GetSealingHeaderBytes(consensusType ConsensusType) ([]byte, error) {
newHeader := *h.Base
// IBFT2: {Vanity, Validators, Vote, Round}
// QBFT: {Vanity, Validators, Vote, Round, Empty-Seals}
if consensusType == IBFT2 {
extra, err := rlp.EncodeToBytes([]interface{}{
h.Vanity, h.Validators, h.Vote, h.Round,
})
if err != nil {
return nil, err
}
newHeader.Extra = extra
} else if consensusType == QBFT {
extra, err := rlp.EncodeToBytes([]interface{}{
h.Vanity, h.Validators, h.Vote, h.Round, [][]byte{},
})
if err != nil {
return nil, err
}
newHeader.Extra = extra
} else {
return nil, fmt.Errorf("unsupported consensus type: %v", consensusType)
}
return rlp.EncodeToBytes(&newHeader)
}
func (h ParsedHeader) ValidateAndGetCommitSeals(consensusType ConsensusType) ([][]byte, error) {
header, err := h.GetSealingHeaderBytes(consensusType)
if err != nil {
return nil, err
}
vals, err := RecoverCommitterAddressesVals(crypto.Keccak256(header), h.Seals)
if err != nil {
return nil, err
}
var newSeals [][]byte
count := 0
for _, val := range h.Validators {
if seal, ok := vals[val]; ok {
count++
newSeals = append(newSeals, seal)
} else {
newSeals = append(newSeals, nil)
}
}
if threshold := len(h.Validators) * 2 / 3; count > threshold {
return newSeals, nil
} else {
return nil, fmt.Errorf("insufficient voting: %v > %v", count, threshold)
}
}