Closes: #4420
Created a new error ErrInvalidHeaderwhich can be formed during the verification process verifier.go and will result in the replacement of the primary provider with a witness by executing: replacePrimaryProvider()
Co-authored-by: Anton Kaliaev <anton.kalyaev@gmail.com>
error itself is not enough since it only signals if there were any
errors. Either (types.SignedHeader) or (success bool) is needed to
indicate the status of the operation. Returning a header is optimal
since most of the clients will want to get a newly verified header
anyway.
We first introduced auto-update as a separate struct AutoClient, which
was wrapping Client and calling Update periodically.
// AutoClient can auto update itself by fetching headers every N seconds.
type AutoClient struct {
base *Client
updatePeriod time.Duration
quit chan struct{}
trustedHeaders chan *types.SignedHeader
errs chan error
}
// NewAutoClient creates a new client and starts a polling goroutine.
func NewAutoClient(base *Client, updatePeriod time.Duration) *AutoClient {
c := &AutoClient{
base: base,
updatePeriod: updatePeriod,
quit: make(chan struct{}),
trustedHeaders: make(chan *types.SignedHeader),
errs: make(chan error),
}
go c.autoUpdate()
return c
}
// TrustedHeaders returns a channel onto which new trusted headers are posted.
func (c *AutoClient) TrustedHeaders() <-chan *types.SignedHeader {
return c.trustedHeaders
}
// Err returns a channel onto which errors are posted.
func (c *AutoClient) Errs() <-chan error {
return c.errs
}
// Stop stops the client.
func (c *AutoClient) Stop() {
close(c.quit)
}
func (c *AutoClient) autoUpdate() {
ticker := time.NewTicker(c.updatePeriod)
defer ticker.Stop()
for {
select {
case <-ticker.C:
lastTrustedHeight, err := c.base.LastTrustedHeight()
if err != nil {
c.errs <- err
continue
}
if lastTrustedHeight == -1 {
// no headers yet => wait
continue
}
newTrustedHeader, err := c.base.Update(time.Now())
if err != nil {
c.errs <- err
continue
}
if newTrustedHeader != nil {
c.trustedHeaders <- newTrustedHeader
}
case <-c.quit:
return
}
}
}
Later we merged it into the Client itself with the assumption that most clients will want it.
But now I am not sure. Neither IBC nor cosmos/relayer are using it. It increases complexity (Start/Stop methods).
That said, I think it makes sense to remove it until we see a need for it (until we better understand usage behavior). We can always introduce it later 😅. Maybe in the form of AutoClient.
* fix: fix proto-breakage
- this is amed to fix proto breakage for consumers
Signed-off-by: Marko Baricevic <marbar3778@yahoo.com>
* fix for importing third_party everywhere
* undo change
* test breakage change
* test ssh
* test https
* change ssh to https
* fix phony
* rpc: use BlockStoreRPC instead of BlockStore
BlockStoreRPC is a limited version of BlockStore interface, which does
not include SaveBlock method.
Closes#4159
* remove BlockStoreRPC interface in favor of single BlockStore
interface
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
* lite2: fix tendermint lite sub command
- better logging
- chainID as an argument
- more examples
* one more log msg
* lite2: fire update right away after start
* turn off auto update in verification tests
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
* test functions take time.Now and other minor changes
* updated remaining test files
* Update validation_test.go
* fix typo
* go fmt
* import time
Co-authored-by: Marko <marbar3778@yahoo.com>
closes#4469
Improved speed of cleanup by using SignedHeaderAfter instead of TrustedHeader to jump from header to header.
Prune() is now called when a new header and validator set are saved and is a function dealt by the database itself
## Commits:
* prune headers and vals
* modified cleanup and tests
* fixes after my own review
* implement Prune func
* make db ops concurrently safe
* use Iterator in SignedHeaderAfter
we should iterate from height+1, not from the end!
* simplify cleanup
Co-authored-by: Anton Kaliaev <anton.kalyaev@gmail.com>
closes: #4455
Verifying backwards checks that the trustedHeader hasn't expired both before and after the loop in case of verifying many headers (a longer operation), but not during the loop itself.
TrustedHeader() no longer checks whether the header saved in the store has expired.
Tests have been updated to reflect the changes
## Commits:
* verify headers backwards out of trust period
* removed expiration check in trusted header func
* modified tests to reflect changes
* wrote new tests for backwards verification
* modified TrustedHeader and TrustedValSet functions
* condensed test functions
* condensed test functions further
* fix build error
* update doc
* add comments
* remove unnecessary declaration
* extract latestHeight check into a separate func
Co-authored-by: Callum Waters <cmwaters19@gmail.com>
Before we were storing trustedHeader (height=1) and trustedNextVals
(height=2).
After this change, we will be storing trustedHeader (height=1) and
trustedVals (height=1). This a) simplifies the code b) fixes#4399
inconsistent pairing issue c) gives a relayer access to the current
validator set #4470.
The only downside is more jumps during bisection. If validator set
changes between trustedHeader and the next header (by 2/3 or more), the
light client will be forced to download the next header and check that
2/3+ signed the transition. But we don't expect validator set change too
much and too often, so it's an acceptable compromise.
Closes#4470 and #4399
closes#4426
The sequence and bisection methods no longer save the intermediate headers and validator sets that they require to verify a currently untrusted header.
## Commits:
* sequence and bisection don't save intermediate headers and vals
* check the next validator hash matches the header
* check expired header at start of backwards verification
* added tests
* handled cleanup warning
* lint fix
* removed redundant code
* tweaked minor errors
* avoided premature trusting of nextVals
* fix test error
* updated trustedHeader and Vals together
* fixed bisection error
* fixed sequence error for different vals and made test
* fixes after my own review
* reorder vars to be consistent
with the rest of the code
Co-authored-by: Anton Kaliaev <anton.kalyaev@gmail.com>
closes#4413 and #4419
When VerifyHeaderAtHeight() is called, TrustedHeader is initially run to check if the header has already been verified and returns the Header.
If the new header height is less than the lite clients latestTrustedHeader height, than backwards verification is performed else either sequence or bisection
Refactored a test to reflect the changes
* use trustedHeader func for already verified Headers
* remove fetch missing header from TrustedHeader
* check for already trusted Header in VerifyHeaderAtHeight
* replace updateTrustedHeaderAndVals to updateTrustedHeaderAndNextVals
* rename trustedHeader and trustedNextVals
* refactored backwards and included it in VerifyHeader
* cleaned up test to match changes
* lite2: fixes after my own review
Refs https://github.com/tendermint/tendermint/pull/4428#pullrequestreview-361730169
* fix ineffectual assignment
* lite2: check that header exists in VerifyHeader
* extract function
Co-authored-by: Anton Kaliaev <anton.kalyaev@gmail.com>