pubsub: Refactor Event Subscription (#6634)

This commit is contained in:
Aleksandr Bezobchuk
2021-07-01 11:17:48 -04:00
committed by GitHub
parent b0a413eb17
commit 414130aee1
19 changed files with 428 additions and 226 deletions

View File

@@ -3,6 +3,7 @@ package types
import (
"context"
"fmt"
"strings"
"github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/libs/log"
@@ -100,47 +101,31 @@ func (b *EventBus) UnsubscribeAll(ctx context.Context, subscriber string) error
return b.pubsub.UnsubscribeAll(ctx, subscriber)
}
func (b *EventBus) Publish(eventType string, eventData TMEventData) error {
func (b *EventBus) Publish(eventValue string, eventData TMEventData) error {
// no explicit deadline for publishing events
ctx := context.Background()
return b.pubsub.PublishWithEvents(ctx, eventData, map[string][]string{EventTypeKey: {eventType}})
}
// validateAndStringifyEvents takes a slice of event objects and creates a
// map of stringified events where each key is composed of the event
// type and each of the event's attributes keys in the form of
// "{event.Type}.{attribute.Key}" and the value is each attribute's value.
func (b *EventBus) validateAndStringifyEvents(events []types.Event, logger log.Logger) map[string][]string {
result := make(map[string][]string)
for _, event := range events {
if len(event.Type) == 0 {
logger.Debug("Got an event with an empty type (skipping)", "event", event)
continue
}
for _, attr := range event.Attributes {
if len(attr.Key) == 0 {
logger.Debug("Got an event attribute with an empty key(skipping)", "event", event)
continue
}
compositeTag := fmt.Sprintf("%s.%s", event.Type, attr.Key)
result[compositeTag] = append(result[compositeTag], attr.Value)
}
tokens := strings.Split(EventTypeKey, ".")
event := types.Event{
Type: tokens[0],
Attributes: []types.EventAttribute{
{
Key: tokens[1],
Value: eventValue,
},
},
}
return result
return b.pubsub.PublishWithEvents(ctx, eventData, []types.Event{event})
}
func (b *EventBus) PublishEventNewBlock(data EventDataNewBlock) error {
// no explicit deadline for publishing events
ctx := context.Background()
events := append(data.ResultBeginBlock.Events, data.ResultEndBlock.Events...)
resultEvents := append(data.ResultBeginBlock.Events, data.ResultEndBlock.Events...)
events := b.validateAndStringifyEvents(resultEvents, b.Logger.With("block", data.Block.StringShort()))
// add predefined new block event
events[EventTypeKey] = append(events[EventTypeKey], EventNewBlock)
// add Tendermint-reserved new block event
events = append(events, EventNewBlock)
return b.pubsub.PublishWithEvents(ctx, data, events)
}
@@ -148,27 +133,24 @@ func (b *EventBus) PublishEventNewBlock(data EventDataNewBlock) error {
func (b *EventBus) PublishEventNewBlockHeader(data EventDataNewBlockHeader) error {
// no explicit deadline for publishing events
ctx := context.Background()
events := append(data.ResultBeginBlock.Events, data.ResultEndBlock.Events...)
resultTags := append(data.ResultBeginBlock.Events, data.ResultEndBlock.Events...)
// TODO: Create StringShort method for Header and use it in logger.
events := b.validateAndStringifyEvents(resultTags, b.Logger.With("header", data.Header))
// add predefined new block header event
events[EventTypeKey] = append(events[EventTypeKey], EventNewBlockHeader)
// add Tendermint-reserved new block header event
events = append(events, EventNewBlockHeader)
return b.pubsub.PublishWithEvents(ctx, data, events)
}
func (b *EventBus) PublishEventNewEvidence(evidence EventDataNewEvidence) error {
return b.Publish(EventNewEvidence, evidence)
return b.Publish(EventNewEvidenceValue, evidence)
}
func (b *EventBus) PublishEventVote(data EventDataVote) error {
return b.Publish(EventVote, data)
return b.Publish(EventVoteValue, data)
}
func (b *EventBus) PublishEventValidBlock(data EventDataRoundState) error {
return b.Publish(EventValidBlock, data)
return b.Publish(EventValidBlockValue, data)
}
// PublishEventTx publishes tx event with events from Result. Note it will add
@@ -177,55 +159,74 @@ func (b *EventBus) PublishEventValidBlock(data EventDataRoundState) error {
func (b *EventBus) PublishEventTx(data EventDataTx) error {
// no explicit deadline for publishing events
ctx := context.Background()
events := data.Result.Events
events := b.validateAndStringifyEvents(data.Result.Events, b.Logger.With("tx", data.Tx))
// add Tendermint-reserved events
events = append(events, EventTx)
// add predefined compositeKeys
events[EventTypeKey] = append(events[EventTypeKey], EventTx)
events[TxHashKey] = append(events[TxHashKey], fmt.Sprintf("%X", Tx(data.Tx).Hash()))
events[TxHeightKey] = append(events[TxHeightKey], fmt.Sprintf("%d", data.Height))
tokens := strings.Split(TxHashKey, ".")
events = append(events, types.Event{
Type: tokens[0],
Attributes: []types.EventAttribute{
{
Key: tokens[1],
Value: fmt.Sprintf("%X", Tx(data.Tx).Hash()),
},
},
})
tokens = strings.Split(TxHeightKey, ".")
events = append(events, types.Event{
Type: tokens[0],
Attributes: []types.EventAttribute{
{
Key: tokens[1],
Value: fmt.Sprintf("%d", data.Height),
},
},
})
return b.pubsub.PublishWithEvents(ctx, data, events)
}
func (b *EventBus) PublishEventNewRoundStep(data EventDataRoundState) error {
return b.Publish(EventNewRoundStep, data)
return b.Publish(EventNewRoundStepValue, data)
}
func (b *EventBus) PublishEventTimeoutPropose(data EventDataRoundState) error {
return b.Publish(EventTimeoutPropose, data)
return b.Publish(EventTimeoutProposeValue, data)
}
func (b *EventBus) PublishEventTimeoutWait(data EventDataRoundState) error {
return b.Publish(EventTimeoutWait, data)
return b.Publish(EventTimeoutWaitValue, data)
}
func (b *EventBus) PublishEventNewRound(data EventDataNewRound) error {
return b.Publish(EventNewRound, data)
return b.Publish(EventNewRoundValue, data)
}
func (b *EventBus) PublishEventCompleteProposal(data EventDataCompleteProposal) error {
return b.Publish(EventCompleteProposal, data)
return b.Publish(EventCompleteProposalValue, data)
}
func (b *EventBus) PublishEventPolka(data EventDataRoundState) error {
return b.Publish(EventPolka, data)
return b.Publish(EventPolkaValue, data)
}
func (b *EventBus) PublishEventUnlock(data EventDataRoundState) error {
return b.Publish(EventUnlock, data)
return b.Publish(EventUnlockValue, data)
}
func (b *EventBus) PublishEventRelock(data EventDataRoundState) error {
return b.Publish(EventRelock, data)
return b.Publish(EventRelockValue, data)
}
func (b *EventBus) PublishEventLock(data EventDataRoundState) error {
return b.Publish(EventLock, data)
return b.Publish(EventLockValue, data)
}
func (b *EventBus) PublishEventValidatorSetUpdates(data EventDataValidatorSetUpdates) error {
return b.Publish(EventValidatorSetUpdates, data)
return b.Publish(EventValidatorSetUpdatesValue, data)
}
//-----------------------------------------------------------------------------

View File

@@ -342,7 +342,7 @@ func TestEventBusPublish(t *testing.T) {
}
}()
err = eventBus.Publish(EventNewBlockHeader, EventDataNewBlockHeader{})
err = eventBus.Publish(EventNewBlockHeaderValue, EventDataNewBlockHeader{})
require.NoError(t, err)
err = eventBus.PublishEventNewBlock(EventDataNewBlock{})
require.NoError(t, err)
@@ -447,16 +447,16 @@ func benchmarkEventBus(numClients int, randQueries bool, randEvents bool, b *tes
}()
}
eventType := EventNewBlock
eventValue := EventNewBlockValue
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
if randEvents {
eventType = randEvent()
eventValue = randEventValue()
}
err := eventBus.Publish(eventType, EventDataString("Gamora"))
err := eventBus.Publish(eventValue, EventDataString("Gamora"))
if err != nil {
b.Error(err)
}
@@ -464,20 +464,21 @@ func benchmarkEventBus(numClients int, randQueries bool, randEvents bool, b *tes
}
var events = []string{
EventNewBlock,
EventNewBlockHeader,
EventNewRound,
EventNewRoundStep,
EventTimeoutPropose,
EventCompleteProposal,
EventPolka,
EventUnlock,
EventLock,
EventRelock,
EventTimeoutWait,
EventVote}
EventNewBlockValue,
EventNewBlockHeaderValue,
EventNewRoundValue,
EventNewRoundStepValue,
EventTimeoutProposeValue,
EventCompleteProposalValue,
EventPolkaValue,
EventUnlockValue,
EventLockValue,
EventRelockValue,
EventTimeoutWaitValue,
EventVoteValue,
}
func randEvent() string {
func randEventValue() string {
return events[mrand.Intn(len(events))]
}

View File

@@ -2,6 +2,7 @@ package types
import (
"fmt"
"strings"
abci "github.com/tendermint/tendermint/abci/types"
tmjson "github.com/tendermint/tendermint/libs/json"
@@ -16,26 +17,69 @@ const (
// 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.
EventNewBlock = "NewBlock"
EventNewBlockHeader = "NewBlockHeader"
EventNewEvidence = "NewEvidence"
EventTx = "Tx"
EventValidatorSetUpdates = "ValidatorSetUpdates"
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.
EventCompleteProposal = "CompleteProposal"
EventLock = "Lock"
EventNewRound = "NewRound"
EventNewRoundStep = "NewRoundStep"
EventPolka = "Polka"
EventRelock = "Relock"
EventTimeoutPropose = "TimeoutPropose"
EventTimeoutWait = "TimeoutWait"
EventUnlock = "Unlock"
EventValidBlock = "ValidBlock"
EventVote = "Vote"
EventCompleteProposalValue = "CompleteProposal"
EventLockValue = "Lock"
EventNewRoundValue = "NewRound"
EventNewRoundStepValue = "NewRoundStep"
EventPolkaValue = "Polka"
EventRelockValue = "Relock"
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
@@ -147,30 +191,30 @@ const (
)
var (
EventQueryCompleteProposal = QueryForEvent(EventCompleteProposal)
EventQueryLock = QueryForEvent(EventLock)
EventQueryNewBlock = QueryForEvent(EventNewBlock)
EventQueryNewBlockHeader = QueryForEvent(EventNewBlockHeader)
EventQueryNewEvidence = QueryForEvent(EventNewEvidence)
EventQueryNewRound = QueryForEvent(EventNewRound)
EventQueryNewRoundStep = QueryForEvent(EventNewRoundStep)
EventQueryPolka = QueryForEvent(EventPolka)
EventQueryRelock = QueryForEvent(EventRelock)
EventQueryTimeoutPropose = QueryForEvent(EventTimeoutPropose)
EventQueryTimeoutWait = QueryForEvent(EventTimeoutWait)
EventQueryTx = QueryForEvent(EventTx)
EventQueryUnlock = QueryForEvent(EventUnlock)
EventQueryValidatorSetUpdates = QueryForEvent(EventValidatorSetUpdates)
EventQueryValidBlock = QueryForEvent(EventValidBlock)
EventQueryVote = QueryForEvent(EventVote)
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)
)
func EventQueryTxFor(tx Tx) tmpubsub.Query {
return tmquery.MustParse(fmt.Sprintf("%s='%s' AND %s='%X'", EventTypeKey, EventTx, TxHashKey, tx.Hash()))
return tmquery.MustParse(fmt.Sprintf("%s='%s' AND %s='%X'", EventTypeKey, EventTxValue, TxHashKey, tx.Hash()))
}
func QueryForEvent(eventType string) tmpubsub.Query {
return tmquery.MustParse(fmt.Sprintf("%s='%s'", EventTypeKey, eventType))
func QueryForEvent(eventValue string) tmpubsub.Query {
return tmquery.MustParse(fmt.Sprintf("%s='%s'", EventTypeKey, eventValue))
}
// BlockEventPublisher publishes all block related events

View File

@@ -18,10 +18,10 @@ func TestQueryTxFor(t *testing.T) {
func TestQueryForEvent(t *testing.T) {
assert.Equal(t,
"tm.event='NewBlock'",
QueryForEvent(EventNewBlock).String(),
QueryForEvent(EventNewBlockValue).String(),
)
assert.Equal(t,
"tm.event='NewEvidence'",
QueryForEvent(EventNewEvidence).String(),
QueryForEvent(EventNewEvidenceValue).String(),
)
}