rpc: implement the ADR 075 /events method (#7965)

This method implements the eventlog extension interface to expose ABCI metadata
to the log for query processing. Only the types that have ABCI events need to
implement this.

- Add an event log to the environment
- Add a sketch of the handler method
- Add an /events RPCFunc to the route map
- Implement query logic
- Subscribe to pubsub if confingured, handle termination
This commit is contained in:
M. J. Fromberger
2022-02-23 15:22:40 -08:00
committed by GitHub
parent 61a81279bd
commit 5662bd12a8
7 changed files with 303 additions and 1 deletions

View File

@@ -92,7 +92,13 @@ var (
// ENCODING / DECODING
// EventData is satisfied by types that can be published as event data.
//
// Implementations of this interface that contain ABCI event metadata should
// also implement the eventlog.ABCIEventer extension interface to expose those
// metadata to the event log machinery. Event data that do not contain ABCI
// metadata can safely omit this.
type EventData interface {
// The value must support encoding as a type-tagged JSON object.
jsontypes.Tagged
}
@@ -125,6 +131,9 @@ type EventDataNewBlock struct {
// TypeTag implements the required method of jsontypes.Tagged.
func (EventDataNewBlock) TypeTag() string { return "tendermint/event/NewBlock" }
// ABCIEvents implements the eventlog.ABCIEventer interface.
func (e EventDataNewBlock) ABCIEvents() []abci.Event { return e.ResultFinalizeBlock.Events }
type EventDataNewBlockHeader struct {
Header Header `json:"header"`
@@ -135,6 +144,9 @@ type EventDataNewBlockHeader struct {
// TypeTag implements the required method of jsontypes.Tagged.
func (EventDataNewBlockHeader) TypeTag() string { return "tendermint/event/NewBlockHeader" }
// ABCIEvents implements the eventlog.ABCIEventer interface.
func (e EventDataNewBlockHeader) ABCIEvents() []abci.Event { return e.ResultFinalizeBlock.Events }
type EventDataNewEvidence struct {
Evidence Evidence `json:"evidence"`
@@ -152,6 +164,15 @@ type EventDataTx struct {
// TypeTag implements the required method of jsontypes.Tagged.
func (EventDataTx) TypeTag() string { return "tendermint/event/Tx" }
// ABCIEvents implements the eventlog.ABCIEventer interface.
func (e EventDataTx) ABCIEvents() []abci.Event {
base := []abci.Event{
eventWithAttr(TxHashKey, fmt.Sprintf("%X", Tx(e.Tx).Hash())),
eventWithAttr(TxHeightKey, fmt.Sprintf("%d", e.Height)),
}
return append(base, e.Result.Events...)
}
// NOTE: This goes into the replay WAL
type EventDataRoundState struct {
Height int64 `json:"height,string"`
@@ -298,3 +319,16 @@ type BlockEventPublisher interface {
type TxEventPublisher interface {
PublishEventTx(context.Context, EventDataTx) error
}
// eventWithAttr constructs a single abci.Event with a single attribute.
// The type of the event and the name of the attribute are obtained by
// splitting the event type on period (e.g., "foo.bar").
func eventWithAttr(etype, value string) abci.Event {
parts := strings.SplitN(etype, ".", 2)
return abci.Event{
Type: parts[0],
Attributes: []abci.EventAttribute{{
Key: parts[1], Value: value,
}},
}
}

View File

@@ -7,6 +7,22 @@ import (
"github.com/stretchr/testify/assert"
)
// Verify that the event data types satisfy their shared interface.
var (
_ EventData = EventDataBlockSyncStatus{}
_ EventData = EventDataCompleteProposal{}
_ EventData = EventDataNewBlock{}
_ EventData = EventDataNewBlockHeader{}
_ EventData = EventDataNewEvidence{}
_ EventData = EventDataNewRound{}
_ EventData = EventDataRoundState{}
_ EventData = EventDataStateSyncStatus{}
_ EventData = EventDataTx{}
_ EventData = EventDataValidatorSetUpdates{}
_ EventData = EventDataVote{}
_ EventData = EventDataString("")
)
func TestQueryTxFor(t *testing.T) {
tx := Tx("foo")
assert.Equal(t,