github.com/aergoio/aergo@v1.3.1/consensus/raftCommon.go (about) 1 package consensus 2 3 import ( 4 "bytes" 5 "context" 6 "crypto/sha1" 7 "encoding/binary" 8 "encoding/gob" 9 "encoding/json" 10 "errors" 11 "fmt" 12 "github.com/aergoio/aergo/internal/enc" 13 "github.com/aergoio/aergo/types" 14 "github.com/aergoio/etcd/raft" 15 "github.com/aergoio/etcd/raft/raftpb" 16 "io" 17 ) 18 19 type EntryType int8 20 21 const ( 22 EntryBlock EntryType = iota 23 EntryEmpty // it is generated when node becomes leader 24 EntryConfChange 25 InvalidMemberID = 0 26 ) 27 28 type ConfChangePropose struct { 29 Ctx context.Context 30 Cc *raftpb.ConfChange 31 32 ReplyC chan *ConfChangeReply 33 } 34 35 type ConfChangeReply struct { 36 Member *Member 37 Err error 38 } 39 40 var ( 41 WalEntryType_name = map[EntryType]string{ 42 0: "EntryBlock", 43 1: "EntryEmpty", 44 2: "EntryConfChange", 45 } 46 47 ErrInvalidMemberID = errors.New("member id of conf change doesn't match") 48 ErrEmptySnapData = errors.New("failed to decode snapshot data. encoded data is empty") 49 ErrInvalidMemberAttr = errors.New("invalid member attribute") 50 ErrorMembershipChangeSkip = errors.New("node is not raft leader, so skip membership change request") 51 ) 52 53 type WalEntry struct { 54 Type EntryType 55 Term uint64 56 Index uint64 57 Data []byte // hash is set if Type is EntryBlock 58 } 59 60 func (we *WalEntry) ToBytes() ([]byte, error) { 61 var val bytes.Buffer 62 encoder := gob.NewEncoder(&val) 63 if err := encoder.Encode(we); err != nil { 64 panic("raft entry to bytes error") 65 return nil, err 66 } 67 68 return val.Bytes(), nil 69 } 70 71 func (we *WalEntry) ToString() string { 72 if we == nil { 73 return "wal entry is nil" 74 } 75 return fmt.Sprintf("wal entry[type:%s, index:%d, term:%d", WalEntryType_name[we.Type], we.Index, we.Term) 76 } 77 78 type RaftIdentity struct { 79 ClusterID uint64 80 ID uint64 81 Name string 82 PeerID string // base58 encoded format 83 } 84 85 func (rid *RaftIdentity) ToString() string { 86 if rid == nil { 87 return "raft identity is nil" 88 } 89 return fmt.Sprintf("raft identity[name:%s, nodeid:%x, peerid:%s]", rid.Name, rid.ID, rid.PeerID) 90 } 91 92 type ChainWAL interface { 93 ChainDB 94 95 ClearWAL() 96 ResetWAL(hardStateInfo *types.HardStateInfo) error 97 WriteRaftEntry([]*WalEntry, []*types.Block, []*raftpb.ConfChange) error 98 GetRaftEntry(idx uint64) (*WalEntry, error) 99 HasWal(identity RaftIdentity) (bool, error) 100 GetRaftEntryOfBlock(hash []byte) (*WalEntry, error) 101 GetRaftEntryLastIdx() (uint64, error) 102 GetRaftEntryIndexOfBlock(hash []byte) (uint64, error) 103 GetHardState() (*raftpb.HardState, error) 104 WriteHardState(hardstate *raftpb.HardState) error 105 WriteSnapshot(snap *raftpb.Snapshot) error 106 GetSnapshot() (*raftpb.Snapshot, error) 107 WriteIdentity(id *RaftIdentity) error 108 GetIdentity() (*RaftIdentity, error) 109 WriteConfChangeProgress(id uint64, progress *types.ConfChangeProgress) error 110 GetConfChangeProgress(id uint64) (*types.ConfChangeProgress, error) 111 } 112 113 type SnapshotData struct { 114 Chain ChainSnapshot `json:"chain"` 115 Members []*Member `json:"members"` 116 RemovedMembers []*Member 117 } 118 119 func NewSnapshotData(members []*Member, rmMembers []*Member, block *types.Block) *SnapshotData { 120 if block == nil { 121 return nil 122 } 123 124 return &SnapshotData{ 125 Chain: *NewChainSnapshot(block), 126 Members: members, 127 RemovedMembers: rmMembers, 128 } 129 } 130 131 func (snapd *SnapshotData) Encode() ([]byte, error) { 132 return json.Marshal(snapd) 133 } 134 135 func (snapd *SnapshotData) Decode(data []byte) error { 136 if len(data) == 0 { 137 return ErrEmptySnapData 138 } 139 return json.Unmarshal(data, snapd) 140 } 141 142 func (snapd *SnapshotData) Equal(t *SnapshotData) bool { 143 if !snapd.Chain.Equal(&t.Chain) { 144 return false 145 } 146 147 if len(t.Members) != len(snapd.Members) { 148 return false 149 } 150 151 for i, m := range snapd.Members { 152 tMbr := t.Members[i] 153 154 if !m.Equal(tMbr) { 155 return false 156 } 157 } 158 159 return true 160 } 161 162 func (snapd *SnapshotData) ToString() string { 163 var buf string 164 165 buf += fmt.Sprintf("chain:%s, ", snapd.Chain.ToString()) 166 167 printMembers := func(mbrs []*Member, name string) { 168 if len(mbrs) > 0 { 169 buf += fmt.Sprintf("%s[", name) 170 171 for i, m := range mbrs { 172 buf += fmt.Sprintf("#%d{%s}", i, m.ToString()) 173 } 174 175 buf += fmt.Sprintf("]") 176 } 177 } 178 179 printMembers(snapd.Members, "members") 180 printMembers(snapd.RemovedMembers, "removed members") 181 182 return buf 183 } 184 185 type ChainSnapshot struct { 186 No types.BlockNo `json:"no"` 187 Hash []byte `json:"hash"` 188 } 189 190 func NewChainSnapshot(block *types.Block) *ChainSnapshot { 191 if block == nil { 192 return nil 193 } 194 195 return &ChainSnapshot{No: block.BlockNo(), Hash: block.BlockHash()} 196 } 197 198 func (csnap *ChainSnapshot) Equal(other *ChainSnapshot) bool { 199 return csnap.No == other.No && bytes.Equal(csnap.Hash, other.Hash) 200 } 201 202 func (csnap *ChainSnapshot) ToString() string { 203 if csnap == nil || csnap.Hash == nil { 204 return "csnap: empty" 205 } 206 return fmt.Sprintf("chainsnap:(no=%d, hash=%s)", csnap.No, enc.ToString(csnap.Hash)) 207 } 208 209 /* 210 func (csnap *ChainSnapshot) Encode() ([]byte, error) { 211 var val bytes.Buffer 212 213 encoder := gob.NewEncoder(&val) 214 if err := encoder.Encode(csnap); err != nil { 215 logger.Fatal().Err(err).Msg("failed to encode chainsnap") 216 return nil, err 217 } 218 219 return val.Bytes(), nil 220 } 221 222 func DecodeChainSnapshot(data []byte) (*ChainSnapshot, error) { 223 var snap ChainSnapshot 224 var b bytes.Buffer 225 b.Write(data) 226 227 if data == nil { 228 return nil, ErrEmptySnapData 229 } 230 231 decoder := gob.NewDecoder(&b) 232 if err := decoder.Decode(&snap); err != nil { 233 logger.Fatal().Err(err).Msg("failed to decode chainsnap") 234 return nil, err 235 } 236 237 return &snap, nil 238 }*/ 239 240 func ConfStateToString(conf *raftpb.ConfState) string { 241 var buf string 242 243 if len(conf.Nodes) > 0 { 244 buf = fmt.Sprintf("node") 245 for _, node := range conf.Nodes { 246 buf = buf + fmt.Sprintf("[%x]", node) 247 } 248 } 249 250 if len(conf.Learners) > 0 { 251 buf = buf + fmt.Sprintf(".learner") 252 for _, learner := range conf.Learners { 253 buf = buf + fmt.Sprintf("[%x]", learner) 254 } 255 } 256 return buf 257 } 258 259 func SnapToString(snap *raftpb.Snapshot, snapd *SnapshotData) string { 260 var buf string 261 buf = buf + fmt.Sprintf("snap=[index:%d term:%d conf:%s]", snap.Metadata.Index, snap.Metadata.Term, ConfStateToString(&snap.Metadata.ConfState)) 262 263 if snapd != nil { 264 buf = buf + fmt.Sprintf(", %s", snapd.ToString()) 265 } 266 267 return buf 268 } 269 270 type Member struct { 271 types.MemberAttr 272 } 273 274 func NewMember(name string, address string, peerID types.PeerID, chainID []byte, when int64) *Member { 275 //check unique 276 m := &Member{MemberAttr: types.MemberAttr{Name: name, Address: address, PeerID: []byte(peerID)}} 277 278 //make ID 279 m.CalculateMemberID(chainID, when) 280 281 return m 282 } 283 284 func (m *Member) Clone() *Member { 285 newM := Member{MemberAttr: types.MemberAttr{ID: m.ID, Name: m.Name, Address: m.Address}} 286 287 copy(newM.PeerID, m.PeerID) 288 289 return &newM 290 } 291 292 func (m *Member) SetAttr(attr *types.MemberAttr) { 293 m.MemberAttr = *attr 294 } 295 296 func (m *Member) SetMemberID(id uint64) { 297 m.ID = id 298 } 299 300 func (m *Member) CalculateMemberID(chainID []byte, curTimestamp int64) { 301 var buf []byte 302 303 buf = append(buf, []byte(m.Name)...) 304 buf = append(buf, []byte(chainID)...) 305 buf = append(buf, []byte(fmt.Sprintf("%d", curTimestamp))...) 306 307 hash := sha1.Sum(buf) 308 m.ID = binary.LittleEndian.Uint64(hash[:8]) 309 } 310 311 func (m *Member) IsValid() bool { 312 if m.ID == InvalidMemberID || len(m.PeerID) == 0 || len(m.Name) == 0 || len(m.Address) == 0 { 313 return false 314 } 315 316 if _, err := types.ParseMultiaddrWithResolve(m.Address); err != nil { 317 logger.Error().Err(err).Msg("parse address of member") 318 return false 319 } 320 321 return true 322 } 323 324 func (m *Member) GetPeerID() types.PeerID { 325 return types.PeerID(m.PeerID) 326 } 327 328 func (m *Member) Equal(other *Member) bool { 329 return m.ID == other.ID && 330 bytes.Equal(m.PeerID, other.PeerID) && 331 m.Name == other.Name && 332 m.Address == other.Address && 333 bytes.Equal([]byte(m.PeerID), []byte(other.PeerID)) 334 } 335 336 func (m *Member) ToString() string { 337 data, err := json.Marshal(&m.MemberAttr) 338 if err != nil { 339 logger.Error().Err(err).Str("name", m.Name).Msg("can't unmarshal member") 340 return "" 341 } 342 return string(data) 343 } 344 345 func (m *Member) HasDuplicatedAttr(x *Member) bool { 346 if m.Name == x.Name || m.ID == x.ID || m.Address == x.Address || bytes.Equal(m.PeerID, x.PeerID) { 347 return true 348 } 349 350 return false 351 } 352 353 // IsCompatible checks if name, url and peerid of this member are the same with other member 354 func (m *Member) IsCompatible(other *Member) bool { 355 return m.Name == other.Name && m.Address == other.Address && bytes.Equal(m.PeerID, other.PeerID) 356 } 357 358 type MembersByName []*Member 359 360 func (mbrs MembersByName) Len() int { 361 return len(mbrs) 362 } 363 func (mbrs MembersByName) Less(i, j int) bool { 364 return mbrs[i].Name < mbrs[j].Name 365 } 366 func (mbrs MembersByName) Swap(i, j int) { 367 mbrs[i], mbrs[j] = mbrs[j], mbrs[i] 368 } 369 370 // DummyRaftAccessor returns error if process request comes, or silently ignore raft message. 371 type DummyRaftAccessor struct { 372 } 373 374 var IllegalArgumentError = errors.New("illegal argument") 375 376 func (DummyRaftAccessor) Process(ctx context.Context, peerID types.PeerID, m raftpb.Message) error { 377 return IllegalArgumentError 378 } 379 380 func (DummyRaftAccessor) IsIDRemoved(peerID types.PeerID) bool { 381 return false 382 } 383 384 func (DummyRaftAccessor) ReportUnreachable(peerID types.PeerID) { 385 } 386 387 func (DummyRaftAccessor) ReportSnapshot(peerID types.PeerID, status raft.SnapshotStatus) { 388 } 389 390 func (DummyRaftAccessor) GetMemberByID(id uint64) *Member { 391 return nil 392 } 393 394 func (DummyRaftAccessor) GetMemberByPeerID(peerID types.PeerID) *Member { 395 return nil 396 } 397 398 func (DummyRaftAccessor) SaveFromRemote(r io.Reader, id uint64, msg raftpb.Message) (int64, error) { 399 return 0, nil 400 }