/
protocol.go
178 lines (140 loc) · 4.66 KB
/
protocol.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
package backend
import (
"errors"
"fmt"
"bitbucket.org/cpchain/chain/types"
"github.com/ethereum/go-ethereum/p2p"
)
const (
// ProtocolName protocol name
ProtocolName = "dpor"
// ProtocolVersion protocol version
ProtocolVersion = 65
// ProtocolLength protocol length, max msg code
ProtocolLength = 100
)
// Protocol messages belonging to cpc/01
const (
// PbftMsgOutset is not a msg code, just used for msg code comparing
PbftMsgOutset = 0x42
// NewSignerMsg is a msg code used for network building
NewSignerMsg = 0x42
// those are messages for normal block verification
PreprepareBlockMsg = 0x43
PrepareHeaderMsg = 0x44
CommitHeaderMsg = 0x45
ValidateBlockMsg = 0x46
// those are messages for abnormal(impeachment) block verification
PreprepareImpeachBlockMsg = 0x47
PrepareImpeachHeaderMsg = 0x48
CommitImpeachHeaderMsg = 0x49
ValidateImpeachBlockMsg = 0x50
)
// ProtocolMaxMsgSize Maximum cap on the size of a protocol message
const ProtocolMaxMsgSize = 10 * 1024 * 1024
type errCode int
const (
// ErrMsgTooLarge is returned if msg if too large
ErrMsgTooLarge = iota
// ErrDecode is returned if decode failed
ErrDecode
// ErrInvalidMsgCode is returned if msg code is invalid
ErrInvalidMsgCode
// ErrProtocolVersionMismatch is returned if protocol version is not matched when handshaking
ErrProtocolVersionMismatch
// ErrNetworkIDMismatch is returned if networkid is not matched when handshaking
ErrNetworkIDMismatch
// ErrGenesisBlockMismatch is returned if genesis block is different from remote signer
ErrGenesisBlockMismatch
// ErrNoStatusMsg is returned if failed when reading status msg
ErrNoStatusMsg
// ErrExtraStatusMsg is returned if failed when extracting status msg
ErrExtraStatusMsg
// ErrSuspendedPeer is returned if remote signer is dead
ErrSuspendedPeer
)
func (e errCode) String() string {
return errorToString[int(e)]
}
// XXX change once legacy code is out
var errorToString = map[int]string{
ErrMsgTooLarge: "Message too long",
ErrDecode: "Invalid message",
ErrInvalidMsgCode: "Invalid message code",
ErrProtocolVersionMismatch: "Protocol version mismatch",
ErrNetworkIDMismatch: "NetworkId mismatch",
ErrGenesisBlockMismatch: "Genesis block mismatch",
ErrNoStatusMsg: "No status message",
ErrExtraStatusMsg: "Extra status message",
ErrSuspendedPeer: "Suspended peer",
}
// SignerStatusData represents signer status when handshaking
type SignerStatusData struct {
ProtocolVersion uint32
Mac string
Sig []byte
}
func errResp(code errCode, format string, v ...interface{}) error {
return fmt.Errorf("%v - %v", code, fmt.Sprintf(format, v...))
}
// IsSyncMsg checks if msg is a sync msg
func IsSyncMsg(msg p2p.Msg) bool {
return msg.Code < PbftMsgOutset
}
// IsDporMsg checks if msg is a dpor related msg
func IsDporMsg(msg p2p.Msg) bool {
return msg.Code >= PbftMsgOutset
}
// RecoverBlockFromMsg recovers a block from a p2p msg
func RecoverBlockFromMsg(msg p2p.Msg, p interface{}) (*types.Block, error) {
// recover the block
var block *types.Block
if err := msg.Decode(&block); err != nil {
return nil, errResp(ErrDecode, "%v: %v", msg, err)
}
block.ReceivedAt = msg.ReceivedAt
block.ReceivedFrom = p
return block, VerifyBlockFields(block)
}
// RecoverHeaderFromMsg recovers a header from a p2p msg
func RecoverHeaderFromMsg(msg p2p.Msg, p interface{}) (*types.Header, error) {
// retrieve the header
var header *types.Header
if err := msg.Decode(&header); err != nil {
return nil, errResp(ErrDecode, "msg %v: %v", msg, err)
}
return header, VerifyHeaderFields(header)
}
var (
errNilHeader = errors.New("the header is nil")
errNilDpor = errors.New("the Dpor field in header is nil")
errNilNumber = errors.New("the Number field in header is nil")
errNilTime = errors.New("the Time field in header is nil")
errNilExtra = errors.New("the Extra field in header is nil")
)
// VerifyHeaderFields verifies that all fields in the header do exist.
// if the function returns nil, then nil-pointer panic will not occur.
func VerifyHeaderFields(header *types.Header) error {
if header.Number == nil {
return errNilNumber
}
if header.Time == nil {
return errNilTime
}
if header.Extra == nil {
return errNilExtra
}
if header.Dpor.Sigs == nil || header.Dpor.Proposers == nil {
return errNilDpor
}
return nil
}
// VerifyBlockFields verifies that all fields in the block do exist.
// if the function returns nil, then nil-pointer panic will not occur.
func VerifyBlockFields(block *types.Block) error {
if block.Header() == nil {
return errNilHeader
}
err := VerifyHeaderFields(block.Header())
return err
}