State implements StateProvider.
(ctx context.Context, height uint64)
| 123 | |
| 124 | // State implements StateProvider. |
| 125 | func (s *lightClientStateProvider) State(ctx context.Context, height uint64) (sm.State, error) { |
| 126 | s.Lock() |
| 127 | defer s.Unlock() |
| 128 | |
| 129 | state := sm.State{ |
| 130 | ChainID: s.lc.ChainID(), |
| 131 | Version: s.version, |
| 132 | InitialHeight: s.initialHeight, |
| 133 | } |
| 134 | if state.InitialHeight == 0 { |
| 135 | state.InitialHeight = 1 |
| 136 | } |
| 137 | |
| 138 | // The snapshot height maps onto the state heights as follows: |
| 139 | // |
| 140 | // height: last block, i.e. the snapshotted height |
| 141 | // height+1: current block, i.e. the first block we'll process after the snapshot |
| 142 | // height+2: next block, i.e. the second block after the snapshot |
| 143 | // |
| 144 | // We need to fetch the NextValidators from height+2 because if the application changed |
| 145 | // the validator set at the snapshot height then this only takes effect at height+2. |
| 146 | lastLightBlock, err := s.lc.VerifyLightBlockAtHeight(ctx, int64(height), time.Now()) |
| 147 | if err != nil { |
| 148 | return sm.State{}, err |
| 149 | } |
| 150 | currentLightBlock, err := s.lc.VerifyLightBlockAtHeight(ctx, int64(height+1), time.Now()) |
| 151 | if err != nil { |
| 152 | return sm.State{}, err |
| 153 | } |
| 154 | nextLightBlock, err := s.lc.VerifyLightBlockAtHeight(ctx, int64(height+2), time.Now()) |
| 155 | if err != nil { |
| 156 | return sm.State{}, err |
| 157 | } |
| 158 | |
| 159 | state.Version = tmstate.Version{ |
| 160 | Consensus: currentLightBlock.Version, |
| 161 | Software: version.TMCoreSemVer, |
| 162 | } |
| 163 | state.LastBlockHeight = lastLightBlock.Height |
| 164 | state.LastBlockTime = lastLightBlock.Time |
| 165 | state.LastBlockID = lastLightBlock.Commit.BlockID |
| 166 | state.AppHash = currentLightBlock.AppHash |
| 167 | state.LastResultsHash = currentLightBlock.LastResultsHash |
| 168 | state.LastValidators = lastLightBlock.ValidatorSet |
| 169 | state.Validators = currentLightBlock.ValidatorSet |
| 170 | state.NextValidators = nextLightBlock.ValidatorSet |
| 171 | state.LastHeightValidatorsChanged = nextLightBlock.Height |
| 172 | |
| 173 | // We'll also need to fetch consensus params via RPC, using light client verification. |
| 174 | primaryURL, ok := s.providers[s.lc.Primary()] |
| 175 | if !ok || primaryURL == "" { |
| 176 | return sm.State{}, fmt.Errorf("could not find address for primary light client provider") |
| 177 | } |
| 178 | primaryRPC, err := rpcClient(primaryURL) |
| 179 | if err != nil { |
| 180 | return sm.State{}, fmt.Errorf("unable to create RPC client: %w", err) |
| 181 | } |
| 182 | rpcclient := lightrpc.NewClient(primaryRPC, s.lc) |
nothing calls this directly
no test coverage detected