func (wal *baseWAL) WriteSync(msg WALMessage) error {
	if wal == nil {
		return nil
	}
	if err := wal.Write(msg); err != nil {
		return err
	}
	if err := wal.FlushAndSync(); err != nil {
		wal.Logger.Error("WriteSync failed to flush consensus wal. WARNING: may result in creating alternative proposals / votes for the current height iff the node restarted",
			"err", err)
		return err
	}
	return nil
}
WriteSync is called when we receive a msg from ourselves
so that we write to disk before sending signed messages.
NOTE: calls fsync()
package consensus
import (
	"encoding/binary"
	"fmt"
	"hash/crc32"
	"io"
	"path/filepath"
	"time"
	"github.com/pkg/errors"
	amino "github.com/tendermint/go-amino"
	auto "github.com/tendermint/tendermint/libs/autofile"
	cmn "github.com/tendermint/tendermint/libs/common"
	"github.com/tendermint/tendermint/libs/log"
	"github.com/tendermint/tendermint/types"
	tmtime "github.com/tendermint/tendermint/types/time"
)
const (
	maxMsgSizeBytes = maxMsgSize + 24
	walDefaultFlushInterval = 2 * time.Second
)
type TimedWALMessage struct {
	Time time.Time  `json:"time"`
	Msg  WALMessage `json:"msg"`
}
type EndHeightMessage struct {
	Height int64 `json:"height"`
}
type WALMessage interface{}
func RegisterWALMessages(cdc *amino.Codec) {
	cdc.RegisterInterface((*WALMessage)(nil), nil)
	cdc.RegisterConcrete(types.EventDataRoundState{}, "tendermint/wal/EventDataRoundState", nil)
	cdc.RegisterConcrete(msgInfo{}, "tendermint/wal/MsgInfo", nil)
	cdc.RegisterConcrete(timeoutInfo{}, "tendermint/wal/TimeoutInfo", nil)
	cdc.RegisterConcrete(EndHeightMessage{}, "tendermint/wal/EndHeightMessage", nil)
}
type WAL interface {
	Write(WALMessage) error
	WriteSync(WALMessage) error
	FlushAndSync() error
	SearchForEndHeight(height int64, options *WALSearchOptions) (rd io.ReadCloser, found bool, err error)
	Start() error
	Stop() error
	Wait()
}
type baseWAL struct {
	cmn.BaseService
	group *auto.Group
	enc *WALEncoder
	flushTicker   *time.Ticker
	flushInterval time.Duration
}
var _ WAL = &baseWAL{}
func NewWAL(walFile string, groupOptions ...func(*auto.Group)) (*baseWAL, error) {
	err := cmn.EnsureDir(filepath.Dir(walFile), 0700)
	if err != nil {
		return nil, errors.Wrap(err, "failed to ensure WAL directory is in place")
	}
	group, err := auto.OpenGroup(walFile, groupOptions...)
	if err != nil {
		return nil, err
	}
	wal := &baseWAL{
		group:         group,
		enc:           NewWALEncoder(group),
		flushInterval: walDefaultFlushInterval,
	}
	wal.BaseService = *cmn.NewBaseService(nil, "baseWAL", wal)
	return wal, nil
}
func (wal *baseWAL) SetFlushInterval(i time.Duration) {
	wal.flushInterval = i
}
func (wal *baseWAL) Group() *auto.Group {
	return wal.group
}
func (wal *baseWAL) SetLogger(l log.Logger) {
	wal.BaseService.Logger = l
	wal.group.SetLogger(l)
}
func (wal *baseWAL) OnStart() error {
	size, err := wal.group.Head.Size()
	if err != nil {
		return err
	} else if size == 0 {
		wal.WriteSync(EndHeightMessage{0})
	}
	err = wal.group.Start()
	if err != nil {
		return err
	}
	wal.flushTicker = time.NewTicker(wal.flushInterval)
	go wal.processFlushTicks()
	return nil
}
func (wal *baseWAL) processFlushTicks() {
	for {
		select {
		case <-wal.flushTicker.C:
			if err := wal.FlushAndSync(); err != nil {
				wal.Logger.Error("Periodic WAL flush failed", "err", err)
			}
		case <-wal.Quit():
			return
		}
	}
}
func (wal *baseWAL) FlushAndSync() error {
	return wal.group.FlushAndSync()
}
func (wal *baseWAL) OnStop() {
	wal.flushTicker.Stop()
	wal.FlushAndSync()
	wal.group.Stop()
	wal.group.Close()
}
func (wal *baseWAL) Wait() {
	wal.group.Wait()
}
func (wal *baseWAL) Write(msg WALMessage) error {
	if wal == nil {
		return nil
	}
	if err := wal.enc.Encode(&TimedWALMessage{tmtime.Now(), msg}); err != nil {
		wal.Logger.Error("Error writing msg to consensus wal. WARNING: recover may not be possible for the current height",
			"err", err, "msg", msg)
		return err
	}
	return nil
}