Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support Event Indexing #7121

Merged
merged 8 commits into from
Aug 20, 2020
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions baseapp/abci.go
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ func (app *BaseApp) BeginBlock(req abci.RequestBeginBlock) (res abci.ResponseBeg

if app.beginBlocker != nil {
res = app.beginBlocker(app.deliverState.ctx, req)
res.Events = sdk.MarkEventsToIndex(res.Events, app.indexEvents)
}
// set the signed validators for addition to context in deliverTx
app.voteInfos = req.LastCommitInfo.GetVotes()
Expand All @@ -161,6 +162,7 @@ func (app *BaseApp) EndBlock(req abci.RequestEndBlock) (res abci.ResponseEndBloc

if app.endBlocker != nil {
res = app.endBlocker(app.deliverState.ctx, req)
res.Events = sdk.MarkEventsToIndex(res.Events, app.indexEvents)
}

if cp := app.GetConsensusParams(app.deliverState.ctx); cp != nil {
Expand Down Expand Up @@ -207,7 +209,7 @@ func (app *BaseApp) CheckTx(req abci.RequestCheckTx) abci.ResponseCheckTx {
GasUsed: int64(gInfo.GasUsed), // TODO: Should type accept unsigned ints?
Log: result.Log,
Data: result.Data,
Events: result.Events,
Events: sdk.MarkEventsToIndex(result.Events, app.indexEvents),
}
}

Expand Down Expand Up @@ -245,7 +247,7 @@ func (app *BaseApp) DeliverTx(req abci.RequestDeliverTx) abci.ResponseDeliverTx
GasUsed: int64(gInfo.GasUsed), // TODO: Should type accept unsigned ints?
Log: result.Log,
Data: result.Data,
Events: result.Events,
Events: sdk.MarkEventsToIndex(result.Events, app.indexEvents),
}
}

Expand Down
12 changes: 12 additions & 0 deletions baseapp/baseapp.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,10 @@ type BaseApp struct { // nolint: maligned

// trace set will return full stack traces for errors in ABCI Log field
trace bool

// indexEvents defines the set of events in the form {eventType}.{attributeKey},
// which informs Tendermint what to index. If empty, all events will be indexed.
indexEvents map[string]struct{}
}

// NewBaseApp returns a reference to an initialized BaseApp. It accepts a
Expand Down Expand Up @@ -283,6 +287,14 @@ func (app *BaseApp) setTrace(trace bool) {
app.trace = trace
}

func (app *BaseApp) setIndexEvents(ie []string) {
app.indexEvents = make(map[string]struct{})

for _, e := range ie {
app.indexEvents[e] = struct{}{}
}
}

// Router returns the router of the BaseApp.
func (app *BaseApp) Router() sdk.Router {
if app.sealed {
Expand Down
5 changes: 5 additions & 0 deletions baseapp/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,11 @@ func SetTrace(trace bool) func(*BaseApp) {
return func(app *BaseApp) { app.setTrace(trace) }
}

// SetIndexEvents provides a BaseApp option function that sets the events to index.
func SetIndexEvents(ie []string) func(*BaseApp) {
return func(app *BaseApp) { app.setIndexEvents(ie) }
}

// SetInterBlockCache provides a BaseApp option function that sets the
// inter-block cache.
func SetInterBlockCache(cache sdk.MultiStorePersistentCache) func(*BaseApp) {
Expand Down
6 changes: 6 additions & 0 deletions server/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ type BaseConfig struct {

// InterBlockCache enables inter-block caching.
InterBlockCache bool `mapstructure:"inter-block-cache"`

// IndexEvents defines the set of events in the form {eventType}.{attributeKey},
// which informs Tendermint what to index. If empty, all events will be indexed.
IndexEvents []string `mapstructure:"index-events"`
}

// APIConfig defines the API listener configuration.
Expand Down Expand Up @@ -134,6 +138,7 @@ func DefaultConfig() *Config {
PruningKeepRecent: "0",
PruningKeepEvery: "0",
PruningInterval: "0",
IndexEvents: make([]string, 0),
},
Telemetry: telemetry.Config{
Enabled: false,
Expand Down Expand Up @@ -175,6 +180,7 @@ func GetConfig(v *viper.Viper) Config {
PruningInterval: v.GetString("pruning-interval"),
HaltHeight: v.GetUint64("halt-height"),
HaltTime: v.GetUint64("halt-time"),
IndexEvents: v.GetStringSlice("index-events"),
},
Telemetry: telemetry.Config{
ServiceName: v.GetString("telemetry.service-name"),
Expand Down
4 changes: 4 additions & 0 deletions server/config/toml.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ halt-time = {{ .BaseConfig.HaltTime }}
# InterBlockCache enables inter-block caching.
inter-block-cache = {{ .BaseConfig.InterBlockCache }}

# IndexEvents defines the set of events in the form {eventType}.{attributeKey},
# which informs Tendermint what to index. If empty, all events will be indexed.
alexanderbez marked this conversation as resolved.
Show resolved Hide resolved
index-events = {{ .BaseConfig.IndexEvents }}

###############################################################################
### Telemetry Configuration ###
###############################################################################
Expand Down
1 change: 1 addition & 0 deletions server/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ const (
FlagPruningKeepRecent = "pruning-keep-recent"
FlagPruningKeepEvery = "pruning-keep-every"
FlagPruningInterval = "pruning-interval"
FlagIndexEvents = "index-events"
)

// GRPC-related flags.
Expand Down
1 change: 1 addition & 0 deletions simapp/simd/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,7 @@ func newApp(logger log.Logger, db dbm.DB, traceStore io.Writer, appOpts serverty
baseapp.SetHaltTime(cast.ToUint64(appOpts.Get(server.FlagHaltTime))),
baseapp.SetInterBlockCache(cache),
baseapp.SetTrace(cast.ToBool(appOpts.Get(server.FlagTrace))),
baseapp.SetIndexEvents(cast.ToStringSlice(appOpts.Get(server.FlagIndexEvents))),
)
}

Expand Down
27 changes: 27 additions & 0 deletions types/events.go
Original file line number Diff line number Diff line change
Expand Up @@ -199,3 +199,30 @@ func StringifyEvents(events []abci.Event) StringEvents {

return res.Flatten()
}

// MarkEventsToIndex returns the set of ABCI events, where each event's attribute
// has it's index value marked based on the provided set of events to index.
func MarkEventsToIndex(events []abci.Event, indexSet map[string]struct{}) []abci.Event {
updatedEvents := make([]abci.Event, len(events))
for i, e := range events {
updatedEvent := abci.Event{
Type: e.Type,
Attributes: make([]abci.EventAttribute, len(e.Attributes)),
}

for j, attr := range e.Attributes {
_, index := indexSet[fmt.Sprintf("%s.%s", e.Type, attr.Key)]
updatedAttr := abci.EventAttribute{
Key: attr.Key,
Value: attr.Value,
Index: index,
}

updatedEvent.Attributes[j] = updatedAttr
}

updatedEvents[i] = updatedEvent
}

return updatedEvents
}
87 changes: 87 additions & 0 deletions types/events_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"testing"

"github.com/stretchr/testify/require"
abci "github.com/tendermint/tendermint/abci/types"
)

func TestAppendEvents(t *testing.T) {
Expand Down Expand Up @@ -69,3 +70,89 @@ func TestStringifyEvents(t *testing.T) {
expectedJSONStr := "[{\"type\":\"message\",\"attributes\":[{\"key\":\"sender\",\"value\":\"foo\"},{\"key\":\"module\",\"value\":\"bank\"}]}]"
require.Equal(t, expectedJSONStr, string(bz))
}

func TestMarkEventsToIndex(t *testing.T) {
events := []abci.Event{
{
Type: "message",
Attributes: []abci.EventAttribute{
{Key: []byte("sender"), Value: []byte("foo")},
{Key: []byte("recipient"), Value: []byte("bar")},
},
},
{
Type: "staking",
Attributes: []abci.EventAttribute{
{Key: []byte("deposit"), Value: []byte("5")},
{Key: []byte("unbond"), Value: []byte("10")},
},
},
}

testCases := map[string]struct {
events []abci.Event
indexSet map[string]struct{}
expected []abci.Event
}{
"empty index set": {
events: events,
expected: events,
indexSet: map[string]struct{}{},
},
"index some events": {
events: events,
expected: []abci.Event{
{
Type: "message",
Attributes: []abci.EventAttribute{
{Key: []byte("sender"), Value: []byte("foo"), Index: true},
{Key: []byte("recipient"), Value: []byte("bar")},
},
},
{
Type: "staking",
Attributes: []abci.EventAttribute{
{Key: []byte("deposit"), Value: []byte("5"), Index: true},
{Key: []byte("unbond"), Value: []byte("10")},
},
},
},
indexSet: map[string]struct{}{
"message.sender": {},
"staking.deposit": {},
},
},
"index all events": {
events: events,
expected: []abci.Event{
{
Type: "message",
Attributes: []abci.EventAttribute{
{Key: []byte("sender"), Value: []byte("foo"), Index: true},
{Key: []byte("recipient"), Value: []byte("bar"), Index: true},
},
},
{
Type: "staking",
Attributes: []abci.EventAttribute{
{Key: []byte("deposit"), Value: []byte("5"), Index: true},
{Key: []byte("unbond"), Value: []byte("10"), Index: true},
},
},
},
indexSet: map[string]struct{}{
"message.sender": {},
"message.recipient": {},
"staking.deposit": {},
"staking.unbond": {},
},
},
}

for name, tc := range testCases {
tc := tc
t.Run(name, func(t *testing.T) {
require.Equal(t, tc.expected, MarkEventsToIndex(tc.events, tc.indexSet))
})
}
}