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  }