func (sm *StateMachine) applyEvent(stateEvent *state.Event) *ActionList {
	assertInitialized := func() {
		assertEqualf(sm.state, smInitialized, "cannot apply events to an uninitialized state machine")
	}
	actions := &ActionList{}
	switch event := stateEvent.Type.(type) {
	case *state.Event_Initialize:
		sm.initialize(event.Initialize)
		return &ActionList{}
	case *state.Event_LoadPersistedEntry:
		sm.applyPersisted(event.LoadPersistedEntry.Index, event.LoadPersistedEntry.Entry)
		return &ActionList{}
	case *state.Event_CompleteInitialization:
		return sm.completeInitialization()
	case *state.Event_TickElapsed:
		assertInitialized()
		actions.concat(sm.clientHashDisseminator.tick())
		actions.concat(sm.epochTracker.tick())
	case *state.Event_Step:
		assertInitialized()
		actions.concat(sm.step(
			nodeID(event.Step.Source),
			event.Step.Msg,
		))
	case *state.Event_HashResult:
		assertInitialized()
		actions.concat(sm.processHashResult(event.HashResult))
	case *state.Event_CheckpointResult:
		assertInitialized()
		actions.concat(sm.processCheckpointResult(event.CheckpointResult))
	case *state.Event_RequestPersisted:
		assertInitialized()
		actions.concat(sm.clientHashDisseminator.applyNewRequest(
			event.RequestPersisted.RequestAck,
		))
	case *state.Event_StateTransferFailed:
		sm.Logger.Log(logging.LevelDebug, "state transfer failed", "seq_no", event.StateTransferFailed.SeqNo)
		panic("XXX handle state transfer failure")
	case *state.Event_StateTransferComplete:
		assertEqualf(sm.commitState.transferring, true, "state transfer event received but the state machine did not request transfer")
		sm.Logger.Log(logging.LevelDebug, "state transfer completed", "seq_no", event.StateTransferComplete.SeqNo)
		actions.concat(sm.persisted.addCEntry(&msgs.CEntry{
			SeqNo:           event.StateTransferComplete.SeqNo,
			CheckpointValue: event.StateTransferComplete.CheckpointValue,
			NetworkState:    event.StateTransferComplete.NetworkState,
		}))
		actions.concat(sm.reinitialize())
	case *state.Event_ActionsReceived:
		return &ActionList{}
	default:
		panic(fmt.Sprintf("unknown state event type: %T", stateEvent.Type))
	}
	if sm.checkpointTracker.state == cpsGarbageCollectable {
		newLow := sm.checkpointTracker.garbageCollect()
		sm.Logger.Log(logging.LevelDebug, "garbage collecting through", "seq_no", newLow)
		sm.persisted.truncate(newLow)
		if newLow > uint64(sm.checkpointTracker.networkConfig.CheckpointInterval) {
			sm.batchTracker.truncate(newLow - uint64(sm.checkpointTracker.networkConfig.CheckpointInterval))
		}
		actions.concat(sm.epochTracker.moveLowWatermark(newLow))
	}
	for {
		actions.concat(sm.commitState.drain())
		loopActions := sm.epochTracker.advanceState()
		if loopActions.isEmpty() {
			break
		}
		actions.concat(loopActions)
	}
	return actions
}
Applies an external event, such as a message, a tick, or a result of an action, to the state machine.
package legacy_statemachine
import (
	"fmt"
	"github.com/hyperledger-labs/mirbft/pkg/logger"
	"github.com/pkg/errors"
	"github.com/hyperledger-labs/mirbft/pkg/pb/msgs"
	"github.com/hyperledger-labs/mirbft/pkg/pb/state"
	"github.com/hyperledger-labs/mirbft/pkg/status"
)
type bucketID uint64
type nodeID uint64
type stateMachineState int
func assertFailed(failure, format string, args ...interface{}) {
	panic(
		fmt.Sprintf(
			fmt.Sprintf("assertion failed, code bug? -- %s -- %s", failure, format),
			args...,
		),
	)
}
func assertTrue(value bool, text string) {
	assertTruef(value, text)
}
func assertTruef(value bool, format string, args ...interface{}) {
	if !value {
		assertFailed("expected false to be true", format, args...)
	}
}
func assertEqual(lhs, rhs interface{}, text string) {
	assertEqualf(lhs, rhs, text)
}
func assertEqualf(lhs, rhs interface{}, format string, args ...interface{}) {
	if lhs != rhs {
		assertFailed(fmt.Sprintf("expected %v == %v", lhs, rhs), format, args...)
	}
}
func assertNotEqual(lhs, rhs interface{}, text string) {
	assertNotEqualf(lhs, rhs, text)
}
func assertNotEqualf(lhs, rhs interface{}, format string, args ...interface{}) {
	if lhs == rhs {
		assertFailed(fmt.Sprintf("expected %v != %v", lhs, rhs), format, args...)
	}
}
func assertGreaterThanOrEqual(lhs, rhs uint64, text string) {
	assertGreaterThanOrEqualf(lhs, rhs, text)
}
func assertGreaterThanOrEqualf(lhs, rhs uint64, format string, args ...interface{}) {
	if lhs < rhs {
		assertFailed(fmt.Sprintf("expected %v >= %v", lhs, rhs), format, args...)
	}
}
func assertGreaterThan(lhs, rhs uint64, text string) {
	assertGreaterThanf(lhs, rhs, text)
}
func assertGreaterThanf(lhs, rhs uint64, format string, args ...interface{}) {
	if lhs <= rhs {
		assertFailed(fmt.Sprintf("expected %v > %v", lhs, rhs), format, args...)
	}
}
const (
	smUninitialized stateMachineState = iota
	smLoadingPersisted
	smInitialized
)
type StateMachine struct {
	Logger logging.Logger
	state stateMachineState
	myConfig               *state.EventInitialParameters
	commitState            *commitState
	clientTracker          *clientTracker
	clientHashDisseminator *clientHashDisseminator
	nodeBuffers       *nodeBuffers
	batchTracker      *batchTracker
	checkpointTracker *checkpointTracker
	epochTracker      *epochTracker
	persisted         *persisted
}
func (sm *StateMachine) initialize(parameters *state.EventInitialParameters) {
	assertEqualf(sm.state, smUninitialized, "state machine has already been initialized")
	sm.myConfig = parameters
	sm.state = smLoadingPersisted
	sm.persisted = newPersisted(sm.Logger)
	dummyInitialState := &msgs.NetworkState{
		Config: &msgs.NetworkState_Config{
			Nodes:              []uint64{sm.myConfig.Id},
			MaxEpochLength:     1,
			CheckpointInterval: 1,
			NumberOfBuckets:    1,
		},
	}
	sm.nodeBuffers = newNodeBuffers(sm.myConfig, sm.Logger)
	sm.checkpointTracker = newCheckpointTracker(0, dummyInitialState, sm.persisted, sm.nodeBuffers, sm.myConfig, sm.Logger)
	sm.clientTracker = newClientTracker(sm.myConfig, sm.Logger)
	sm.commitState = newCommitState(sm.persisted, sm.Logger)
	sm.clientHashDisseminator = newClientHashDisseminator(sm.nodeBuffers, sm.myConfig, sm.Logger, sm.clientTracker)
	sm.batchTracker = newBatchTracker(sm.persisted)
	sm.epochTracker = newEpochTracker(
		sm.persisted,
		sm.nodeBuffers,
		sm.commitState,
		dummyInitialState.Config,
		sm.Logger,
		sm.myConfig,
		sm.batchTracker,
		sm.clientTracker,
		sm.clientHashDisseminator,
	)
}
func (sm *StateMachine) applyPersisted(index uint64, data *msgs.Persistent) {
	assertEqualf(sm.state, smLoadingPersisted, "state machine has already finished loading persisted data")
	sm.persisted.appendInitialLoad(index, data)
}
func (sm *StateMachine) completeInitialization() *ActionList {
	assertEqualf(sm.state, smLoadingPersisted, "state machine has already finished loading persisted data")
	sm.state = smInitialized
	return sm.reinitialize()
}
func (sm *StateMachine) ApplyEvent(stateEvent *state.Event) *ActionList {
	return sm.applyEvent(stateEvent)
}