diff --git a/internal/statesync/stateprovider.go b/internal/statesync/stateprovider.go index b622824cd..83a95981c 100644 --- a/internal/statesync/stateprovider.go +++ b/internal/statesync/stateprovider.go @@ -85,6 +85,12 @@ func NewRPCStateProvider( }, nil } +func (s *stateProviderRPC) verifyLightBlockAtHeight(ctx context.Context, height uint64, ts time.Time) (*types.LightBlock, error) { + ctx, cancel := context.WithTimeout(ctx, 10*time.Second) + defer cancel() + return s.lc.VerifyLightBlockAtHeight(ctx, int64(height), ts) +} + // AppHash implements part of StateProvider. It calls the application to verify the // light blocks at heights h+1 and h+2 and, if verification succeeds, reports the app // hash for the block at height h+1 which correlates to the state at height h. @@ -93,7 +99,7 @@ func (s *stateProviderRPC) AppHash(ctx context.Context, height uint64) ([]byte, defer s.Unlock() // We have to fetch the next height, which contains the app hash for the previous height. - header, err := s.lc.VerifyLightBlockAtHeight(ctx, int64(height+1), time.Now()) + header, err := s.verifyLightBlockAtHeight(ctx, height+1, time.Now()) if err != nil { return nil, err } @@ -101,7 +107,7 @@ func (s *stateProviderRPC) AppHash(ctx context.Context, height uint64) ([]byte, // We also try to fetch the blocks at H+2, since we need these // when building the state while restoring the snapshot. This avoids the race // condition where we try to restore a snapshot before H+2 exists. - _, err = s.lc.VerifyLightBlockAtHeight(ctx, int64(height+2), time.Now()) + _, err = s.verifyLightBlockAtHeight(ctx, height+2, time.Now()) if err != nil { return nil, err } @@ -112,7 +118,7 @@ func (s *stateProviderRPC) AppHash(ctx context.Context, height uint64) ([]byte, func (s *stateProviderRPC) Commit(ctx context.Context, height uint64) (*types.Commit, error) { s.Lock() defer s.Unlock() - header, err := s.lc.VerifyLightBlockAtHeight(ctx, int64(height), time.Now()) + header, err := s.verifyLightBlockAtHeight(ctx, height, time.Now()) if err != nil { return nil, err } @@ -140,15 +146,15 @@ func (s *stateProviderRPC) State(ctx context.Context, height uint64) (sm.State, // // We need to fetch the NextValidators from height+2 because if the application changed // the validator set at the snapshot height then this only takes effect at height+2. - lastLightBlock, err := s.lc.VerifyLightBlockAtHeight(ctx, int64(height), time.Now()) + lastLightBlock, err := s.verifyLightBlockAtHeight(ctx, height, time.Now()) if err != nil { return sm.State{}, err } - currentLightBlock, err := s.lc.VerifyLightBlockAtHeight(ctx, int64(height+1), time.Now()) + currentLightBlock, err := s.verifyLightBlockAtHeight(ctx, height+1, time.Now()) if err != nil { return sm.State{}, err } - nextLightBlock, err := s.lc.VerifyLightBlockAtHeight(ctx, int64(height+2), time.Now()) + nextLightBlock, err := s.verifyLightBlockAtHeight(ctx, height+2, time.Now()) if err != nil { return sm.State{}, err } @@ -233,13 +239,19 @@ func NewP2PStateProvider( }, nil } +func (s *stateProviderP2P) verifyLightBlockAtHeight(ctx context.Context, height uint64, ts time.Time) (*types.LightBlock, error) { + ctx, cancel := context.WithTimeout(ctx, 10*time.Second) + defer cancel() + return s.lc.VerifyLightBlockAtHeight(ctx, int64(height), ts) +} + // AppHash implements StateProvider. func (s *stateProviderP2P) AppHash(ctx context.Context, height uint64) ([]byte, error) { s.Lock() defer s.Unlock() // We have to fetch the next height, which contains the app hash for the previous height. - header, err := s.lc.VerifyLightBlockAtHeight(ctx, int64(height+1), time.Now()) + header, err := s.verifyLightBlockAtHeight(ctx, height+1, time.Now()) if err != nil { return nil, err } @@ -247,7 +259,7 @@ func (s *stateProviderP2P) AppHash(ctx context.Context, height uint64) ([]byte, // We also try to fetch the blocks at H+2, since we need these // when building the state while restoring the snapshot. This avoids the race // condition where we try to restore a snapshot before H+2 exists. - _, err = s.lc.VerifyLightBlockAtHeight(ctx, int64(height+2), time.Now()) + _, err = s.verifyLightBlockAtHeight(ctx, height+2, time.Now()) if err != nil { return nil, err } @@ -258,7 +270,7 @@ func (s *stateProviderP2P) AppHash(ctx context.Context, height uint64) ([]byte, func (s *stateProviderP2P) Commit(ctx context.Context, height uint64) (*types.Commit, error) { s.Lock() defer s.Unlock() - header, err := s.lc.VerifyLightBlockAtHeight(ctx, int64(height), time.Now()) + header, err := s.verifyLightBlockAtHeight(ctx, height, time.Now()) if err != nil { return nil, err } @@ -286,15 +298,15 @@ func (s *stateProviderP2P) State(ctx context.Context, height uint64) (sm.State, // // We need to fetch the NextValidators from height+2 because if the application changed // the validator set at the snapshot height then this only takes effect at height+2. - lastLightBlock, err := s.lc.VerifyLightBlockAtHeight(ctx, int64(height), time.Now()) + lastLightBlock, err := s.verifyLightBlockAtHeight(ctx, height, time.Now()) if err != nil { return sm.State{}, err } - currentLightBlock, err := s.lc.VerifyLightBlockAtHeight(ctx, int64(height+1), time.Now()) + currentLightBlock, err := s.verifyLightBlockAtHeight(ctx, height+1, time.Now()) if err != nil { return sm.State{}, err } - nextLightBlock, err := s.lc.VerifyLightBlockAtHeight(ctx, int64(height+2), time.Now()) + nextLightBlock, err := s.verifyLightBlockAtHeight(ctx, height+2, time.Now()) if err != nil { return sm.State{}, err } diff --git a/light/client.go b/light/client.go index cc606f496..5bff76894 100644 --- a/light/client.go +++ b/light/client.go @@ -52,8 +52,6 @@ const ( // 10s is sufficient for most networks. defaultMaxBlockLag = 10 * time.Second - - defaultProviderTimeout = 10 * time.Second ) // Option sets a parameter for the light client. @@ -113,12 +111,6 @@ func MaxBlockLag(d time.Duration) Option { return func(c *Client) { c.maxBlockLag = d } } -// Provider timeout is the maximum time that the light client will wait for a -// provider to respond with a light block. -func ProviderTimeout(d time.Duration) Option { - return func(c *Client) { c.providerTimeout = d } -} - // Client represents a light client, connected to a single chain, which gets // light blocks from a primary provider, verifies them either sequentially or by // skipping some and stores them in a trusted store (usually, a local FS). @@ -131,7 +123,6 @@ type Client struct { trustLevel tmmath.Fraction maxClockDrift time.Duration maxBlockLag time.Duration - providerTimeout time.Duration // Mutex for locking during changes of the light clients providers providerMutex tmsync.Mutex @@ -202,7 +193,6 @@ func NewClient( trustLevel: DefaultTrustLevel, maxClockDrift: defaultMaxClockDrift, maxBlockLag: defaultMaxBlockLag, - providerTimeout: defaultProviderTimeout, pruningSize: defaultPruningSize, logger: log.NewNopLogger(), } @@ -695,9 +685,7 @@ func (c *Client) verifySkipping( if depth == len(blockCache)-1 { // schedule what the next height we need to fetch is pivotHeight := c.schedule(verifiedBlock.Height, blockCache[depth].Height) - subCtx, cancel := context.WithTimeout(ctx, c.providerTimeout) - defer cancel() - interimBlock, providerErr := c.getLightBlock(subCtx, source, pivotHeight) + interimBlock, providerErr := c.getLightBlock(ctx, source, pivotHeight) if providerErr != nil { return nil, ErrVerificationFailed{From: verifiedBlock.Height, To: pivotHeight, Reason: providerErr} } @@ -962,10 +950,8 @@ func (c *Client) lightBlockFromPrimary(ctx context.Context, height int64) (*type } func (c *Client) getLightBlock(ctx context.Context, p provider.Provider, height int64) (*types.LightBlock, error) { - subCtx, cancel := context.WithTimeout(ctx, c.providerTimeout) - defer cancel() - l, err := p.LightBlock(subCtx, height) - if err == context.DeadlineExceeded || ctx.Err() != nil { + l, err := p.LightBlock(ctx, height) + if ctx.Err() != nil { return nil, provider.ErrNoResponse } return l, err @@ -1014,16 +1000,19 @@ func (c *Client) findNewPrimary(ctx context.Context, height int64, remove bool) wg sync.WaitGroup ) - // send out a light block request to all witnesses - subctx, cancel := context.WithTimeout(ctx, c.providerTimeout) + ctx, cancel := context.WithCancel(ctx) defer cancel() + // send out a light block request to all witnesses for index := range c.witnesses { wg.Add(1) go func(witnessIndex int, witnessResponsesC chan witnessResponse) { defer wg.Done() - lb, err := c.witnesses[witnessIndex].LightBlock(subctx, height) - witnessResponsesC <- witnessResponse{lb, witnessIndex, err} + lb, err := c.witnesses[witnessIndex].LightBlock(ctx, height) + select { + case witnessResponsesC <- witnessResponse{lb, witnessIndex, err}: + case <-ctx.Done(): + } }(index, witnessResponsesC) }