Files
tendermint/rpc/client/helpers.go
M. J. Fromberger f795d3f360 rpc/client: rewrite the WaitForOneEvent helper (#7986)
Update usage in tests.
2022-02-24 11:21:40 -08:00

78 lines
2.1 KiB
Go

package client
import (
"context"
"fmt"
"time"
"github.com/tendermint/tendermint/internal/jsontypes"
"github.com/tendermint/tendermint/rpc/coretypes"
"github.com/tendermint/tendermint/types"
)
// Waiter is informed of current height, decided whether to quit early
type Waiter func(delta int64) (abort error)
// DefaultWaitStrategy is the standard backoff algorithm,
// but you can plug in another one
func DefaultWaitStrategy(delta int64) (abort error) {
if delta > 10 {
return fmt.Errorf("waiting for %d blocks... aborting", delta)
} else if delta > 0 {
// estimate of wait time....
// wait half a second for the next block (in progress)
// plus one second for every full block
delay := time.Duration(delta-1)*time.Second + 500*time.Millisecond
time.Sleep(delay)
}
return nil
}
// Wait for height will poll status at reasonable intervals until
// the block at the given height is available.
//
// If waiter is nil, we use DefaultWaitStrategy, but you can also
// provide your own implementation
func WaitForHeight(ctx context.Context, c StatusClient, h int64, waiter Waiter) error {
if waiter == nil {
waiter = DefaultWaitStrategy
}
delta := int64(1)
for delta > 0 {
s, err := c.Status(ctx)
if err != nil {
return err
}
delta = h - s.SyncInfo.LatestBlockHeight
// wait for the time, or abort early
if err := waiter(delta); err != nil {
return err
}
}
return nil
}
// WaitForOneEvent waits for the first event matching the given query on c, or
// until ctx ends. It reports an error if ctx ends before a matching event is
// received.
func WaitForOneEvent(ctx context.Context, c EventsClient, query string) (types.EventData, error) {
for {
rsp, err := c.Events(ctx, &coretypes.RequestEvents{
Filter: &coretypes.EventFilter{Query: query},
MaxItems: 1,
WaitTime: 10 * time.Second, // duration doesn't matter, limited by ctx timeout
})
if err != nil {
return nil, err
} else if len(rsp.Items) == 0 {
continue // continue polling until ctx expires
}
var result types.EventData
if err := jsontypes.Unmarshal(rsp.Items[0].Data, &result); err != nil {
return nil, err
}
return result, nil
}
}