func (m *Mediator) OnCaughtUp(id string, s Status) {
	logger.Info("[%s] caught up to %s:%s", m.loggingId, id, s)
	m.selfChan <- onCaughtUpEvent{id, s}
}
Called in the ChainSyncer's worker goroutine in the future.
package consensus
import (
	"flag"
	"fmt"
	"math"
	"sort"
	"strings"
	"thunder2/blockchain"
	"thunder2/network"
	"thunder2/utils"
	"time"
	"github.com/petar/GoLLRB/llrb"
	"github.com/pkg/errors"
)
var delayOfMakingFirstProposal = 1000
type MediatorConfig struct {
	LoggingId        string
	K                uint32  
	BlockChain       blockchain.BlockChain
	Role             RoleAssigner
	Verifier         blockchain.Verifier
	DataUnmarshaller blockchain.DataUnmarshaller
	Reconfigurer     Reconfigurer
	EpochManager     EpochManager
	Selector         func() int
	Timer            Timer
}
type Mediator struct {
	StartStopWaiter
	loggingId string
	k         uint32
	host      *network.Host
	role      RoleAssigner
	syncer              *ChainSyncer
	chain               blockchain.BlockChain
	selfChan            chan interface{}
	messageChan         chan *network.Message
	blockChan           chan blockchain.BlockAndEvent
	blockChainEventChan <-chan interface{}
	verifier     blockchain.Verifier
	node         *Node
	unmarshaller blockchain.DataUnmarshaller
	reconfigurer Reconfigurer
	epochManager                   EpochManager
	connections                    map[string]network.ConnectionHandle
	handshakeStates                map[network.ConnectionHandle]handshakeState
	reconciliationWithAllBeginTime time.Time
	syncedIds                map[string]bool
	unnotarizedProposals     map[blockchain.BlockSn]blockchain.Proposal
	reconfFinalizedByBlockSn blockchain.BlockSn
	recentProposals *llrb.LLRB
	lastBroadcastedProposal blockchain.BlockSn
	eventChansMutex utils.CheckedLock
	eventChans      []chan interface{}
}
type EpochManager interface {
	GetEpoch() blockchain.Epoch
	UpdateByClockMsgNota(cn blockchain.ClockMsgNota) error
	UpdateByNotarization(nota blockchain.Notarization) error
	GetClockMsgNota(epoch blockchain.Epoch) blockchain.ClockMsgNota
	GetNotarization(epoch blockchain.Epoch) blockchain.Notarization
}
type FreshestNotarizedChainExtendedEvent struct {
	Sn blockchain.BlockSn
}
type FinalizedChainExtendedEvent struct {
	Sn blockchain.BlockSn
}
type Reconfigurer interface {
	UpdateVerifier(bc blockchain.BlockChain, verifier blockchain.Verifier) error
	UpdateRoleAssigner(bc blockchain.BlockChain, role RoleAssigner) error
	UpdateHost(bc blockchain.BlockChain, host *network.Host) error
	UpdateEpochManager(bc blockchain.BlockChain, em EpochManager) error
}
type Type uint8
const (
	TypeSentChallengeResponse           = Type(0x81)
	TypeRequestStatus                   = Type(0x82)
	TypeRespondStatus                   = Type(0x83)
	TypeRequestNotarizedBlock           = Type(0x84)
	TypeRespondNotarizedBlock           = Type(0x85)
	TypeRespondNotarizedBlockNotExisted = Type(0x86)
	TypeRequestProposal                 = Type(0x87)
	TypeRespondProposal                 = Type(0x88)
	TypeRespondProposalNotExisted       = Type(0x89)
	TypeRequestUnnotarizedProposals     = Type(0x8a)
	TypeRespondUnnotarizedProposals     = Type(0x8b)
	TypeRequestEpoch                    = Type(0x8c)
	TypeRespondEpochByClockMsgNota      = Type(0x8d)
	TypeRespondEpochByNotarization      = Type(0x8e)
	TypeRespondEpochNotExisted          = Type(0x8f)
	TypeRespondEpochInvalid             = Type(0x90)
)
type Status struct {
	FncBlockSn blockchain.BlockSn
	Epoch      blockchain.Epoch
	ReconfFinalizedByBlockSn blockchain.BlockSn
}
type DebugState struct {
	Identity             string
	Status               Status
	SyncerState          SyncerDebugState
	SyncedIds            []string
	ConnectedIds         []string
	ProposalInfo         string
	IsMakingBlock        bool
	LastBroadcastedBlock blockchain.BlockSn
}
type handshakeState int
const (
	hsWaitChallengeResponse = handshakeState(1)
	hsSentChallengeResponse = handshakeState(2)
	hsDone                  = handshakeState(3)
)
type broadcastEvent struct {
	msg blockchain.Message
}
type replyEvent struct {
	source *network.Message
	msg    blockchain.Message
}
type catchUpStatusEvent struct {
	source *network.Message
	sn     blockchain.BlockSn
}
type startCreatingBlocksEvent struct {
}
type reconciliationWithAllEvent struct {
}
type requestEpochProofEvent struct {
	id    string
	epoch blockchain.Epoch
}
type requestDataEvent struct {
	typ uint8
	id  string
	sn  blockchain.BlockSn
}
type onCaughtUpEvent struct {
	id string
	s  Status
}
func init() {
	if flag.Lookup("test.v") != nil {
		delayOfMakingFirstProposal = 50
	}
}
func IsSyncMessage(v uint8) bool {
	return v&0x80 > 0
}
func (typ Type) String() string {
	switch typ {
	case TypeSentChallengeResponse:
		return "TypeSentChallengeResponse"
	case TypeRequestStatus:
		return "TypeRequestStatus"
	case TypeRespondStatus:
		return "TypeRespondStatus"
	case TypeRequestNotarizedBlock:
		return "TypeRequestNotarizedBlock"
	case TypeRespondNotarizedBlock:
		return "TypeRespondNotarizedBlock"
	case TypeRespondNotarizedBlockNotExisted:
		return "TypeRespondNotarizedBlockNotExisted"
	case TypeRequestProposal:
		return "TypeRequestProposal"
	case TypeRespondProposal:
		return "TypeRespondProposal"
	case TypeRespondProposalNotExisted:
		return "TypeRespondProposalNotExisted"
	case TypeRequestUnnotarizedProposals:
		return "TypeRequestUnnotarizedProposals"
	case TypeRespondUnnotarizedProposals:
		return "TypeRespondUnnotarizedProposals"
	case TypeRequestEpoch:
		return "TypeRequestEpoch"
	case TypeRespondEpochByClockMsgNota:
		return "TypeRespondEpochByClockMsgNota"
	case TypeRespondEpochByNotarization:
		return "TypeRespondEpochByNotarization"
	case TypeRespondEpochNotExisted:
		return "TypeRespondEpochNotExisted"
	case TypeRespondEpochInvalid:
		return "TypeRespondEpochInvalid"
	default:
		return "unknown"
	}
}
func hsStateToString(s handshakeState) string {
	switch s {
	case hsWaitChallengeResponse:
		return "hsWaitChallengeResponse"
	case hsSentChallengeResponse:
		return "hsSentChallengeResponse"
	case hsDone:
		return "hsDone"
	default:
		return "unknown"
	}
}
func NewMediator(cfg MediatorConfig) *Mediator {
	if len(cfg.LoggingId) == 0 || cfg.K == 0 || cfg.BlockChain == nil ||
		cfg.Role == nil || cfg.Verifier == nil || cfg.DataUnmarshaller == nil ||
		cfg.Reconfigurer == nil || cfg.Selector == nil || cfg.Timer == nil {
		logger.Error("NewMediator: must fill all fields in MediatorConfig")
		return nil
	}
	nr := network.RoleSpoke
	epoch := cfg.EpochManager.GetEpoch()
	if cfg.Role.IsProposer("", epoch) ||
		cfg.Role.IsBootnode("") {
		nr = network.RoleHub
	}
	ch := make(chan *network.Message, 1024)
	h := network.NewHost(cfg.LoggingId, nr, cfg.Selector, ch)
	m := Mediator{
		loggingId:            cfg.LoggingId,
		k:                    cfg.K,
		host:                 h,
		role:                 cfg.Role,
		chain:                cfg.BlockChain,
		messageChan:          ch,
		verifier:             cfg.Verifier,
		unmarshaller:         cfg.DataUnmarshaller,
		reconfigurer:         cfg.Reconfigurer,
		epochManager:         cfg.EpochManager,
		connections:          make(map[string]network.ConnectionHandle),
		handshakeStates:      make(map[network.ConnectionHandle]handshakeState),
		syncedIds:            make(map[string]bool),
		unnotarizedProposals: make(map[blockchain.BlockSn]blockchain.Proposal),
		recentProposals:      llrb.New(),
	}
	n := NewNode(NodeConfig{
		LoggingId:  cfg.LoggingId,
		K:          cfg.K,
		Chain:      cfg.BlockChain,
		NodeClient: &m,
		Role:       cfg.Role,
		Verifier:   cfg.Verifier,
		Epoch:      cfg.EpochManager.GetEpoch(),
		Timer:      cfg.Timer,
	})
	m.node = &n
	m.reset()
	return &m
}
func (m *Mediator) Broadcast(msg blockchain.Message) {
	logger.Debug("[%s] Broadcast %s", m.loggingId, msg.GetDebugString())
	m.selfChan <- broadcastEvent{msg}
}
func (m *Mediator) Reply(source *network.Message, msg blockchain.Message) {
	logger.Debug("[%s] Reply %s %s",
		m.loggingId, msg.GetDebugString(), source.GetSourceDebugInfo())
	m.selfChan <- replyEvent{source, msg}
}
func (m *Mediator) CatchUp(source *network.Message, sn blockchain.BlockSn) {
	m.selfChan <- catchUpStatusEvent{source, sn}
}
func (m *Mediator) UpdateEpoch(cNota blockchain.ClockMsgNota) {
	m.selfChan <- cNota
}
func (m *Mediator) RequestEpochProof(id string, epoch blockchain.Epoch) {
	logger.Debug("[%s] send request for the proof of epoch=%d to id=%s", m.loggingId, epoch, id)
	m.selfChan <- requestEpochProofEvent{id, epoch}
}
func (m *Mediator) RequestNotarizedBlock(id string, sn blockchain.BlockSn) {
	logger.Debug("[%s] send request for notarized block %s to id=%s", m.loggingId, sn, id)
	m.selfChan <- requestDataEvent{uint8(TypeRequestNotarizedBlock), id, sn}
}
func (m *Mediator) RequestProposal(id string, sn blockchain.BlockSn) {
	logger.Debug("[%s] send request for proposal %s to id=%s", m.loggingId, sn, id)
	m.selfChan <- requestDataEvent{uint8(TypeRequestProposal), id, sn}
}