To tell which events you want, you need to provide a query. query is a string, which has a form: "condition AND condition ..." (no OR at the moment). condition has a form: "key operation operand". key is a string with a restricted set of possible symbols ( \t\n\r\()"'=>< are not allowed). operation can be "=", "<", "<=", ">", ">=", "CONTAINS" AND "EXISTS". operand can be a string (escaped with single quotes), number, date or time.
Examples: tm.event = 'NewBlock' # new blocks tm.event = 'CompleteProposal' # node got a complete proposal tm.event = 'Tx' AND tx.hash = 'XYZ' # single transaction tm.event = 'Tx' AND tx.height = 5 # all txs of the fifth block tx.height = 5 # all txs of the fifth block
Tendermint provides a few predefined keys: tm.event, tx.hash and tx.height. Note for transactions, you can define additional keys by providing events with DeliverTx response.
import ( abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/libs/pubsub/query" )
abci.ResponseDeliverTx{ Events: []abci.Event{ { Type: "rewards.withdraw", Attributes: abci.EventAttribute{ {Key: []byte("address"), Value: []byte("AddrA"), Index: true}, {Key: []byte("source"), Value: []byte("SrcX"), Index: true}, {Key: []byte("amount"), Value: []byte("..."), Index: true}, {Key: []byte("balance"), Value: []byte("..."), Index: true}, }, }, { Type: "rewards.withdraw", Attributes: abci.EventAttribute{ {Key: []byte("address"), Value: []byte("AddrB"), Index: true}, {Key: []byte("source"), Value: []byte("SrcY"), Index: true}, {Key: []byte("amount"), Value: []byte("..."), Index: true}, {Key: []byte("balance"), Value: []byte("..."), Index: true}, }, }, { Type: "transfer", Attributes: abci.EventAttribute{ {Key: []byte("sender"), Value: []byte("AddrC"), Index: true}, {Key: []byte("recipient"), Value: []byte("AddrD"), Index: true}, {Key: []byte("amount"), Value: []byte("..."), Index: true}, }, }, }, }
All events are indexed by a composite key of the form {eventType}.{evenAttrKey}. In the above examples, the following keys would be indexed:
Multiple event types with duplicate keys are allowed and are meant to
categorize unique and distinct events. In the above example, all events
indexed under the key rewards.withdraw.address
will have the following
values stored and queryable:
To create a query for txs where address AddrA withdrew rewards: query.MustParse("tm.event = 'Tx' AND rewards.withdraw.address = 'AddrA'")
To create a query for txs where address AddrA withdrew rewards from source Y: query.MustParse("tm.event = 'Tx' AND rewards.withdraw.address = 'AddrA' AND rewards.withdraw.source = 'Y'")
To create a query for txs where AddrA transferred funds: query.MustParse("tm.event = 'Tx' AND transfer.sender = 'AddrA'")
The following queries would return no results: query.MustParse("tm.event = 'Tx' AND transfer.sender = 'AddrZ'") query.MustParse("tm.event = 'Tx' AND rewards.withdraw.address = 'AddrZ'") query.MustParse("tm.event = 'Tx' AND rewards.withdraw.source = 'W'")
See list of all possible events here https://godoc.org/github.com/tendermint/tendermint/types#pkg-constants
For complete query syntax, check out https://godoc.org/github.com/tendermint/tendermint/libs/pubsub/query.
import rpchttp "github.com/tendermint/rpc/client/http"
import "github.com/tendermint/tendermint/types"
client := rpchttp.New("tcp:0.0.0.0:26657", "/websocket")
err := client.Start()
if err != nil {
handle error
}
defer client.Stop()
ctx, cancel := context.WithTimeout(context.Background(), 1 * time.Second)
defer cancel()
query := "tm.event = 'Tx' AND tx.height = 3"
txs, err := client.Subscribe(ctx, "test-client", query)
if err != nil {
handle error
}
go func() {
for e := range txs {
fmt.Println("got ", e.Data.(types.EventDataTx))
}
}()
NOTE: if you're not reading events fast enough, Tendermint might terminate the subscription.
empty answer
0
"2.0"