func GetErrorChannel() chan NodeError {
	mu.RLock()
	defer mu.RUnlock()
	if reporter != nil {
		return reporter.channelError
	}
	return nil
}
GetErrorChannel returns a channel for node errors.
package events
import (
	"errors"
	"fmt"
	"runtime/debug"
	"sync"
	"go.uber.org/zap/zapcore"
	"github.com/spacemeshos/go-spacemesh/common/types"
	"github.com/spacemeshos/go-spacemesh/log"
	"github.com/spacemeshos/go-spacemesh/timesync"
)
var reporter *EventReporter
var mu sync.RWMutex
func EventHook() func(entry zapcore.Entry) error {
	return func(entry zapcore.Entry) error {
		if entry.Level >= zapcore.ErrorLevel {
			ReportError(NodeError{
				Msg:   entry.Message,
				Trace: string(debug.Stack()),
				Level: entry.Level,
			})
		}
		return nil
	}
}
func ReportNewTx(tx *types.Transaction) {
	Publish(NewTx{
		ID:          tx.ID().String(),
		Origin:      tx.Origin().String(),
		Destination: tx.Recipient.String(),
		Amount:      tx.Amount,
		Fee:         tx.Fee,
	})
	ReportTxWithValidity(tx, true)
}
func ReportTxWithValidity(tx *types.Transaction, valid bool) {
	mu.RLock()
	defer mu.RUnlock()
	txWithValidity := TransactionWithValidity{
		Transaction: tx,
		Valid:       valid,
	}
	if reporter != nil {
		if reporter.blocking {
			reporter.channelTransaction <- txWithValidity
			log.Debug("reported tx on channelTransaction: %v", txWithValidity)
		} else {
			select {
			case reporter.channelTransaction <- txWithValidity:
				log.Debug("reported tx on channelTransaction: %v", txWithValidity)
			default:
				log.Debug("not reporting tx as no one is listening: %v", txWithValidity)
			}
		}
	}
}
func ReportValidTx(tx *types.Transaction, valid bool) {
	Publish(ValidTx{ID: tx.ID().String(), Valid: valid})
}
func ReportNewActivation(activation *types.ActivationTx) {
	mu.RLock()
	defer mu.RUnlock()
	Publish(NewAtx{
		ID:      activation.ShortString(),
		EpochID: uint32(activation.PubLayerID.GetEpoch()),
	})
	if reporter != nil {
		innerBytes, err := activation.InnerBytes()
		if err != nil {
			log.Error("error attempting to report activation: unable to encode activation")
			return
		}
		if reporter.blocking {
			reporter.channelActivation <- activation
			log.With().Debug("reported activation", activation.Fields(len(innerBytes))...)
		} else {
			select {
			case reporter.channelActivation <- activation:
				log.With().Debug("reported activation", activation.Fields(len(innerBytes))...)
			default:
				log.With().Debug("not reporting activation as no one is listening", activation.Fields(len(innerBytes))...)
			}
		}
	}
}
func ReportRewardReceived(r Reward) {
	mu.RLock()
	defer mu.RUnlock()
	Publish(RewardReceived{
		Coinbase:  r.Coinbase.String(),
		Amount:    r.Total,
		SmesherID: r.Smesher.ToBytes(),
	})
	if reporter != nil {
		if reporter.blocking {
			reporter.channelReward <- r
			log.Debug("reported reward: %v", r)
		} else {
			select {
			case reporter.channelReward <- r:
				log.Debug("reported reward: %v", r)
			default:
				log.Debug("not reporting reward as no one is listening: %v", r)
			}
		}
	}
}
func ReportNewBlock(blk *types.Block) {
	Publish(NewBlock{
		ID:    blk.ID().String(),
		Atx:   blk.ATXID.ShortString(),
		Layer: blk.LayerIndex.Uint32(),
	})
}
func ReportValidBlock(blockID types.BlockID, valid bool) {
	Publish(ValidBlock{
		ID:    blockID.String(),
		Valid: valid,
	})
}
func ReportAtxCreated(created bool, epoch uint32, id string) {
	Publish(AtxCreated{Created: created, Epoch: epoch, ID: id})
}
func ReportValidActivation(activation *types.ActivationTx, valid bool) {
	Publish(ValidAtx{ID: activation.ShortString(), Valid: valid})
}
func ReportDoneCreatingBlock(eligible bool, layer uint32, error string) {
	Publish(DoneCreatingBlock{
		Eligible: eligible,
		Layer:    layer,
		Error:    error,
	})
}
func ReportCalculatedTortoiseBeacon(epoch types.EpochID, beacon string) {
	Publish(TortoiseBeaconCalculated{
		Epoch:  epoch,
		Beacon: beacon,
	})
}
func ReportLayerUpdate(layer LayerUpdate) {
	mu.RLock()
	defer mu.RUnlock()
	if reporter != nil {
		if reporter.blocking {
			reporter.channelLayer <- layer
			log.With().Debug("reported new or updated layer", layer)
		} else {
			select {
			case reporter.channelLayer <- layer:
				log.With().Debug("reported new or updated layer", layer)
			default:
				log.With().Debug("not reporting new or updated layer as no one is listening", layer)
			}
		}
	}
}
func ReportError(err NodeError) {
	mu.RLock()
	defer mu.RUnlock()
	if reporter != nil {
		if reporter.blocking {
			reporter.channelError <- err
			log.Debug("reported error: %v", err)
		} else {
			select {
			case reporter.channelError <- err:
				log.Debug("reported error: %v", err)
			default:
				log.Debug("not reporting error as buffer is full: %v", err)
			}
		}
	}
}
func ReportNodeStatusUpdate() {
	mu.RLock()
	defer mu.RUnlock()
	if reporter != nil {
		if reporter.blocking {
			reporter.channelStatus <- struct{}{}
			log.Debug("reported status update")
		} else {
			select {
			case reporter.channelStatus <- struct{}{}:
				log.Debug("reported status update")
			default:
				log.Debug("not reporting status update as no one is listening")
			}
		}
	}
}
func ReportReceipt(r TxReceipt) {
	mu.RLock()
	defer mu.RUnlock()
	if reporter != nil {
		if reporter.blocking {
			reporter.channelReceipt <- r
			log.Debug("reported receipt: %v", r)
		} else {
			select {
			case reporter.channelReceipt <- r:
				log.Debug("reported receipt: %v", r)
			default:
				log.Debug("not reporting receipt as no one is listening: %v", r)
			}
		}
	}
}
func ReportAccountUpdate(a types.Address) {
	mu.RLock()
	defer mu.RUnlock()
	if reporter != nil {
		if reporter.blocking {
			reporter.channelAccount <- a
			log.With().Debug("reported account update", a)
		} else {
			select {
			case reporter.channelAccount <- a:
				log.With().Debug("reported account update", a)
			default:
				log.With().Debug("not reporting account update as no one is listening", a)
			}
		}
	}
}
func GetNewTxChannel() chan TransactionWithValidity {
	mu.RLock()
	defer mu.RUnlock()
	if reporter != nil {
		return reporter.channelTransaction
	}
	return nil
}
func GetActivationsChannel() chan *types.ActivationTx {
	mu.RLock()
	defer mu.RUnlock()
	if reporter != nil {
		return reporter.channelActivation
	}
	return nil
}
func GetLayerChannel() chan LayerUpdate {
	mu.RLock()
	defer mu.RUnlock()
	if reporter != nil {
		return reporter.channelLayer
	}
	return nil
}