package types import ( "context" "fmt" "strings" abci "github.com/tendermint/tendermint/abci/types" tmjson "github.com/tendermint/tendermint/libs/json" tmpubsub "github.com/tendermint/tendermint/libs/pubsub" tmquery "github.com/tendermint/tendermint/libs/pubsub/query" ) // Reserved event types (alphabetically sorted). const ( // Block level events for mass consumption by users. // These events are triggered from the state package, // after a block has been committed. // These are also used by the tx indexer for async indexing. // All of this data can be fetched through the rpc. EventNewBlockValue = "NewBlock" EventNewBlockHeaderValue = "NewBlockHeader" EventNewEvidenceValue = "NewEvidence" EventTxValue = "Tx" EventValidatorSetUpdatesValue = "ValidatorSetUpdates" // Internal consensus events. // These are used for testing the consensus state machine. // They can also be used to build real-time consensus visualizers. EventCompleteProposalValue = "CompleteProposal" // The BlockSyncStatus event will be emitted when the node switching // state sync mechanism between the consensus reactor and the blocksync reactor. EventBlockSyncStatusValue = "BlockSyncStatus" EventLockValue = "Lock" EventNewRoundValue = "NewRound" EventNewRoundStepValue = "NewRoundStep" EventPolkaValue = "Polka" EventRelockValue = "Relock" EventStateSyncStatusValue = "StateSyncStatus" EventTimeoutProposeValue = "TimeoutPropose" EventTimeoutWaitValue = "TimeoutWait" EventUnlockValue = "Unlock" EventValidBlockValue = "ValidBlock" EventVoteValue = "Vote" ) // Pre-populated ABCI Tendermint-reserved events var ( EventNewBlock = abci.Event{ Type: strings.Split(EventTypeKey, ".")[0], Attributes: []abci.EventAttribute{ { Key: strings.Split(EventTypeKey, ".")[1], Value: EventNewBlockValue, }, }, } EventNewBlockHeader = abci.Event{ Type: strings.Split(EventTypeKey, ".")[0], Attributes: []abci.EventAttribute{ { Key: strings.Split(EventTypeKey, ".")[1], Value: EventNewBlockHeaderValue, }, }, } EventNewEvidence = abci.Event{ Type: strings.Split(EventTypeKey, ".")[0], Attributes: []abci.EventAttribute{ { Key: strings.Split(EventTypeKey, ".")[1], Value: EventNewEvidenceValue, }, }, } EventTx = abci.Event{ Type: strings.Split(EventTypeKey, ".")[0], Attributes: []abci.EventAttribute{ { Key: strings.Split(EventTypeKey, ".")[1], Value: EventTxValue, }, }, } ) // ENCODING / DECODING // TMEventData implements events.EventData. type TMEventData interface { // empty interface } func init() { tmjson.RegisterType(EventDataNewBlock{}, "tendermint/event/NewBlock") tmjson.RegisterType(EventDataNewBlockHeader{}, "tendermint/event/NewBlockHeader") tmjson.RegisterType(EventDataNewEvidence{}, "tendermint/event/NewEvidence") tmjson.RegisterType(EventDataTx{}, "tendermint/event/Tx") tmjson.RegisterType(EventDataRoundState{}, "tendermint/event/RoundState") tmjson.RegisterType(EventDataNewRound{}, "tendermint/event/NewRound") tmjson.RegisterType(EventDataCompleteProposal{}, "tendermint/event/CompleteProposal") tmjson.RegisterType(EventDataVote{}, "tendermint/event/Vote") tmjson.RegisterType(EventDataValidatorSetUpdates{}, "tendermint/event/ValidatorSetUpdates") tmjson.RegisterType(EventDataString(""), "tendermint/event/ProposalString") tmjson.RegisterType(EventDataBlockSyncStatus{}, "tendermint/event/FastSyncStatus") tmjson.RegisterType(EventDataStateSyncStatus{}, "tendermint/event/StateSyncStatus") } // Most event messages are basic types (a block, a transaction) // but some (an input to a call tx or a receive) are more exotic type EventDataNewBlock struct { Block *Block `json:"block"` BlockID BlockID `json:"block_id"` ResultBeginBlock abci.ResponseBeginBlock `json:"result_begin_block"` ResultEndBlock abci.ResponseEndBlock `json:"result_end_block"` } type EventDataNewBlockHeader struct { Header Header `json:"header"` NumTxs int64 `json:"num_txs"` // Number of txs in a block ResultBeginBlock abci.ResponseBeginBlock `json:"result_begin_block"` ResultEndBlock abci.ResponseEndBlock `json:"result_end_block"` } type EventDataNewEvidence struct { Evidence Evidence `json:"evidence"` Height int64 `json:"height"` } // All txs fire EventDataTx type EventDataTx struct { abci.TxResult } // NOTE: This goes into the replay WAL type EventDataRoundState struct { Height int64 `json:"height"` Round int32 `json:"round"` Step string `json:"step"` } type ValidatorInfo struct { Address Address `json:"address"` Index int32 `json:"index"` } type EventDataNewRound struct { Height int64 `json:"height"` Round int32 `json:"round"` Step string `json:"step"` Proposer ValidatorInfo `json:"proposer"` } type EventDataCompleteProposal struct { Height int64 `json:"height"` Round int32 `json:"round"` Step string `json:"step"` BlockID BlockID `json:"block_id"` } type EventDataVote struct { Vote *Vote } type EventDataString string type EventDataValidatorSetUpdates struct { ValidatorUpdates []*Validator `json:"validator_updates"` } // EventDataBlockSyncStatus shows the fastsync status and the // height when the node state sync mechanism changes. type EventDataBlockSyncStatus struct { Complete bool `json:"complete"` Height int64 `json:"height"` } // EventDataStateSyncStatus shows the statesync status and the // height when the node state sync mechanism changes. type EventDataStateSyncStatus struct { Complete bool `json:"complete"` Height int64 `json:"height"` } // PUBSUB const ( // EventTypeKey is a reserved composite key for event name. EventTypeKey = "tm.event" // TxHashKey is a reserved key, used to specify transaction's hash. // see EventBus#PublishEventTx TxHashKey = "tx.hash" // TxHeightKey is a reserved key, used to specify transaction block's height. // see EventBus#PublishEventTx TxHeightKey = "tx.height" // BlockHeightKey is a reserved key used for indexing BeginBlock and Endblock // events. BlockHeightKey = "block.height" EventTypeBeginBlock = "begin_block" EventTypeEndBlock = "end_block" ) var ( EventQueryCompleteProposal = QueryForEvent(EventCompleteProposalValue) EventQueryLock = QueryForEvent(EventLockValue) EventQueryNewBlock = QueryForEvent(EventNewBlockValue) EventQueryNewBlockHeader = QueryForEvent(EventNewBlockHeaderValue) EventQueryNewEvidence = QueryForEvent(EventNewEvidenceValue) EventQueryNewRound = QueryForEvent(EventNewRoundValue) EventQueryNewRoundStep = QueryForEvent(EventNewRoundStepValue) EventQueryPolka = QueryForEvent(EventPolkaValue) EventQueryRelock = QueryForEvent(EventRelockValue) EventQueryTimeoutPropose = QueryForEvent(EventTimeoutProposeValue) EventQueryTimeoutWait = QueryForEvent(EventTimeoutWaitValue) EventQueryTx = QueryForEvent(EventTxValue) EventQueryUnlock = QueryForEvent(EventUnlockValue) EventQueryValidatorSetUpdates = QueryForEvent(EventValidatorSetUpdatesValue) EventQueryValidBlock = QueryForEvent(EventValidBlockValue) EventQueryVote = QueryForEvent(EventVoteValue) EventQueryBlockSyncStatus = QueryForEvent(EventBlockSyncStatusValue) EventQueryStateSyncStatus = QueryForEvent(EventStateSyncStatusValue) ) func EventQueryTxFor(tx Tx) tmpubsub.Query { return tmquery.MustCompile(fmt.Sprintf("%s='%s' AND %s='%X'", EventTypeKey, EventTxValue, TxHashKey, tx.Hash())) } func QueryForEvent(eventValue string) tmpubsub.Query { return tmquery.MustCompile(fmt.Sprintf("%s='%s'", EventTypeKey, eventValue)) } // BlockEventPublisher publishes all block related events type BlockEventPublisher interface { PublishEventNewBlock(ctx context.Context, block EventDataNewBlock) error PublishEventNewBlockHeader(ctx context.Context, header EventDataNewBlockHeader) error PublishEventNewEvidence(ctx context.Context, evidence EventDataNewEvidence) error PublishEventTx(context.Context, EventDataTx) error PublishEventValidatorSetUpdates(context.Context, EventDataValidatorSetUpdates) error } type TxEventPublisher interface { PublishEventTx(context.Context, EventDataTx) error }