You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1161 lines
31 KiB

lite2: light client with weak subjectivity (#3989) Refs #1771 ADR: https://github.com/tendermint/tendermint/blob/master/docs/architecture/adr-044-lite-client-with-weak-subjectivity.md ## Commits: * add Verifier and VerifyCommitTrusting * add two more checks make trustLevel an option * float32 for trustLevel * check newHeader time * started writing lite Client * unify Verify methods * ensure h2.Header.bfttime < h1.Header.bfttime + tp * move trust checks into Verify function * add more comments * more docs * started writing tests * unbonding period failures * tests are green * export ErrNewHeaderTooFarIntoFuture * make golangci happy * test for non-adjusted headers * more precision * providers and stores * VerifyHeader and VerifyHeaderAtHeight funcs * fix compile errors * remove lastVerifiedHeight, persist new trusted header * sequential verification * remove TrustedStore option * started writing tests for light client * cover basic cases for linear verification * bisection tests PASS * rename BisectingVerification to SkippingVerification * refactor the code * add TrustedHeader method * consolidate sequential verification tests * consolidate skipping verification tests * rename trustedVals to trustedNextVals * start writing docs * ValidateTrustLevel func and ErrOldHeaderExpired error * AutoClient and example tests * fix errors * update doc * remove ErrNewHeaderTooFarIntoFuture This check is unnecessary given existing a) ErrOldHeaderExpired b) h2.Time > now checks. * return an error if we're at more recent height * add comments * add LastSignedHeaderHeight method to Store I think it's fine if Store tracks last height * copy over proxy from old lite package * make TrustedHeader return latest if height=0 * modify LastSignedHeaderHeight to return an error if no headers exist * copy over proxy impl * refactor proxy and start http lite client * Tx and BlockchainInfo methods * Block method * commit method * code compiles again * lite client compiles * extract updateLiteClientIfNeededTo func * move final parts * add placeholder for tests * force usage of lite http client in proxy * comment out query tests for now * explicitly mention tp: trusting period * verify nextVals in VerifyHeader * refactor bisection * move the NextValidatorsHash check into updateTrustedHeaderAndVals + update the comment * add ConsensusParams method to RPC client * add ConsensusParams to rpc/mock/client * change trustLevel type to a new cmn.Fraction type + update SkippingVerification comment * stress out trustLevel is only used for non-adjusted headers * fixes after Fede's review Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com> * compare newHeader with a header from an alternative provider * save pivot header Refs https://github.com/tendermint/tendermint/pull/3989#discussion_r349122824 * check header can still be trusted in TrustedHeader Refs https://github.com/tendermint/tendermint/pull/3989#discussion_r349101424 * lite: update Validators and Block endpoints - Block no longer contains BlockMeta - Validators now accept two additional params: page and perPage * make linter happy
5 years ago
lite2: light client with weak subjectivity (#3989) Refs #1771 ADR: https://github.com/tendermint/tendermint/blob/master/docs/architecture/adr-044-lite-client-with-weak-subjectivity.md ## Commits: * add Verifier and VerifyCommitTrusting * add two more checks make trustLevel an option * float32 for trustLevel * check newHeader time * started writing lite Client * unify Verify methods * ensure h2.Header.bfttime < h1.Header.bfttime + tp * move trust checks into Verify function * add more comments * more docs * started writing tests * unbonding period failures * tests are green * export ErrNewHeaderTooFarIntoFuture * make golangci happy * test for non-adjusted headers * more precision * providers and stores * VerifyHeader and VerifyHeaderAtHeight funcs * fix compile errors * remove lastVerifiedHeight, persist new trusted header * sequential verification * remove TrustedStore option * started writing tests for light client * cover basic cases for linear verification * bisection tests PASS * rename BisectingVerification to SkippingVerification * refactor the code * add TrustedHeader method * consolidate sequential verification tests * consolidate skipping verification tests * rename trustedVals to trustedNextVals * start writing docs * ValidateTrustLevel func and ErrOldHeaderExpired error * AutoClient and example tests * fix errors * update doc * remove ErrNewHeaderTooFarIntoFuture This check is unnecessary given existing a) ErrOldHeaderExpired b) h2.Time > now checks. * return an error if we're at more recent height * add comments * add LastSignedHeaderHeight method to Store I think it's fine if Store tracks last height * copy over proxy from old lite package * make TrustedHeader return latest if height=0 * modify LastSignedHeaderHeight to return an error if no headers exist * copy over proxy impl * refactor proxy and start http lite client * Tx and BlockchainInfo methods * Block method * commit method * code compiles again * lite client compiles * extract updateLiteClientIfNeededTo func * move final parts * add placeholder for tests * force usage of lite http client in proxy * comment out query tests for now * explicitly mention tp: trusting period * verify nextVals in VerifyHeader * refactor bisection * move the NextValidatorsHash check into updateTrustedHeaderAndVals + update the comment * add ConsensusParams method to RPC client * add ConsensusParams to rpc/mock/client * change trustLevel type to a new cmn.Fraction type + update SkippingVerification comment * stress out trustLevel is only used for non-adjusted headers * fixes after Fede's review Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com> * compare newHeader with a header from an alternative provider * save pivot header Refs https://github.com/tendermint/tendermint/pull/3989#discussion_r349122824 * check header can still be trusted in TrustedHeader Refs https://github.com/tendermint/tendermint/pull/3989#discussion_r349101424 * lite: update Validators and Block endpoints - Block no longer contains BlockMeta - Validators now accept two additional params: page and perPage * make linter happy
5 years ago
lite2: light client with weak subjectivity (#3989) Refs #1771 ADR: https://github.com/tendermint/tendermint/blob/master/docs/architecture/adr-044-lite-client-with-weak-subjectivity.md ## Commits: * add Verifier and VerifyCommitTrusting * add two more checks make trustLevel an option * float32 for trustLevel * check newHeader time * started writing lite Client * unify Verify methods * ensure h2.Header.bfttime < h1.Header.bfttime + tp * move trust checks into Verify function * add more comments * more docs * started writing tests * unbonding period failures * tests are green * export ErrNewHeaderTooFarIntoFuture * make golangci happy * test for non-adjusted headers * more precision * providers and stores * VerifyHeader and VerifyHeaderAtHeight funcs * fix compile errors * remove lastVerifiedHeight, persist new trusted header * sequential verification * remove TrustedStore option * started writing tests for light client * cover basic cases for linear verification * bisection tests PASS * rename BisectingVerification to SkippingVerification * refactor the code * add TrustedHeader method * consolidate sequential verification tests * consolidate skipping verification tests * rename trustedVals to trustedNextVals * start writing docs * ValidateTrustLevel func and ErrOldHeaderExpired error * AutoClient and example tests * fix errors * update doc * remove ErrNewHeaderTooFarIntoFuture This check is unnecessary given existing a) ErrOldHeaderExpired b) h2.Time > now checks. * return an error if we're at more recent height * add comments * add LastSignedHeaderHeight method to Store I think it's fine if Store tracks last height * copy over proxy from old lite package * make TrustedHeader return latest if height=0 * modify LastSignedHeaderHeight to return an error if no headers exist * copy over proxy impl * refactor proxy and start http lite client * Tx and BlockchainInfo methods * Block method * commit method * code compiles again * lite client compiles * extract updateLiteClientIfNeededTo func * move final parts * add placeholder for tests * force usage of lite http client in proxy * comment out query tests for now * explicitly mention tp: trusting period * verify nextVals in VerifyHeader * refactor bisection * move the NextValidatorsHash check into updateTrustedHeaderAndVals + update the comment * add ConsensusParams method to RPC client * add ConsensusParams to rpc/mock/client * change trustLevel type to a new cmn.Fraction type + update SkippingVerification comment * stress out trustLevel is only used for non-adjusted headers * fixes after Fede's review Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com> * compare newHeader with a header from an alternative provider * save pivot header Refs https://github.com/tendermint/tendermint/pull/3989#discussion_r349122824 * check header can still be trusted in TrustedHeader Refs https://github.com/tendermint/tendermint/pull/3989#discussion_r349101424 * lite: update Validators and Block endpoints - Block no longer contains BlockMeta - Validators now accept two additional params: page and perPage * make linter happy
5 years ago
lite: follow up from #3989 (#4209) * rename adjusted to adjacent Refs https://github.com/tendermint/tendermint/pull/3989#discussion_r352140829 * rename ErrTooMuchChange to ErrNotEnoughVotingPowerSigned Refs https://github.com/tendermint/tendermint/pull/3989#discussion_r352142785 * verify commit is properly signed * remove no longer trusted headers * restore trustedHeader and trustedNextVals * check trustedHeader using options Refs https://github.com/tendermint/tendermint/pull/4209#issuecomment-562462165 * use correct var when checking if headers are adjacent in bisection func + replace TODO with a comment https://github.com/tendermint/tendermint/pull/3989#discussion_r352125455 * return header in VerifyHeaderAtHeight because that way we avoid DB call + add godoc comments + check if there are no headers yet in AutoClient https://github.com/tendermint/tendermint/pull/3989#pullrequestreview-315454506 * TestVerifyAdjacentHeaders: add 2 more test-cases + add TestVerifyReturnsErrorIfTrustLevelIsInvalid * lite: avoid overflow when parsing key in db store! * lite: rename AutoClient#Err to Errs * lite: add a test for AutoClient * lite: fix keyPattern and call itr.Next in db store * lite: add two tests for db store * lite: add TestClientRemovesNoLongerTrustedHeaders * lite: test Client#Cleanup * lite: test restoring trustedHeader https://github.com/tendermint/tendermint/pull/4209#issuecomment-562462165 * lite: comment out unused code in test_helpers * fix TestVerifyReturnsErrorIfTrustLevelIsInvalid after merge * change defaultRemoveNoLongerTrustedHeadersPeriod and add docs * write more doc * lite: uncomment testable examples * use stdlog.Fatal to stop AutoClient tests * make lll linter happy * separate errors for 2 cases - the validator set of a skipped header cannot be trusted, i.e. <1/3rd of h1 validator set has signed (new error, something like ErrNewValSetCantBeTrusted) - the validator set is trusted but < 2/3rds has signed (ErrNewHeaderCantBeTrusted) https://github.com/tendermint/tendermint/pull/4209#discussion_r360331253 * remove all headers (even the last one) that are outside of the trusting period. By doing this, we avoid checking the trustedHeader's hash in checkTrustedHeaderUsingOptions (case #1). https://github.com/tendermint/tendermint/pull/4209#discussion_r360332460 * explain restoreTrustedHeaderAndNextVals better https://github.com/tendermint/tendermint/pull/4209#discussion_r360602328 * add ConfirmationFunction option for optionally prompting for user input Y/n before removing headers Refs https://github.com/tendermint/tendermint/pull/4209#discussion_r360602945 * make cleaning optional https://github.com/tendermint/tendermint/pull/4209#discussion_r364838189 * return error when user refused to remove headers * check for double votes in VerifyCommitTrusting * leave only ErrNewValSetCantBeTrusted error to differenciate between h2Vals.VerifyCommit and h1NextVals.VerifyCommitTrusting * fix example tests * remove unnecessary if condition https://github.com/tendermint/tendermint/pull/4209#discussion_r365171847 It will be handled by the above switch. * verifyCommitBasic does not depend on vals Co-authored-by: Marko <marbar3778@yahoo.com>
4 years ago
lite2: light client with weak subjectivity (#3989) Refs #1771 ADR: https://github.com/tendermint/tendermint/blob/master/docs/architecture/adr-044-lite-client-with-weak-subjectivity.md ## Commits: * add Verifier and VerifyCommitTrusting * add two more checks make trustLevel an option * float32 for trustLevel * check newHeader time * started writing lite Client * unify Verify methods * ensure h2.Header.bfttime < h1.Header.bfttime + tp * move trust checks into Verify function * add more comments * more docs * started writing tests * unbonding period failures * tests are green * export ErrNewHeaderTooFarIntoFuture * make golangci happy * test for non-adjusted headers * more precision * providers and stores * VerifyHeader and VerifyHeaderAtHeight funcs * fix compile errors * remove lastVerifiedHeight, persist new trusted header * sequential verification * remove TrustedStore option * started writing tests for light client * cover basic cases for linear verification * bisection tests PASS * rename BisectingVerification to SkippingVerification * refactor the code * add TrustedHeader method * consolidate sequential verification tests * consolidate skipping verification tests * rename trustedVals to trustedNextVals * start writing docs * ValidateTrustLevel func and ErrOldHeaderExpired error * AutoClient and example tests * fix errors * update doc * remove ErrNewHeaderTooFarIntoFuture This check is unnecessary given existing a) ErrOldHeaderExpired b) h2.Time > now checks. * return an error if we're at more recent height * add comments * add LastSignedHeaderHeight method to Store I think it's fine if Store tracks last height * copy over proxy from old lite package * make TrustedHeader return latest if height=0 * modify LastSignedHeaderHeight to return an error if no headers exist * copy over proxy impl * refactor proxy and start http lite client * Tx and BlockchainInfo methods * Block method * commit method * code compiles again * lite client compiles * extract updateLiteClientIfNeededTo func * move final parts * add placeholder for tests * force usage of lite http client in proxy * comment out query tests for now * explicitly mention tp: trusting period * verify nextVals in VerifyHeader * refactor bisection * move the NextValidatorsHash check into updateTrustedHeaderAndVals + update the comment * add ConsensusParams method to RPC client * add ConsensusParams to rpc/mock/client * change trustLevel type to a new cmn.Fraction type + update SkippingVerification comment * stress out trustLevel is only used for non-adjusted headers * fixes after Fede's review Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com> * compare newHeader with a header from an alternative provider * save pivot header Refs https://github.com/tendermint/tendermint/pull/3989#discussion_r349122824 * check header can still be trusted in TrustedHeader Refs https://github.com/tendermint/tendermint/pull/3989#discussion_r349101424 * lite: update Validators and Block endpoints - Block no longer contains BlockMeta - Validators now accept two additional params: page and perPage * make linter happy
5 years ago
lite2: light client with weak subjectivity (#3989) Refs #1771 ADR: https://github.com/tendermint/tendermint/blob/master/docs/architecture/adr-044-lite-client-with-weak-subjectivity.md ## Commits: * add Verifier and VerifyCommitTrusting * add two more checks make trustLevel an option * float32 for trustLevel * check newHeader time * started writing lite Client * unify Verify methods * ensure h2.Header.bfttime < h1.Header.bfttime + tp * move trust checks into Verify function * add more comments * more docs * started writing tests * unbonding period failures * tests are green * export ErrNewHeaderTooFarIntoFuture * make golangci happy * test for non-adjusted headers * more precision * providers and stores * VerifyHeader and VerifyHeaderAtHeight funcs * fix compile errors * remove lastVerifiedHeight, persist new trusted header * sequential verification * remove TrustedStore option * started writing tests for light client * cover basic cases for linear verification * bisection tests PASS * rename BisectingVerification to SkippingVerification * refactor the code * add TrustedHeader method * consolidate sequential verification tests * consolidate skipping verification tests * rename trustedVals to trustedNextVals * start writing docs * ValidateTrustLevel func and ErrOldHeaderExpired error * AutoClient and example tests * fix errors * update doc * remove ErrNewHeaderTooFarIntoFuture This check is unnecessary given existing a) ErrOldHeaderExpired b) h2.Time > now checks. * return an error if we're at more recent height * add comments * add LastSignedHeaderHeight method to Store I think it's fine if Store tracks last height * copy over proxy from old lite package * make TrustedHeader return latest if height=0 * modify LastSignedHeaderHeight to return an error if no headers exist * copy over proxy impl * refactor proxy and start http lite client * Tx and BlockchainInfo methods * Block method * commit method * code compiles again * lite client compiles * extract updateLiteClientIfNeededTo func * move final parts * add placeholder for tests * force usage of lite http client in proxy * comment out query tests for now * explicitly mention tp: trusting period * verify nextVals in VerifyHeader * refactor bisection * move the NextValidatorsHash check into updateTrustedHeaderAndVals + update the comment * add ConsensusParams method to RPC client * add ConsensusParams to rpc/mock/client * change trustLevel type to a new cmn.Fraction type + update SkippingVerification comment * stress out trustLevel is only used for non-adjusted headers * fixes after Fede's review Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com> * compare newHeader with a header from an alternative provider * save pivot header Refs https://github.com/tendermint/tendermint/pull/3989#discussion_r349122824 * check header can still be trusted in TrustedHeader Refs https://github.com/tendermint/tendermint/pull/3989#discussion_r349101424 * lite: update Validators and Block endpoints - Block no longer contains BlockMeta - Validators now accept two additional params: page and perPage * make linter happy
5 years ago
lite2: light client with weak subjectivity (#3989) Refs #1771 ADR: https://github.com/tendermint/tendermint/blob/master/docs/architecture/adr-044-lite-client-with-weak-subjectivity.md ## Commits: * add Verifier and VerifyCommitTrusting * add two more checks make trustLevel an option * float32 for trustLevel * check newHeader time * started writing lite Client * unify Verify methods * ensure h2.Header.bfttime < h1.Header.bfttime + tp * move trust checks into Verify function * add more comments * more docs * started writing tests * unbonding period failures * tests are green * export ErrNewHeaderTooFarIntoFuture * make golangci happy * test for non-adjusted headers * more precision * providers and stores * VerifyHeader and VerifyHeaderAtHeight funcs * fix compile errors * remove lastVerifiedHeight, persist new trusted header * sequential verification * remove TrustedStore option * started writing tests for light client * cover basic cases for linear verification * bisection tests PASS * rename BisectingVerification to SkippingVerification * refactor the code * add TrustedHeader method * consolidate sequential verification tests * consolidate skipping verification tests * rename trustedVals to trustedNextVals * start writing docs * ValidateTrustLevel func and ErrOldHeaderExpired error * AutoClient and example tests * fix errors * update doc * remove ErrNewHeaderTooFarIntoFuture This check is unnecessary given existing a) ErrOldHeaderExpired b) h2.Time > now checks. * return an error if we're at more recent height * add comments * add LastSignedHeaderHeight method to Store I think it's fine if Store tracks last height * copy over proxy from old lite package * make TrustedHeader return latest if height=0 * modify LastSignedHeaderHeight to return an error if no headers exist * copy over proxy impl * refactor proxy and start http lite client * Tx and BlockchainInfo methods * Block method * commit method * code compiles again * lite client compiles * extract updateLiteClientIfNeededTo func * move final parts * add placeholder for tests * force usage of lite http client in proxy * comment out query tests for now * explicitly mention tp: trusting period * verify nextVals in VerifyHeader * refactor bisection * move the NextValidatorsHash check into updateTrustedHeaderAndVals + update the comment * add ConsensusParams method to RPC client * add ConsensusParams to rpc/mock/client * change trustLevel type to a new cmn.Fraction type + update SkippingVerification comment * stress out trustLevel is only used for non-adjusted headers * fixes after Fede's review Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com> * compare newHeader with a header from an alternative provider * save pivot header Refs https://github.com/tendermint/tendermint/pull/3989#discussion_r349122824 * check header can still be trusted in TrustedHeader Refs https://github.com/tendermint/tendermint/pull/3989#discussion_r349101424 * lite: update Validators and Block endpoints - Block no longer contains BlockMeta - Validators now accept two additional params: page and perPage * make linter happy
5 years ago
lite2: light client with weak subjectivity (#3989) Refs #1771 ADR: https://github.com/tendermint/tendermint/blob/master/docs/architecture/adr-044-lite-client-with-weak-subjectivity.md ## Commits: * add Verifier and VerifyCommitTrusting * add two more checks make trustLevel an option * float32 for trustLevel * check newHeader time * started writing lite Client * unify Verify methods * ensure h2.Header.bfttime < h1.Header.bfttime + tp * move trust checks into Verify function * add more comments * more docs * started writing tests * unbonding period failures * tests are green * export ErrNewHeaderTooFarIntoFuture * make golangci happy * test for non-adjusted headers * more precision * providers and stores * VerifyHeader and VerifyHeaderAtHeight funcs * fix compile errors * remove lastVerifiedHeight, persist new trusted header * sequential verification * remove TrustedStore option * started writing tests for light client * cover basic cases for linear verification * bisection tests PASS * rename BisectingVerification to SkippingVerification * refactor the code * add TrustedHeader method * consolidate sequential verification tests * consolidate skipping verification tests * rename trustedVals to trustedNextVals * start writing docs * ValidateTrustLevel func and ErrOldHeaderExpired error * AutoClient and example tests * fix errors * update doc * remove ErrNewHeaderTooFarIntoFuture This check is unnecessary given existing a) ErrOldHeaderExpired b) h2.Time > now checks. * return an error if we're at more recent height * add comments * add LastSignedHeaderHeight method to Store I think it's fine if Store tracks last height * copy over proxy from old lite package * make TrustedHeader return latest if height=0 * modify LastSignedHeaderHeight to return an error if no headers exist * copy over proxy impl * refactor proxy and start http lite client * Tx and BlockchainInfo methods * Block method * commit method * code compiles again * lite client compiles * extract updateLiteClientIfNeededTo func * move final parts * add placeholder for tests * force usage of lite http client in proxy * comment out query tests for now * explicitly mention tp: trusting period * verify nextVals in VerifyHeader * refactor bisection * move the NextValidatorsHash check into updateTrustedHeaderAndVals + update the comment * add ConsensusParams method to RPC client * add ConsensusParams to rpc/mock/client * change trustLevel type to a new cmn.Fraction type + update SkippingVerification comment * stress out trustLevel is only used for non-adjusted headers * fixes after Fede's review Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com> * compare newHeader with a header from an alternative provider * save pivot header Refs https://github.com/tendermint/tendermint/pull/3989#discussion_r349122824 * check header can still be trusted in TrustedHeader Refs https://github.com/tendermint/tendermint/pull/3989#discussion_r349101424 * lite: update Validators and Block endpoints - Block no longer contains BlockMeta - Validators now accept two additional params: page and perPage * make linter happy
5 years ago
lite2: light client with weak subjectivity (#3989) Refs #1771 ADR: https://github.com/tendermint/tendermint/blob/master/docs/architecture/adr-044-lite-client-with-weak-subjectivity.md ## Commits: * add Verifier and VerifyCommitTrusting * add two more checks make trustLevel an option * float32 for trustLevel * check newHeader time * started writing lite Client * unify Verify methods * ensure h2.Header.bfttime < h1.Header.bfttime + tp * move trust checks into Verify function * add more comments * more docs * started writing tests * unbonding period failures * tests are green * export ErrNewHeaderTooFarIntoFuture * make golangci happy * test for non-adjusted headers * more precision * providers and stores * VerifyHeader and VerifyHeaderAtHeight funcs * fix compile errors * remove lastVerifiedHeight, persist new trusted header * sequential verification * remove TrustedStore option * started writing tests for light client * cover basic cases for linear verification * bisection tests PASS * rename BisectingVerification to SkippingVerification * refactor the code * add TrustedHeader method * consolidate sequential verification tests * consolidate skipping verification tests * rename trustedVals to trustedNextVals * start writing docs * ValidateTrustLevel func and ErrOldHeaderExpired error * AutoClient and example tests * fix errors * update doc * remove ErrNewHeaderTooFarIntoFuture This check is unnecessary given existing a) ErrOldHeaderExpired b) h2.Time > now checks. * return an error if we're at more recent height * add comments * add LastSignedHeaderHeight method to Store I think it's fine if Store tracks last height * copy over proxy from old lite package * make TrustedHeader return latest if height=0 * modify LastSignedHeaderHeight to return an error if no headers exist * copy over proxy impl * refactor proxy and start http lite client * Tx and BlockchainInfo methods * Block method * commit method * code compiles again * lite client compiles * extract updateLiteClientIfNeededTo func * move final parts * add placeholder for tests * force usage of lite http client in proxy * comment out query tests for now * explicitly mention tp: trusting period * verify nextVals in VerifyHeader * refactor bisection * move the NextValidatorsHash check into updateTrustedHeaderAndVals + update the comment * add ConsensusParams method to RPC client * add ConsensusParams to rpc/mock/client * change trustLevel type to a new cmn.Fraction type + update SkippingVerification comment * stress out trustLevel is only used for non-adjusted headers * fixes after Fede's review Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com> * compare newHeader with a header from an alternative provider * save pivot header Refs https://github.com/tendermint/tendermint/pull/3989#discussion_r349122824 * check header can still be trusted in TrustedHeader Refs https://github.com/tendermint/tendermint/pull/3989#discussion_r349101424 * lite: update Validators and Block endpoints - Block no longer contains BlockMeta - Validators now accept two additional params: page and perPage * make linter happy
5 years ago
lite2: light client with weak subjectivity (#3989) Refs #1771 ADR: https://github.com/tendermint/tendermint/blob/master/docs/architecture/adr-044-lite-client-with-weak-subjectivity.md ## Commits: * add Verifier and VerifyCommitTrusting * add two more checks make trustLevel an option * float32 for trustLevel * check newHeader time * started writing lite Client * unify Verify methods * ensure h2.Header.bfttime < h1.Header.bfttime + tp * move trust checks into Verify function * add more comments * more docs * started writing tests * unbonding period failures * tests are green * export ErrNewHeaderTooFarIntoFuture * make golangci happy * test for non-adjusted headers * more precision * providers and stores * VerifyHeader and VerifyHeaderAtHeight funcs * fix compile errors * remove lastVerifiedHeight, persist new trusted header * sequential verification * remove TrustedStore option * started writing tests for light client * cover basic cases for linear verification * bisection tests PASS * rename BisectingVerification to SkippingVerification * refactor the code * add TrustedHeader method * consolidate sequential verification tests * consolidate skipping verification tests * rename trustedVals to trustedNextVals * start writing docs * ValidateTrustLevel func and ErrOldHeaderExpired error * AutoClient and example tests * fix errors * update doc * remove ErrNewHeaderTooFarIntoFuture This check is unnecessary given existing a) ErrOldHeaderExpired b) h2.Time > now checks. * return an error if we're at more recent height * add comments * add LastSignedHeaderHeight method to Store I think it's fine if Store tracks last height * copy over proxy from old lite package * make TrustedHeader return latest if height=0 * modify LastSignedHeaderHeight to return an error if no headers exist * copy over proxy impl * refactor proxy and start http lite client * Tx and BlockchainInfo methods * Block method * commit method * code compiles again * lite client compiles * extract updateLiteClientIfNeededTo func * move final parts * add placeholder for tests * force usage of lite http client in proxy * comment out query tests for now * explicitly mention tp: trusting period * verify nextVals in VerifyHeader * refactor bisection * move the NextValidatorsHash check into updateTrustedHeaderAndVals + update the comment * add ConsensusParams method to RPC client * add ConsensusParams to rpc/mock/client * change trustLevel type to a new cmn.Fraction type + update SkippingVerification comment * stress out trustLevel is only used for non-adjusted headers * fixes after Fede's review Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com> * compare newHeader with a header from an alternative provider * save pivot header Refs https://github.com/tendermint/tendermint/pull/3989#discussion_r349122824 * check header can still be trusted in TrustedHeader Refs https://github.com/tendermint/tendermint/pull/3989#discussion_r349101424 * lite: update Validators and Block endpoints - Block no longer contains BlockMeta - Validators now accept two additional params: page and perPage * make linter happy
5 years ago
lite2: light client with weak subjectivity (#3989) Refs #1771 ADR: https://github.com/tendermint/tendermint/blob/master/docs/architecture/adr-044-lite-client-with-weak-subjectivity.md ## Commits: * add Verifier and VerifyCommitTrusting * add two more checks make trustLevel an option * float32 for trustLevel * check newHeader time * started writing lite Client * unify Verify methods * ensure h2.Header.bfttime < h1.Header.bfttime + tp * move trust checks into Verify function * add more comments * more docs * started writing tests * unbonding period failures * tests are green * export ErrNewHeaderTooFarIntoFuture * make golangci happy * test for non-adjusted headers * more precision * providers and stores * VerifyHeader and VerifyHeaderAtHeight funcs * fix compile errors * remove lastVerifiedHeight, persist new trusted header * sequential verification * remove TrustedStore option * started writing tests for light client * cover basic cases for linear verification * bisection tests PASS * rename BisectingVerification to SkippingVerification * refactor the code * add TrustedHeader method * consolidate sequential verification tests * consolidate skipping verification tests * rename trustedVals to trustedNextVals * start writing docs * ValidateTrustLevel func and ErrOldHeaderExpired error * AutoClient and example tests * fix errors * update doc * remove ErrNewHeaderTooFarIntoFuture This check is unnecessary given existing a) ErrOldHeaderExpired b) h2.Time > now checks. * return an error if we're at more recent height * add comments * add LastSignedHeaderHeight method to Store I think it's fine if Store tracks last height * copy over proxy from old lite package * make TrustedHeader return latest if height=0 * modify LastSignedHeaderHeight to return an error if no headers exist * copy over proxy impl * refactor proxy and start http lite client * Tx and BlockchainInfo methods * Block method * commit method * code compiles again * lite client compiles * extract updateLiteClientIfNeededTo func * move final parts * add placeholder for tests * force usage of lite http client in proxy * comment out query tests for now * explicitly mention tp: trusting period * verify nextVals in VerifyHeader * refactor bisection * move the NextValidatorsHash check into updateTrustedHeaderAndVals + update the comment * add ConsensusParams method to RPC client * add ConsensusParams to rpc/mock/client * change trustLevel type to a new cmn.Fraction type + update SkippingVerification comment * stress out trustLevel is only used for non-adjusted headers * fixes after Fede's review Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com> * compare newHeader with a header from an alternative provider * save pivot header Refs https://github.com/tendermint/tendermint/pull/3989#discussion_r349122824 * check header can still be trusted in TrustedHeader Refs https://github.com/tendermint/tendermint/pull/3989#discussion_r349101424 * lite: update Validators and Block endpoints - Block no longer contains BlockMeta - Validators now accept two additional params: page and perPage * make linter happy
5 years ago
lite2: light client with weak subjectivity (#3989) Refs #1771 ADR: https://github.com/tendermint/tendermint/blob/master/docs/architecture/adr-044-lite-client-with-weak-subjectivity.md ## Commits: * add Verifier and VerifyCommitTrusting * add two more checks make trustLevel an option * float32 for trustLevel * check newHeader time * started writing lite Client * unify Verify methods * ensure h2.Header.bfttime < h1.Header.bfttime + tp * move trust checks into Verify function * add more comments * more docs * started writing tests * unbonding period failures * tests are green * export ErrNewHeaderTooFarIntoFuture * make golangci happy * test for non-adjusted headers * more precision * providers and stores * VerifyHeader and VerifyHeaderAtHeight funcs * fix compile errors * remove lastVerifiedHeight, persist new trusted header * sequential verification * remove TrustedStore option * started writing tests for light client * cover basic cases for linear verification * bisection tests PASS * rename BisectingVerification to SkippingVerification * refactor the code * add TrustedHeader method * consolidate sequential verification tests * consolidate skipping verification tests * rename trustedVals to trustedNextVals * start writing docs * ValidateTrustLevel func and ErrOldHeaderExpired error * AutoClient and example tests * fix errors * update doc * remove ErrNewHeaderTooFarIntoFuture This check is unnecessary given existing a) ErrOldHeaderExpired b) h2.Time > now checks. * return an error if we're at more recent height * add comments * add LastSignedHeaderHeight method to Store I think it's fine if Store tracks last height * copy over proxy from old lite package * make TrustedHeader return latest if height=0 * modify LastSignedHeaderHeight to return an error if no headers exist * copy over proxy impl * refactor proxy and start http lite client * Tx and BlockchainInfo methods * Block method * commit method * code compiles again * lite client compiles * extract updateLiteClientIfNeededTo func * move final parts * add placeholder for tests * force usage of lite http client in proxy * comment out query tests for now * explicitly mention tp: trusting period * verify nextVals in VerifyHeader * refactor bisection * move the NextValidatorsHash check into updateTrustedHeaderAndVals + update the comment * add ConsensusParams method to RPC client * add ConsensusParams to rpc/mock/client * change trustLevel type to a new cmn.Fraction type + update SkippingVerification comment * stress out trustLevel is only used for non-adjusted headers * fixes after Fede's review Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com> * compare newHeader with a header from an alternative provider * save pivot header Refs https://github.com/tendermint/tendermint/pull/3989#discussion_r349122824 * check header can still be trusted in TrustedHeader Refs https://github.com/tendermint/tendermint/pull/3989#discussion_r349101424 * lite: update Validators and Block endpoints - Block no longer contains BlockMeta - Validators now accept two additional params: page and perPage * make linter happy
5 years ago
lite2: light client with weak subjectivity (#3989) Refs #1771 ADR: https://github.com/tendermint/tendermint/blob/master/docs/architecture/adr-044-lite-client-with-weak-subjectivity.md ## Commits: * add Verifier and VerifyCommitTrusting * add two more checks make trustLevel an option * float32 for trustLevel * check newHeader time * started writing lite Client * unify Verify methods * ensure h2.Header.bfttime < h1.Header.bfttime + tp * move trust checks into Verify function * add more comments * more docs * started writing tests * unbonding period failures * tests are green * export ErrNewHeaderTooFarIntoFuture * make golangci happy * test for non-adjusted headers * more precision * providers and stores * VerifyHeader and VerifyHeaderAtHeight funcs * fix compile errors * remove lastVerifiedHeight, persist new trusted header * sequential verification * remove TrustedStore option * started writing tests for light client * cover basic cases for linear verification * bisection tests PASS * rename BisectingVerification to SkippingVerification * refactor the code * add TrustedHeader method * consolidate sequential verification tests * consolidate skipping verification tests * rename trustedVals to trustedNextVals * start writing docs * ValidateTrustLevel func and ErrOldHeaderExpired error * AutoClient and example tests * fix errors * update doc * remove ErrNewHeaderTooFarIntoFuture This check is unnecessary given existing a) ErrOldHeaderExpired b) h2.Time > now checks. * return an error if we're at more recent height * add comments * add LastSignedHeaderHeight method to Store I think it's fine if Store tracks last height * copy over proxy from old lite package * make TrustedHeader return latest if height=0 * modify LastSignedHeaderHeight to return an error if no headers exist * copy over proxy impl * refactor proxy and start http lite client * Tx and BlockchainInfo methods * Block method * commit method * code compiles again * lite client compiles * extract updateLiteClientIfNeededTo func * move final parts * add placeholder for tests * force usage of lite http client in proxy * comment out query tests for now * explicitly mention tp: trusting period * verify nextVals in VerifyHeader * refactor bisection * move the NextValidatorsHash check into updateTrustedHeaderAndVals + update the comment * add ConsensusParams method to RPC client * add ConsensusParams to rpc/mock/client * change trustLevel type to a new cmn.Fraction type + update SkippingVerification comment * stress out trustLevel is only used for non-adjusted headers * fixes after Fede's review Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com> * compare newHeader with a header from an alternative provider * save pivot header Refs https://github.com/tendermint/tendermint/pull/3989#discussion_r349122824 * check header can still be trusted in TrustedHeader Refs https://github.com/tendermint/tendermint/pull/3989#discussion_r349101424 * lite: update Validators and Block endpoints - Block no longer contains BlockMeta - Validators now accept two additional params: page and perPage * make linter happy
5 years ago
lite2: light client with weak subjectivity (#3989) Refs #1771 ADR: https://github.com/tendermint/tendermint/blob/master/docs/architecture/adr-044-lite-client-with-weak-subjectivity.md ## Commits: * add Verifier and VerifyCommitTrusting * add two more checks make trustLevel an option * float32 for trustLevel * check newHeader time * started writing lite Client * unify Verify methods * ensure h2.Header.bfttime < h1.Header.bfttime + tp * move trust checks into Verify function * add more comments * more docs * started writing tests * unbonding period failures * tests are green * export ErrNewHeaderTooFarIntoFuture * make golangci happy * test for non-adjusted headers * more precision * providers and stores * VerifyHeader and VerifyHeaderAtHeight funcs * fix compile errors * remove lastVerifiedHeight, persist new trusted header * sequential verification * remove TrustedStore option * started writing tests for light client * cover basic cases for linear verification * bisection tests PASS * rename BisectingVerification to SkippingVerification * refactor the code * add TrustedHeader method * consolidate sequential verification tests * consolidate skipping verification tests * rename trustedVals to trustedNextVals * start writing docs * ValidateTrustLevel func and ErrOldHeaderExpired error * AutoClient and example tests * fix errors * update doc * remove ErrNewHeaderTooFarIntoFuture This check is unnecessary given existing a) ErrOldHeaderExpired b) h2.Time > now checks. * return an error if we're at more recent height * add comments * add LastSignedHeaderHeight method to Store I think it's fine if Store tracks last height * copy over proxy from old lite package * make TrustedHeader return latest if height=0 * modify LastSignedHeaderHeight to return an error if no headers exist * copy over proxy impl * refactor proxy and start http lite client * Tx and BlockchainInfo methods * Block method * commit method * code compiles again * lite client compiles * extract updateLiteClientIfNeededTo func * move final parts * add placeholder for tests * force usage of lite http client in proxy * comment out query tests for now * explicitly mention tp: trusting period * verify nextVals in VerifyHeader * refactor bisection * move the NextValidatorsHash check into updateTrustedHeaderAndVals + update the comment * add ConsensusParams method to RPC client * add ConsensusParams to rpc/mock/client * change trustLevel type to a new cmn.Fraction type + update SkippingVerification comment * stress out trustLevel is only used for non-adjusted headers * fixes after Fede's review Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com> * compare newHeader with a header from an alternative provider * save pivot header Refs https://github.com/tendermint/tendermint/pull/3989#discussion_r349122824 * check header can still be trusted in TrustedHeader Refs https://github.com/tendermint/tendermint/pull/3989#discussion_r349101424 * lite: update Validators and Block endpoints - Block no longer contains BlockMeta - Validators now accept two additional params: page and perPage * make linter happy
5 years ago
lite: follow up from #3989 (#4209) * rename adjusted to adjacent Refs https://github.com/tendermint/tendermint/pull/3989#discussion_r352140829 * rename ErrTooMuchChange to ErrNotEnoughVotingPowerSigned Refs https://github.com/tendermint/tendermint/pull/3989#discussion_r352142785 * verify commit is properly signed * remove no longer trusted headers * restore trustedHeader and trustedNextVals * check trustedHeader using options Refs https://github.com/tendermint/tendermint/pull/4209#issuecomment-562462165 * use correct var when checking if headers are adjacent in bisection func + replace TODO with a comment https://github.com/tendermint/tendermint/pull/3989#discussion_r352125455 * return header in VerifyHeaderAtHeight because that way we avoid DB call + add godoc comments + check if there are no headers yet in AutoClient https://github.com/tendermint/tendermint/pull/3989#pullrequestreview-315454506 * TestVerifyAdjacentHeaders: add 2 more test-cases + add TestVerifyReturnsErrorIfTrustLevelIsInvalid * lite: avoid overflow when parsing key in db store! * lite: rename AutoClient#Err to Errs * lite: add a test for AutoClient * lite: fix keyPattern and call itr.Next in db store * lite: add two tests for db store * lite: add TestClientRemovesNoLongerTrustedHeaders * lite: test Client#Cleanup * lite: test restoring trustedHeader https://github.com/tendermint/tendermint/pull/4209#issuecomment-562462165 * lite: comment out unused code in test_helpers * fix TestVerifyReturnsErrorIfTrustLevelIsInvalid after merge * change defaultRemoveNoLongerTrustedHeadersPeriod and add docs * write more doc * lite: uncomment testable examples * use stdlog.Fatal to stop AutoClient tests * make lll linter happy * separate errors for 2 cases - the validator set of a skipped header cannot be trusted, i.e. <1/3rd of h1 validator set has signed (new error, something like ErrNewValSetCantBeTrusted) - the validator set is trusted but < 2/3rds has signed (ErrNewHeaderCantBeTrusted) https://github.com/tendermint/tendermint/pull/4209#discussion_r360331253 * remove all headers (even the last one) that are outside of the trusting period. By doing this, we avoid checking the trustedHeader's hash in checkTrustedHeaderUsingOptions (case #1). https://github.com/tendermint/tendermint/pull/4209#discussion_r360332460 * explain restoreTrustedHeaderAndNextVals better https://github.com/tendermint/tendermint/pull/4209#discussion_r360602328 * add ConfirmationFunction option for optionally prompting for user input Y/n before removing headers Refs https://github.com/tendermint/tendermint/pull/4209#discussion_r360602945 * make cleaning optional https://github.com/tendermint/tendermint/pull/4209#discussion_r364838189 * return error when user refused to remove headers * check for double votes in VerifyCommitTrusting * leave only ErrNewValSetCantBeTrusted error to differenciate between h2Vals.VerifyCommit and h1NextVals.VerifyCommitTrusting * fix example tests * remove unnecessary if condition https://github.com/tendermint/tendermint/pull/4209#discussion_r365171847 It will be handled by the above switch. * verifyCommitBasic does not depend on vals Co-authored-by: Marko <marbar3778@yahoo.com>
4 years ago
lite: follow up from #3989 (#4209) * rename adjusted to adjacent Refs https://github.com/tendermint/tendermint/pull/3989#discussion_r352140829 * rename ErrTooMuchChange to ErrNotEnoughVotingPowerSigned Refs https://github.com/tendermint/tendermint/pull/3989#discussion_r352142785 * verify commit is properly signed * remove no longer trusted headers * restore trustedHeader and trustedNextVals * check trustedHeader using options Refs https://github.com/tendermint/tendermint/pull/4209#issuecomment-562462165 * use correct var when checking if headers are adjacent in bisection func + replace TODO with a comment https://github.com/tendermint/tendermint/pull/3989#discussion_r352125455 * return header in VerifyHeaderAtHeight because that way we avoid DB call + add godoc comments + check if there are no headers yet in AutoClient https://github.com/tendermint/tendermint/pull/3989#pullrequestreview-315454506 * TestVerifyAdjacentHeaders: add 2 more test-cases + add TestVerifyReturnsErrorIfTrustLevelIsInvalid * lite: avoid overflow when parsing key in db store! * lite: rename AutoClient#Err to Errs * lite: add a test for AutoClient * lite: fix keyPattern and call itr.Next in db store * lite: add two tests for db store * lite: add TestClientRemovesNoLongerTrustedHeaders * lite: test Client#Cleanup * lite: test restoring trustedHeader https://github.com/tendermint/tendermint/pull/4209#issuecomment-562462165 * lite: comment out unused code in test_helpers * fix TestVerifyReturnsErrorIfTrustLevelIsInvalid after merge * change defaultRemoveNoLongerTrustedHeadersPeriod and add docs * write more doc * lite: uncomment testable examples * use stdlog.Fatal to stop AutoClient tests * make lll linter happy * separate errors for 2 cases - the validator set of a skipped header cannot be trusted, i.e. <1/3rd of h1 validator set has signed (new error, something like ErrNewValSetCantBeTrusted) - the validator set is trusted but < 2/3rds has signed (ErrNewHeaderCantBeTrusted) https://github.com/tendermint/tendermint/pull/4209#discussion_r360331253 * remove all headers (even the last one) that are outside of the trusting period. By doing this, we avoid checking the trustedHeader's hash in checkTrustedHeaderUsingOptions (case #1). https://github.com/tendermint/tendermint/pull/4209#discussion_r360332460 * explain restoreTrustedHeaderAndNextVals better https://github.com/tendermint/tendermint/pull/4209#discussion_r360602328 * add ConfirmationFunction option for optionally prompting for user input Y/n before removing headers Refs https://github.com/tendermint/tendermint/pull/4209#discussion_r360602945 * make cleaning optional https://github.com/tendermint/tendermint/pull/4209#discussion_r364838189 * return error when user refused to remove headers * check for double votes in VerifyCommitTrusting * leave only ErrNewValSetCantBeTrusted error to differenciate between h2Vals.VerifyCommit and h1NextVals.VerifyCommitTrusting * fix example tests * remove unnecessary if condition https://github.com/tendermint/tendermint/pull/4209#discussion_r365171847 It will be handled by the above switch. * verifyCommitBasic does not depend on vals Co-authored-by: Marko <marbar3778@yahoo.com>
4 years ago
lite: follow up from #3989 (#4209) * rename adjusted to adjacent Refs https://github.com/tendermint/tendermint/pull/3989#discussion_r352140829 * rename ErrTooMuchChange to ErrNotEnoughVotingPowerSigned Refs https://github.com/tendermint/tendermint/pull/3989#discussion_r352142785 * verify commit is properly signed * remove no longer trusted headers * restore trustedHeader and trustedNextVals * check trustedHeader using options Refs https://github.com/tendermint/tendermint/pull/4209#issuecomment-562462165 * use correct var when checking if headers are adjacent in bisection func + replace TODO with a comment https://github.com/tendermint/tendermint/pull/3989#discussion_r352125455 * return header in VerifyHeaderAtHeight because that way we avoid DB call + add godoc comments + check if there are no headers yet in AutoClient https://github.com/tendermint/tendermint/pull/3989#pullrequestreview-315454506 * TestVerifyAdjacentHeaders: add 2 more test-cases + add TestVerifyReturnsErrorIfTrustLevelIsInvalid * lite: avoid overflow when parsing key in db store! * lite: rename AutoClient#Err to Errs * lite: add a test for AutoClient * lite: fix keyPattern and call itr.Next in db store * lite: add two tests for db store * lite: add TestClientRemovesNoLongerTrustedHeaders * lite: test Client#Cleanup * lite: test restoring trustedHeader https://github.com/tendermint/tendermint/pull/4209#issuecomment-562462165 * lite: comment out unused code in test_helpers * fix TestVerifyReturnsErrorIfTrustLevelIsInvalid after merge * change defaultRemoveNoLongerTrustedHeadersPeriod and add docs * write more doc * lite: uncomment testable examples * use stdlog.Fatal to stop AutoClient tests * make lll linter happy * separate errors for 2 cases - the validator set of a skipped header cannot be trusted, i.e. <1/3rd of h1 validator set has signed (new error, something like ErrNewValSetCantBeTrusted) - the validator set is trusted but < 2/3rds has signed (ErrNewHeaderCantBeTrusted) https://github.com/tendermint/tendermint/pull/4209#discussion_r360331253 * remove all headers (even the last one) that are outside of the trusting period. By doing this, we avoid checking the trustedHeader's hash in checkTrustedHeaderUsingOptions (case #1). https://github.com/tendermint/tendermint/pull/4209#discussion_r360332460 * explain restoreTrustedHeaderAndNextVals better https://github.com/tendermint/tendermint/pull/4209#discussion_r360602328 * add ConfirmationFunction option for optionally prompting for user input Y/n before removing headers Refs https://github.com/tendermint/tendermint/pull/4209#discussion_r360602945 * make cleaning optional https://github.com/tendermint/tendermint/pull/4209#discussion_r364838189 * return error when user refused to remove headers * check for double votes in VerifyCommitTrusting * leave only ErrNewValSetCantBeTrusted error to differenciate between h2Vals.VerifyCommit and h1NextVals.VerifyCommitTrusting * fix example tests * remove unnecessary if condition https://github.com/tendermint/tendermint/pull/4209#discussion_r365171847 It will be handled by the above switch. * verifyCommitBasic does not depend on vals Co-authored-by: Marko <marbar3778@yahoo.com>
4 years ago
lite: follow up from #3989 (#4209) * rename adjusted to adjacent Refs https://github.com/tendermint/tendermint/pull/3989#discussion_r352140829 * rename ErrTooMuchChange to ErrNotEnoughVotingPowerSigned Refs https://github.com/tendermint/tendermint/pull/3989#discussion_r352142785 * verify commit is properly signed * remove no longer trusted headers * restore trustedHeader and trustedNextVals * check trustedHeader using options Refs https://github.com/tendermint/tendermint/pull/4209#issuecomment-562462165 * use correct var when checking if headers are adjacent in bisection func + replace TODO with a comment https://github.com/tendermint/tendermint/pull/3989#discussion_r352125455 * return header in VerifyHeaderAtHeight because that way we avoid DB call + add godoc comments + check if there are no headers yet in AutoClient https://github.com/tendermint/tendermint/pull/3989#pullrequestreview-315454506 * TestVerifyAdjacentHeaders: add 2 more test-cases + add TestVerifyReturnsErrorIfTrustLevelIsInvalid * lite: avoid overflow when parsing key in db store! * lite: rename AutoClient#Err to Errs * lite: add a test for AutoClient * lite: fix keyPattern and call itr.Next in db store * lite: add two tests for db store * lite: add TestClientRemovesNoLongerTrustedHeaders * lite: test Client#Cleanup * lite: test restoring trustedHeader https://github.com/tendermint/tendermint/pull/4209#issuecomment-562462165 * lite: comment out unused code in test_helpers * fix TestVerifyReturnsErrorIfTrustLevelIsInvalid after merge * change defaultRemoveNoLongerTrustedHeadersPeriod and add docs * write more doc * lite: uncomment testable examples * use stdlog.Fatal to stop AutoClient tests * make lll linter happy * separate errors for 2 cases - the validator set of a skipped header cannot be trusted, i.e. <1/3rd of h1 validator set has signed (new error, something like ErrNewValSetCantBeTrusted) - the validator set is trusted but < 2/3rds has signed (ErrNewHeaderCantBeTrusted) https://github.com/tendermint/tendermint/pull/4209#discussion_r360331253 * remove all headers (even the last one) that are outside of the trusting period. By doing this, we avoid checking the trustedHeader's hash in checkTrustedHeaderUsingOptions (case #1). https://github.com/tendermint/tendermint/pull/4209#discussion_r360332460 * explain restoreTrustedHeaderAndNextVals better https://github.com/tendermint/tendermint/pull/4209#discussion_r360602328 * add ConfirmationFunction option for optionally prompting for user input Y/n before removing headers Refs https://github.com/tendermint/tendermint/pull/4209#discussion_r360602945 * make cleaning optional https://github.com/tendermint/tendermint/pull/4209#discussion_r364838189 * return error when user refused to remove headers * check for double votes in VerifyCommitTrusting * leave only ErrNewValSetCantBeTrusted error to differenciate between h2Vals.VerifyCommit and h1NextVals.VerifyCommitTrusting * fix example tests * remove unnecessary if condition https://github.com/tendermint/tendermint/pull/4209#discussion_r365171847 It will be handled by the above switch. * verifyCommitBasic does not depend on vals Co-authored-by: Marko <marbar3778@yahoo.com>
4 years ago
lite: follow up from #3989 (#4209) * rename adjusted to adjacent Refs https://github.com/tendermint/tendermint/pull/3989#discussion_r352140829 * rename ErrTooMuchChange to ErrNotEnoughVotingPowerSigned Refs https://github.com/tendermint/tendermint/pull/3989#discussion_r352142785 * verify commit is properly signed * remove no longer trusted headers * restore trustedHeader and trustedNextVals * check trustedHeader using options Refs https://github.com/tendermint/tendermint/pull/4209#issuecomment-562462165 * use correct var when checking if headers are adjacent in bisection func + replace TODO with a comment https://github.com/tendermint/tendermint/pull/3989#discussion_r352125455 * return header in VerifyHeaderAtHeight because that way we avoid DB call + add godoc comments + check if there are no headers yet in AutoClient https://github.com/tendermint/tendermint/pull/3989#pullrequestreview-315454506 * TestVerifyAdjacentHeaders: add 2 more test-cases + add TestVerifyReturnsErrorIfTrustLevelIsInvalid * lite: avoid overflow when parsing key in db store! * lite: rename AutoClient#Err to Errs * lite: add a test for AutoClient * lite: fix keyPattern and call itr.Next in db store * lite: add two tests for db store * lite: add TestClientRemovesNoLongerTrustedHeaders * lite: test Client#Cleanup * lite: test restoring trustedHeader https://github.com/tendermint/tendermint/pull/4209#issuecomment-562462165 * lite: comment out unused code in test_helpers * fix TestVerifyReturnsErrorIfTrustLevelIsInvalid after merge * change defaultRemoveNoLongerTrustedHeadersPeriod and add docs * write more doc * lite: uncomment testable examples * use stdlog.Fatal to stop AutoClient tests * make lll linter happy * separate errors for 2 cases - the validator set of a skipped header cannot be trusted, i.e. <1/3rd of h1 validator set has signed (new error, something like ErrNewValSetCantBeTrusted) - the validator set is trusted but < 2/3rds has signed (ErrNewHeaderCantBeTrusted) https://github.com/tendermint/tendermint/pull/4209#discussion_r360331253 * remove all headers (even the last one) that are outside of the trusting period. By doing this, we avoid checking the trustedHeader's hash in checkTrustedHeaderUsingOptions (case #1). https://github.com/tendermint/tendermint/pull/4209#discussion_r360332460 * explain restoreTrustedHeaderAndNextVals better https://github.com/tendermint/tendermint/pull/4209#discussion_r360602328 * add ConfirmationFunction option for optionally prompting for user input Y/n before removing headers Refs https://github.com/tendermint/tendermint/pull/4209#discussion_r360602945 * make cleaning optional https://github.com/tendermint/tendermint/pull/4209#discussion_r364838189 * return error when user refused to remove headers * check for double votes in VerifyCommitTrusting * leave only ErrNewValSetCantBeTrusted error to differenciate between h2Vals.VerifyCommit and h1NextVals.VerifyCommitTrusting * fix example tests * remove unnecessary if condition https://github.com/tendermint/tendermint/pull/4209#discussion_r365171847 It will be handled by the above switch. * verifyCommitBasic does not depend on vals Co-authored-by: Marko <marbar3778@yahoo.com>
4 years ago
lite: follow up from #3989 (#4209) * rename adjusted to adjacent Refs https://github.com/tendermint/tendermint/pull/3989#discussion_r352140829 * rename ErrTooMuchChange to ErrNotEnoughVotingPowerSigned Refs https://github.com/tendermint/tendermint/pull/3989#discussion_r352142785 * verify commit is properly signed * remove no longer trusted headers * restore trustedHeader and trustedNextVals * check trustedHeader using options Refs https://github.com/tendermint/tendermint/pull/4209#issuecomment-562462165 * use correct var when checking if headers are adjacent in bisection func + replace TODO with a comment https://github.com/tendermint/tendermint/pull/3989#discussion_r352125455 * return header in VerifyHeaderAtHeight because that way we avoid DB call + add godoc comments + check if there are no headers yet in AutoClient https://github.com/tendermint/tendermint/pull/3989#pullrequestreview-315454506 * TestVerifyAdjacentHeaders: add 2 more test-cases + add TestVerifyReturnsErrorIfTrustLevelIsInvalid * lite: avoid overflow when parsing key in db store! * lite: rename AutoClient#Err to Errs * lite: add a test for AutoClient * lite: fix keyPattern and call itr.Next in db store * lite: add two tests for db store * lite: add TestClientRemovesNoLongerTrustedHeaders * lite: test Client#Cleanup * lite: test restoring trustedHeader https://github.com/tendermint/tendermint/pull/4209#issuecomment-562462165 * lite: comment out unused code in test_helpers * fix TestVerifyReturnsErrorIfTrustLevelIsInvalid after merge * change defaultRemoveNoLongerTrustedHeadersPeriod and add docs * write more doc * lite: uncomment testable examples * use stdlog.Fatal to stop AutoClient tests * make lll linter happy * separate errors for 2 cases - the validator set of a skipped header cannot be trusted, i.e. <1/3rd of h1 validator set has signed (new error, something like ErrNewValSetCantBeTrusted) - the validator set is trusted but < 2/3rds has signed (ErrNewHeaderCantBeTrusted) https://github.com/tendermint/tendermint/pull/4209#discussion_r360331253 * remove all headers (even the last one) that are outside of the trusting period. By doing this, we avoid checking the trustedHeader's hash in checkTrustedHeaderUsingOptions (case #1). https://github.com/tendermint/tendermint/pull/4209#discussion_r360332460 * explain restoreTrustedHeaderAndNextVals better https://github.com/tendermint/tendermint/pull/4209#discussion_r360602328 * add ConfirmationFunction option for optionally prompting for user input Y/n before removing headers Refs https://github.com/tendermint/tendermint/pull/4209#discussion_r360602945 * make cleaning optional https://github.com/tendermint/tendermint/pull/4209#discussion_r364838189 * return error when user refused to remove headers * check for double votes in VerifyCommitTrusting * leave only ErrNewValSetCantBeTrusted error to differenciate between h2Vals.VerifyCommit and h1NextVals.VerifyCommitTrusting * fix example tests * remove unnecessary if condition https://github.com/tendermint/tendermint/pull/4209#discussion_r365171847 It will be handled by the above switch. * verifyCommitBasic does not depend on vals Co-authored-by: Marko <marbar3778@yahoo.com>
4 years ago
lite: follow up from #3989 (#4209) * rename adjusted to adjacent Refs https://github.com/tendermint/tendermint/pull/3989#discussion_r352140829 * rename ErrTooMuchChange to ErrNotEnoughVotingPowerSigned Refs https://github.com/tendermint/tendermint/pull/3989#discussion_r352142785 * verify commit is properly signed * remove no longer trusted headers * restore trustedHeader and trustedNextVals * check trustedHeader using options Refs https://github.com/tendermint/tendermint/pull/4209#issuecomment-562462165 * use correct var when checking if headers are adjacent in bisection func + replace TODO with a comment https://github.com/tendermint/tendermint/pull/3989#discussion_r352125455 * return header in VerifyHeaderAtHeight because that way we avoid DB call + add godoc comments + check if there are no headers yet in AutoClient https://github.com/tendermint/tendermint/pull/3989#pullrequestreview-315454506 * TestVerifyAdjacentHeaders: add 2 more test-cases + add TestVerifyReturnsErrorIfTrustLevelIsInvalid * lite: avoid overflow when parsing key in db store! * lite: rename AutoClient#Err to Errs * lite: add a test for AutoClient * lite: fix keyPattern and call itr.Next in db store * lite: add two tests for db store * lite: add TestClientRemovesNoLongerTrustedHeaders * lite: test Client#Cleanup * lite: test restoring trustedHeader https://github.com/tendermint/tendermint/pull/4209#issuecomment-562462165 * lite: comment out unused code in test_helpers * fix TestVerifyReturnsErrorIfTrustLevelIsInvalid after merge * change defaultRemoveNoLongerTrustedHeadersPeriod and add docs * write more doc * lite: uncomment testable examples * use stdlog.Fatal to stop AutoClient tests * make lll linter happy * separate errors for 2 cases - the validator set of a skipped header cannot be trusted, i.e. <1/3rd of h1 validator set has signed (new error, something like ErrNewValSetCantBeTrusted) - the validator set is trusted but < 2/3rds has signed (ErrNewHeaderCantBeTrusted) https://github.com/tendermint/tendermint/pull/4209#discussion_r360331253 * remove all headers (even the last one) that are outside of the trusting period. By doing this, we avoid checking the trustedHeader's hash in checkTrustedHeaderUsingOptions (case #1). https://github.com/tendermint/tendermint/pull/4209#discussion_r360332460 * explain restoreTrustedHeaderAndNextVals better https://github.com/tendermint/tendermint/pull/4209#discussion_r360602328 * add ConfirmationFunction option for optionally prompting for user input Y/n before removing headers Refs https://github.com/tendermint/tendermint/pull/4209#discussion_r360602945 * make cleaning optional https://github.com/tendermint/tendermint/pull/4209#discussion_r364838189 * return error when user refused to remove headers * check for double votes in VerifyCommitTrusting * leave only ErrNewValSetCantBeTrusted error to differenciate between h2Vals.VerifyCommit and h1NextVals.VerifyCommitTrusting * fix example tests * remove unnecessary if condition https://github.com/tendermint/tendermint/pull/4209#discussion_r365171847 It will be handled by the above switch. * verifyCommitBasic does not depend on vals Co-authored-by: Marko <marbar3778@yahoo.com>
4 years ago
  1. package light_test
  2. import (
  3. "context"
  4. "errors"
  5. "fmt"
  6. "sync"
  7. "testing"
  8. "time"
  9. "github.com/stretchr/testify/assert"
  10. "github.com/stretchr/testify/mock"
  11. "github.com/stretchr/testify/require"
  12. dbm "github.com/tendermint/tm-db"
  13. "github.com/tendermint/tendermint/internal/test/factory"
  14. "github.com/tendermint/tendermint/libs/log"
  15. "github.com/tendermint/tendermint/light"
  16. "github.com/tendermint/tendermint/light/provider"
  17. provider_mocks "github.com/tendermint/tendermint/light/provider/mocks"
  18. dbs "github.com/tendermint/tendermint/light/store/db"
  19. "github.com/tendermint/tendermint/types"
  20. )
  21. const (
  22. chainID = "test"
  23. )
  24. var bTime time.Time
  25. func init() {
  26. var err error
  27. bTime, err = time.Parse(time.RFC3339, "2006-01-02T15:04:05Z")
  28. if err != nil {
  29. panic(err)
  30. }
  31. }
  32. func TestClient(t *testing.T) {
  33. ctx, cancel := context.WithCancel(context.Background())
  34. defer cancel()
  35. var (
  36. keys = genPrivKeys(4)
  37. vals = keys.ToValidators(20, 10)
  38. trustPeriod = 4 * time.Hour
  39. valSet = map[int64]*types.ValidatorSet{
  40. 1: vals,
  41. 2: vals,
  42. 3: vals,
  43. 4: vals,
  44. }
  45. h1 = keys.GenSignedHeader(t, chainID, 1, bTime, nil, vals, vals,
  46. hash("app_hash"), hash("cons_hash"), hash("results_hash"), 0, len(keys))
  47. // 3/3 signed
  48. h2 = keys.GenSignedHeaderLastBlockID(t, chainID, 2, bTime.Add(30*time.Minute), nil, vals, vals,
  49. hash("app_hash"), hash("cons_hash"), hash("results_hash"), 0, len(keys), types.BlockID{Hash: h1.Hash()})
  50. // 3/3 signed
  51. h3 = keys.GenSignedHeaderLastBlockID(t, chainID, 3, bTime.Add(1*time.Hour), nil, vals, vals,
  52. hash("app_hash"), hash("cons_hash"), hash("results_hash"), 0, len(keys), types.BlockID{Hash: h2.Hash()})
  53. trustOptions = light.TrustOptions{
  54. Period: 4 * time.Hour,
  55. Height: 1,
  56. Hash: h1.Hash(),
  57. }
  58. headerSet = map[int64]*types.SignedHeader{
  59. 1: h1,
  60. // interim header (3/3 signed)
  61. 2: h2,
  62. // last header (3/3 signed)
  63. 3: h3,
  64. }
  65. l1 = &types.LightBlock{SignedHeader: h1, ValidatorSet: vals}
  66. l2 = &types.LightBlock{SignedHeader: h2, ValidatorSet: vals}
  67. l3 = &types.LightBlock{SignedHeader: h3, ValidatorSet: vals}
  68. )
  69. t.Run("ValidateTrustOptions", func(t *testing.T) {
  70. testCases := []struct {
  71. err bool
  72. to light.TrustOptions
  73. }{
  74. {
  75. false,
  76. trustOptions,
  77. },
  78. {
  79. true,
  80. light.TrustOptions{
  81. Period: -1 * time.Hour,
  82. Height: 1,
  83. Hash: h1.Hash(),
  84. },
  85. },
  86. {
  87. true,
  88. light.TrustOptions{
  89. Period: 1 * time.Hour,
  90. Height: 0,
  91. Hash: h1.Hash(),
  92. },
  93. },
  94. {
  95. true,
  96. light.TrustOptions{
  97. Period: 1 * time.Hour,
  98. Height: 1,
  99. Hash: []byte("incorrect hash"),
  100. },
  101. },
  102. }
  103. for idx, tc := range testCases {
  104. t.Run(fmt.Sprint(idx), func(t *testing.T) {
  105. err := tc.to.ValidateBasic()
  106. if tc.err {
  107. assert.Error(t, err)
  108. } else {
  109. assert.NoError(t, err)
  110. }
  111. })
  112. }
  113. })
  114. t.Run("SequentialVerification", func(t *testing.T) {
  115. newKeys := genPrivKeys(4)
  116. newVals := newKeys.ToValidators(10, 1)
  117. differentVals, _ := factory.ValidatorSet(ctx, t, 10, 100)
  118. testCases := []struct {
  119. name string
  120. otherHeaders map[int64]*types.SignedHeader // all except ^
  121. vals map[int64]*types.ValidatorSet
  122. initErr bool
  123. verifyErr bool
  124. }{
  125. {
  126. name: "good",
  127. otherHeaders: headerSet,
  128. vals: valSet,
  129. initErr: false,
  130. verifyErr: false,
  131. },
  132. {
  133. "bad: different first header",
  134. map[int64]*types.SignedHeader{
  135. // different header
  136. 1: keys.GenSignedHeader(t, chainID, 1, bTime.Add(1*time.Hour), nil, vals, vals,
  137. hash("app_hash"), hash("cons_hash"), hash("results_hash"), 0, len(keys)),
  138. },
  139. map[int64]*types.ValidatorSet{
  140. 1: vals,
  141. },
  142. true,
  143. false,
  144. },
  145. {
  146. "bad: no first signed header",
  147. map[int64]*types.SignedHeader{},
  148. map[int64]*types.ValidatorSet{
  149. 1: differentVals,
  150. },
  151. true,
  152. true,
  153. },
  154. {
  155. "bad: different first validator set",
  156. map[int64]*types.SignedHeader{
  157. 1: h1,
  158. },
  159. map[int64]*types.ValidatorSet{
  160. 1: differentVals,
  161. },
  162. true,
  163. true,
  164. },
  165. {
  166. "bad: 1/3 signed interim header",
  167. map[int64]*types.SignedHeader{
  168. // trusted header
  169. 1: h1,
  170. // interim header (1/3 signed)
  171. 2: keys.GenSignedHeader(t, chainID, 2, bTime.Add(1*time.Hour), nil, vals, vals,
  172. hash("app_hash"), hash("cons_hash"), hash("results_hash"), len(keys)-1, len(keys)),
  173. // last header (3/3 signed)
  174. 3: keys.GenSignedHeader(t, chainID, 3, bTime.Add(2*time.Hour), nil, vals, vals,
  175. hash("app_hash"), hash("cons_hash"), hash("results_hash"), 0, len(keys)),
  176. },
  177. valSet,
  178. false,
  179. true,
  180. },
  181. {
  182. "bad: 1/3 signed last header",
  183. map[int64]*types.SignedHeader{
  184. // trusted header
  185. 1: h1,
  186. // interim header (3/3 signed)
  187. 2: keys.GenSignedHeader(t, chainID, 2, bTime.Add(1*time.Hour), nil, vals, vals,
  188. hash("app_hash"), hash("cons_hash"), hash("results_hash"), 0, len(keys)),
  189. // last header (1/3 signed)
  190. 3: keys.GenSignedHeader(t, chainID, 3, bTime.Add(2*time.Hour), nil, vals, vals,
  191. hash("app_hash"), hash("cons_hash"), hash("results_hash"), len(keys)-1, len(keys)),
  192. },
  193. valSet,
  194. false,
  195. true,
  196. },
  197. {
  198. "bad: different validator set at height 3",
  199. headerSet,
  200. map[int64]*types.ValidatorSet{
  201. 1: vals,
  202. 2: vals,
  203. 3: newVals,
  204. },
  205. false,
  206. true,
  207. },
  208. }
  209. for _, tc := range testCases {
  210. testCase := tc
  211. t.Run(testCase.name, func(t *testing.T) {
  212. ctx, cancel := context.WithCancel(context.Background())
  213. defer cancel()
  214. logger := log.NewNopLogger()
  215. mockNode := mockNodeFromHeadersAndVals(testCase.otherHeaders, testCase.vals)
  216. mockNode.On("LightBlock", mock.Anything, mock.Anything).Return(nil, provider.ErrLightBlockNotFound)
  217. c, err := light.NewClient(
  218. ctx,
  219. chainID,
  220. trustOptions,
  221. mockNode,
  222. nil,
  223. dbs.New(dbm.NewMemDB()),
  224. light.SequentialVerification(),
  225. light.Logger(logger),
  226. )
  227. if testCase.initErr {
  228. require.Error(t, err)
  229. return
  230. }
  231. require.NoError(t, err)
  232. _, err = c.VerifyLightBlockAtHeight(ctx, 3, bTime.Add(3*time.Hour))
  233. if testCase.verifyErr {
  234. assert.Error(t, err)
  235. } else {
  236. assert.NoError(t, err)
  237. }
  238. mockNode.AssertExpectations(t)
  239. })
  240. }
  241. })
  242. t.Run("SkippingVerification", func(t *testing.T) {
  243. // required for 2nd test case
  244. newKeys := genPrivKeys(4)
  245. newVals := newKeys.ToValidators(10, 1)
  246. // 1/3+ of vals, 2/3- of newVals
  247. transitKeys := keys.Extend(3)
  248. transitVals := transitKeys.ToValidators(10, 1)
  249. testCases := []struct {
  250. name string
  251. otherHeaders map[int64]*types.SignedHeader // all except ^
  252. vals map[int64]*types.ValidatorSet
  253. initErr bool
  254. verifyErr bool
  255. }{
  256. {
  257. "good",
  258. map[int64]*types.SignedHeader{
  259. // trusted header
  260. 1: h1,
  261. // last header (3/3 signed)
  262. 3: h3,
  263. },
  264. valSet,
  265. false,
  266. false,
  267. },
  268. {
  269. "good, but val set changes by 2/3 (1/3 of vals is still present)",
  270. map[int64]*types.SignedHeader{
  271. // trusted header
  272. 1: h1,
  273. 3: transitKeys.GenSignedHeader(t, chainID, 3, bTime.Add(2*time.Hour), nil, transitVals, transitVals,
  274. hash("app_hash"), hash("cons_hash"), hash("results_hash"), 0, len(transitKeys)),
  275. },
  276. map[int64]*types.ValidatorSet{
  277. 1: vals,
  278. 2: vals,
  279. 3: transitVals,
  280. },
  281. false,
  282. false,
  283. },
  284. {
  285. "good, but val set changes 100% at height 2",
  286. map[int64]*types.SignedHeader{
  287. // trusted header
  288. 1: h1,
  289. // interim header (3/3 signed)
  290. 2: keys.GenSignedHeader(t, chainID, 2, bTime.Add(1*time.Hour), nil, vals, newVals,
  291. hash("app_hash"), hash("cons_hash"), hash("results_hash"), 0, len(keys)),
  292. // last header (0/4 of the original val set signed)
  293. 3: newKeys.GenSignedHeader(t, chainID, 3, bTime.Add(2*time.Hour), nil, newVals, newVals,
  294. hash("app_hash"), hash("cons_hash"), hash("results_hash"), 0, len(newKeys)),
  295. },
  296. map[int64]*types.ValidatorSet{
  297. 1: vals,
  298. 2: vals,
  299. 3: newVals,
  300. },
  301. false,
  302. false,
  303. },
  304. {
  305. "bad: last header signed by newVals, interim header has no signers",
  306. map[int64]*types.SignedHeader{
  307. // trusted header
  308. 1: h1,
  309. // last header (0/4 of the original val set signed)
  310. 2: keys.GenSignedHeader(t, chainID, 2, bTime.Add(1*time.Hour), nil, vals, newVals,
  311. hash("app_hash"), hash("cons_hash"), hash("results_hash"), 0, 0),
  312. // last header (0/4 of the original val set signed)
  313. 3: newKeys.GenSignedHeader(t, chainID, 3, bTime.Add(2*time.Hour), nil, newVals, newVals,
  314. hash("app_hash"), hash("cons_hash"), hash("results_hash"), 0, len(newKeys)),
  315. },
  316. map[int64]*types.ValidatorSet{
  317. 1: vals,
  318. 2: vals,
  319. 3: newVals,
  320. },
  321. false,
  322. true,
  323. },
  324. }
  325. bctx, bcancel := context.WithCancel(context.Background())
  326. defer bcancel()
  327. for _, tc := range testCases {
  328. tc := tc
  329. t.Run(tc.name, func(t *testing.T) {
  330. ctx, cancel := context.WithCancel(bctx)
  331. defer cancel()
  332. logger := log.NewNopLogger()
  333. mockNode := mockNodeFromHeadersAndVals(tc.otherHeaders, tc.vals)
  334. mockNode.On("LightBlock", mock.Anything, mock.Anything).Return(nil, provider.ErrLightBlockNotFound)
  335. c, err := light.NewClient(
  336. ctx,
  337. chainID,
  338. trustOptions,
  339. mockNode,
  340. nil,
  341. dbs.New(dbm.NewMemDB()),
  342. light.SkippingVerification(light.DefaultTrustLevel),
  343. light.Logger(logger),
  344. )
  345. if tc.initErr {
  346. require.Error(t, err)
  347. return
  348. }
  349. require.NoError(t, err)
  350. _, err = c.VerifyLightBlockAtHeight(ctx, 3, bTime.Add(3*time.Hour))
  351. if tc.verifyErr {
  352. assert.Error(t, err)
  353. } else {
  354. assert.NoError(t, err)
  355. }
  356. })
  357. }
  358. })
  359. t.Run("LargeBisectionVerification", func(t *testing.T) {
  360. // start from a large light block to make sure that the pivot height doesn't select a height outside
  361. // the appropriate range
  362. numBlocks := int64(300)
  363. mockHeaders, mockVals, _ := genLightBlocksWithKeys(t, chainID, numBlocks, 101, 2, bTime)
  364. lastBlock := &types.LightBlock{SignedHeader: mockHeaders[numBlocks], ValidatorSet: mockVals[numBlocks]}
  365. mockNode := &provider_mocks.Provider{}
  366. mockNode.On("LightBlock", mock.Anything, numBlocks).
  367. Return(lastBlock, nil)
  368. mockNode.On("LightBlock", mock.Anything, int64(200)).
  369. Return(&types.LightBlock{SignedHeader: mockHeaders[200], ValidatorSet: mockVals[200]}, nil)
  370. mockNode.On("LightBlock", mock.Anything, int64(256)).
  371. Return(&types.LightBlock{SignedHeader: mockHeaders[256], ValidatorSet: mockVals[256]}, nil)
  372. mockNode.On("LightBlock", mock.Anything, int64(0)).Return(lastBlock, nil)
  373. ctx, cancel := context.WithCancel(context.Background())
  374. defer cancel()
  375. trustedLightBlock, err := mockNode.LightBlock(ctx, int64(200))
  376. require.NoError(t, err)
  377. c, err := light.NewClient(
  378. ctx,
  379. chainID,
  380. light.TrustOptions{
  381. Period: 4 * time.Hour,
  382. Height: trustedLightBlock.Height,
  383. Hash: trustedLightBlock.Hash(),
  384. },
  385. mockNode,
  386. nil,
  387. dbs.New(dbm.NewMemDB()),
  388. light.SkippingVerification(light.DefaultTrustLevel),
  389. )
  390. require.NoError(t, err)
  391. h, err := c.Update(ctx, bTime.Add(300*time.Minute))
  392. assert.NoError(t, err)
  393. height, err := c.LastTrustedHeight()
  394. require.NoError(t, err)
  395. require.Equal(t, numBlocks, height)
  396. h2, err := mockNode.LightBlock(ctx, numBlocks)
  397. require.NoError(t, err)
  398. assert.Equal(t, h, h2)
  399. mockNode.AssertExpectations(t)
  400. })
  401. t.Run("BisectionBetweenTrustedHeaders", func(t *testing.T) {
  402. ctx, cancel := context.WithCancel(context.Background())
  403. defer cancel()
  404. mockFullNode := mockNodeFromHeadersAndVals(headerSet, valSet)
  405. c, err := light.NewClient(
  406. ctx,
  407. chainID,
  408. light.TrustOptions{
  409. Period: 4 * time.Hour,
  410. Height: 1,
  411. Hash: h1.Hash(),
  412. },
  413. mockFullNode,
  414. nil,
  415. dbs.New(dbm.NewMemDB()),
  416. light.SkippingVerification(light.DefaultTrustLevel),
  417. )
  418. require.NoError(t, err)
  419. _, err = c.VerifyLightBlockAtHeight(ctx, 3, bTime.Add(2*time.Hour))
  420. require.NoError(t, err)
  421. // confirm that the client already doesn't have the light block
  422. _, err = c.TrustedLightBlock(2)
  423. require.Error(t, err)
  424. // verify using bisection the light block between the two trusted light blocks
  425. _, err = c.VerifyLightBlockAtHeight(ctx, 2, bTime.Add(1*time.Hour))
  426. assert.NoError(t, err)
  427. mockFullNode.AssertExpectations(t)
  428. })
  429. t.Run("Cleanup", func(t *testing.T) {
  430. ctx, cancel := context.WithCancel(context.Background())
  431. defer cancel()
  432. logger := log.NewNopLogger()
  433. mockFullNode := &provider_mocks.Provider{}
  434. mockFullNode.On("LightBlock", mock.Anything, int64(1)).Return(l1, nil)
  435. c, err := light.NewClient(
  436. ctx,
  437. chainID,
  438. trustOptions,
  439. mockFullNode,
  440. nil,
  441. dbs.New(dbm.NewMemDB()),
  442. light.Logger(logger),
  443. )
  444. require.NoError(t, err)
  445. _, err = c.TrustedLightBlock(1)
  446. require.NoError(t, err)
  447. err = c.Cleanup()
  448. require.NoError(t, err)
  449. // Check no light blocks exist after Cleanup.
  450. l, err := c.TrustedLightBlock(1)
  451. assert.Error(t, err)
  452. assert.Nil(t, l)
  453. mockFullNode.AssertExpectations(t)
  454. })
  455. t.Run("RestoresTrustedHeaderAfterStartup", func(t *testing.T) {
  456. // trustedHeader.Height == options.Height
  457. bctx, bcancel := context.WithCancel(context.Background())
  458. defer bcancel()
  459. // 1. options.Hash == trustedHeader.Hash
  460. t.Run("hashes should match", func(t *testing.T) {
  461. ctx, cancel := context.WithCancel(bctx)
  462. defer cancel()
  463. logger := log.NewNopLogger()
  464. mockNode := &provider_mocks.Provider{}
  465. trustedStore := dbs.New(dbm.NewMemDB())
  466. err := trustedStore.SaveLightBlock(l1)
  467. require.NoError(t, err)
  468. c, err := light.NewClient(
  469. ctx,
  470. chainID,
  471. trustOptions,
  472. mockNode,
  473. nil,
  474. trustedStore,
  475. light.Logger(logger),
  476. )
  477. require.NoError(t, err)
  478. l, err := c.TrustedLightBlock(1)
  479. assert.NoError(t, err)
  480. assert.NotNil(t, l)
  481. assert.Equal(t, l.Hash(), h1.Hash())
  482. assert.Equal(t, l.ValidatorSet.Hash(), h1.ValidatorsHash.Bytes())
  483. mockNode.AssertExpectations(t)
  484. })
  485. // 2. options.Hash != trustedHeader.Hash
  486. t.Run("hashes should not match", func(t *testing.T) {
  487. ctx, cancel := context.WithCancel(bctx)
  488. defer cancel()
  489. trustedStore := dbs.New(dbm.NewMemDB())
  490. err := trustedStore.SaveLightBlock(l1)
  491. require.NoError(t, err)
  492. logger := log.NewNopLogger()
  493. // header1 != h1
  494. header1 := keys.GenSignedHeader(t, chainID, 1, bTime.Add(1*time.Hour), nil, vals, vals,
  495. hash("app_hash"), hash("cons_hash"), hash("results_hash"), 0, len(keys))
  496. mockNode := &provider_mocks.Provider{}
  497. c, err := light.NewClient(
  498. ctx,
  499. chainID,
  500. light.TrustOptions{
  501. Period: 4 * time.Hour,
  502. Height: 1,
  503. Hash: header1.Hash(),
  504. },
  505. mockNode,
  506. nil,
  507. trustedStore,
  508. light.Logger(logger),
  509. )
  510. require.NoError(t, err)
  511. l, err := c.TrustedLightBlock(1)
  512. assert.NoError(t, err)
  513. if assert.NotNil(t, l) {
  514. // client take the trusted store and ignores the trusted options
  515. assert.Equal(t, l.Hash(), l1.Hash())
  516. assert.NoError(t, l.ValidateBasic(chainID))
  517. }
  518. mockNode.AssertExpectations(t)
  519. })
  520. })
  521. t.Run("Update", func(t *testing.T) {
  522. ctx, cancel := context.WithCancel(context.Background())
  523. defer cancel()
  524. mockFullNode := &provider_mocks.Provider{}
  525. mockFullNode.On("ID").Return("mockFullNode")
  526. mockFullNode.On("LightBlock", mock.Anything, int64(0)).Return(l3, nil)
  527. mockFullNode.On("LightBlock", mock.Anything, int64(1)).Return(l1, nil)
  528. mockWitnessNode := &provider_mocks.Provider{}
  529. mockWitnessNode.On("ID").Return("mockWitnessNode")
  530. mockWitnessNode.On("LightBlock", mock.Anything, int64(1)).Return(l1, nil)
  531. mockWitnessNode.On("LightBlock", mock.Anything, int64(3)).Return(l3, nil)
  532. logger := log.NewNopLogger()
  533. c, err := light.NewClient(
  534. ctx,
  535. chainID,
  536. trustOptions,
  537. mockFullNode,
  538. []provider.Provider{mockWitnessNode},
  539. dbs.New(dbm.NewMemDB()),
  540. light.Logger(logger),
  541. )
  542. require.NoError(t, err)
  543. // should result in downloading & verifying header #3
  544. l, err := c.Update(ctx, bTime.Add(2*time.Hour))
  545. assert.NoError(t, err)
  546. if assert.NotNil(t, l) {
  547. assert.EqualValues(t, 3, l.Height)
  548. assert.NoError(t, l.ValidateBasic(chainID))
  549. }
  550. mockFullNode.AssertExpectations(t)
  551. mockWitnessNode.AssertExpectations(t)
  552. })
  553. t.Run("Concurrency", func(t *testing.T) {
  554. ctx, cancel := context.WithCancel(context.Background())
  555. defer cancel()
  556. logger := log.NewNopLogger()
  557. mockFullNode := &provider_mocks.Provider{}
  558. mockFullNode.On("LightBlock", mock.Anything, int64(2)).Return(l2, nil)
  559. mockFullNode.On("LightBlock", mock.Anything, int64(1)).Return(l1, nil)
  560. c, err := light.NewClient(
  561. ctx,
  562. chainID,
  563. trustOptions,
  564. mockFullNode,
  565. nil,
  566. dbs.New(dbm.NewMemDB()),
  567. light.Logger(logger),
  568. )
  569. require.NoError(t, err)
  570. _, err = c.VerifyLightBlockAtHeight(ctx, 2, bTime.Add(2*time.Hour))
  571. require.NoError(t, err)
  572. var wg sync.WaitGroup
  573. for i := 0; i < 100; i++ {
  574. wg.Add(1)
  575. go func() {
  576. defer wg.Done()
  577. // NOTE: Cleanup, Stop, VerifyLightBlockAtHeight and Verify are not supposed
  578. // to be concurrently safe.
  579. assert.Equal(t, chainID, c.ChainID())
  580. _, err := c.LastTrustedHeight()
  581. assert.NoError(t, err)
  582. _, err = c.FirstTrustedHeight()
  583. assert.NoError(t, err)
  584. l, err := c.TrustedLightBlock(1)
  585. assert.NoError(t, err)
  586. assert.NotNil(t, l)
  587. }()
  588. }
  589. wg.Wait()
  590. mockFullNode.AssertExpectations(t)
  591. })
  592. t.Run("AddProviders", func(t *testing.T) {
  593. ctx, cancel := context.WithCancel(context.Background())
  594. defer cancel()
  595. mockFullNode := mockNodeFromHeadersAndVals(map[int64]*types.SignedHeader{
  596. 1: h1,
  597. 2: h2,
  598. }, valSet)
  599. logger := log.NewNopLogger()
  600. c, err := light.NewClient(
  601. ctx,
  602. chainID,
  603. trustOptions,
  604. mockFullNode,
  605. nil,
  606. dbs.New(dbm.NewMemDB()),
  607. light.Logger(logger),
  608. )
  609. require.NoError(t, err)
  610. closeCh := make(chan struct{})
  611. go func() {
  612. // run verification concurrently to make sure it doesn't dead lock
  613. _, err = c.VerifyLightBlockAtHeight(ctx, 2, bTime.Add(2*time.Hour))
  614. require.NoError(t, err)
  615. close(closeCh)
  616. }()
  617. c.AddProvider(mockFullNode)
  618. require.Len(t, c.Witnesses(), 1)
  619. select {
  620. case <-closeCh:
  621. case <-time.After(5 * time.Second):
  622. t.Fatal("concurent light block verification failed to finish in 5s")
  623. }
  624. mockFullNode.AssertExpectations(t)
  625. })
  626. t.Run("ReplacesPrimaryWithWitnessIfPrimaryIsUnavailable", func(t *testing.T) {
  627. ctx, cancel := context.WithCancel(context.Background())
  628. defer cancel()
  629. mockFullNode := &provider_mocks.Provider{}
  630. mockFullNode.On("LightBlock", mock.Anything, mock.Anything).Return(l1, nil)
  631. mockFullNode.On("ID").Return("mockFullNode")
  632. mockDeadNode := &provider_mocks.Provider{}
  633. mockDeadNode.On("LightBlock", mock.Anything, mock.Anything).Return(nil, provider.ErrNoResponse)
  634. mockDeadNode.On("ID").Return("mockDeadNode")
  635. logger := log.NewNopLogger()
  636. c, err := light.NewClient(
  637. ctx,
  638. chainID,
  639. trustOptions,
  640. mockDeadNode,
  641. []provider.Provider{mockFullNode},
  642. dbs.New(dbm.NewMemDB()),
  643. light.Logger(logger),
  644. )
  645. require.NoError(t, err)
  646. _, err = c.Update(ctx, bTime.Add(2*time.Hour))
  647. require.NoError(t, err)
  648. // the primary should no longer be the deadNode
  649. assert.NotEqual(t, c.Primary(), mockDeadNode)
  650. // we should still have the dead node as a witness because it
  651. // hasn't repeatedly been unresponsive yet
  652. assert.Equal(t, 1, len(c.Witnesses()))
  653. mockDeadNode.AssertExpectations(t)
  654. mockFullNode.AssertExpectations(t)
  655. })
  656. t.Run("ReplacesPrimaryWithWitnessIfPrimaryDoesntHaveBlock", func(t *testing.T) {
  657. ctx, cancel := context.WithCancel(context.Background())
  658. defer cancel()
  659. mockFullNode := &provider_mocks.Provider{}
  660. mockFullNode.On("LightBlock", mock.Anything, mock.Anything).Return(l1, nil)
  661. mockFullNode.On("ID").Return("mockFullNode")
  662. logger := log.NewNopLogger()
  663. mockDeadNode1 := &provider_mocks.Provider{}
  664. mockDeadNode1.On("LightBlock", mock.Anything, mock.Anything).Return(nil, provider.ErrLightBlockNotFound)
  665. mockDeadNode1.On("ID").Return("mockDeadNode1")
  666. mockDeadNode2 := &provider_mocks.Provider{}
  667. mockDeadNode2.On("LightBlock", mock.Anything, mock.Anything).Return(nil, provider.ErrLightBlockNotFound)
  668. mockDeadNode2.On("ID").Return("mockDeadNode2")
  669. c, err := light.NewClient(
  670. ctx,
  671. chainID,
  672. trustOptions,
  673. mockDeadNode1,
  674. []provider.Provider{mockFullNode, mockDeadNode2},
  675. dbs.New(dbm.NewMemDB()),
  676. light.Logger(logger),
  677. )
  678. require.NoError(t, err)
  679. _, err = c.Update(ctx, bTime.Add(2*time.Hour))
  680. require.NoError(t, err)
  681. // we should still have the dead node as a witness because it
  682. // hasn't repeatedly been unresponsive yet
  683. assert.Equal(t, 2, len(c.Witnesses()))
  684. mockDeadNode1.AssertExpectations(t)
  685. mockFullNode.AssertExpectations(t)
  686. })
  687. t.Run("BackwardsVerification", func(t *testing.T) {
  688. ctx, cancel := context.WithCancel(context.Background())
  689. defer cancel()
  690. logger := log.NewNopLogger()
  691. {
  692. headers, vals, _ := genLightBlocksWithKeys(t, chainID, 9, 3, 0, bTime)
  693. delete(headers, 1)
  694. delete(headers, 2)
  695. delete(vals, 1)
  696. delete(vals, 2)
  697. mockLargeFullNode := mockNodeFromHeadersAndVals(headers, vals)
  698. trustHeader, _ := mockLargeFullNode.LightBlock(ctx, 6)
  699. c, err := light.NewClient(
  700. ctx,
  701. chainID,
  702. light.TrustOptions{
  703. Period: 4 * time.Minute,
  704. Height: trustHeader.Height,
  705. Hash: trustHeader.Hash(),
  706. },
  707. mockLargeFullNode,
  708. nil,
  709. dbs.New(dbm.NewMemDB()),
  710. light.Logger(logger),
  711. )
  712. require.NoError(t, err)
  713. // 1) verify before the trusted header using backwards => expect no error
  714. h, err := c.VerifyLightBlockAtHeight(ctx, 5, bTime.Add(6*time.Minute))
  715. require.NoError(t, err)
  716. if assert.NotNil(t, h) {
  717. assert.EqualValues(t, 5, h.Height)
  718. }
  719. // 2) untrusted header is expired but trusted header is not => expect no error
  720. h, err = c.VerifyLightBlockAtHeight(ctx, 3, bTime.Add(8*time.Minute))
  721. assert.NoError(t, err)
  722. assert.NotNil(t, h)
  723. // 3) already stored headers should return the header without error
  724. h, err = c.VerifyLightBlockAtHeight(ctx, 5, bTime.Add(6*time.Minute))
  725. assert.NoError(t, err)
  726. assert.NotNil(t, h)
  727. // 4a) First verify latest header
  728. _, err = c.VerifyLightBlockAtHeight(ctx, 9, bTime.Add(9*time.Minute))
  729. require.NoError(t, err)
  730. // 4b) Verify backwards using bisection => expect no error
  731. _, err = c.VerifyLightBlockAtHeight(ctx, 7, bTime.Add(9*time.Minute))
  732. assert.NoError(t, err)
  733. // shouldn't have verified this header in the process
  734. _, err = c.TrustedLightBlock(8)
  735. assert.Error(t, err)
  736. // 5) Try bisection method, but closest header (at 7) has expired
  737. // so expect error
  738. _, err = c.VerifyLightBlockAtHeight(ctx, 8, bTime.Add(12*time.Minute))
  739. assert.Error(t, err)
  740. mockLargeFullNode.AssertExpectations(t)
  741. }
  742. {
  743. // 8) provides incorrect hash
  744. headers := map[int64]*types.SignedHeader{
  745. 2: keys.GenSignedHeader(t, chainID, 2, bTime.Add(30*time.Minute), nil, vals, vals,
  746. hash("app_hash2"), hash("cons_hash23"), hash("results_hash30"), 0, len(keys)),
  747. 3: h3,
  748. }
  749. vals := valSet
  750. mockNode := mockNodeFromHeadersAndVals(headers, vals)
  751. c, err := light.NewClient(
  752. ctx,
  753. chainID,
  754. light.TrustOptions{
  755. Period: 1 * time.Hour,
  756. Height: 3,
  757. Hash: h3.Hash(),
  758. },
  759. mockNode,
  760. nil,
  761. dbs.New(dbm.NewMemDB()),
  762. light.Logger(logger),
  763. )
  764. require.NoError(t, err)
  765. _, err = c.VerifyLightBlockAtHeight(ctx, 2, bTime.Add(1*time.Hour).Add(1*time.Second))
  766. assert.Error(t, err)
  767. mockNode.AssertExpectations(t)
  768. }
  769. })
  770. t.Run("NewClientFromTrustedStore", func(t *testing.T) {
  771. // 1) Initiate DB and fill with a "trusted" header
  772. db := dbs.New(dbm.NewMemDB())
  773. err := db.SaveLightBlock(l1)
  774. require.NoError(t, err)
  775. mockPrimary := &provider_mocks.Provider{}
  776. mockPrimary.On("ID").Return("mockPrimary")
  777. mockWitness := &provider_mocks.Provider{}
  778. mockWitness.On("ID").Return("mockWitness")
  779. c, err := light.NewClientFromTrustedStore(
  780. chainID,
  781. trustPeriod,
  782. mockPrimary,
  783. []provider.Provider{mockWitness},
  784. db,
  785. )
  786. require.NoError(t, err)
  787. // 2) Check light block exists
  788. h, err := c.TrustedLightBlock(1)
  789. assert.NoError(t, err)
  790. assert.EqualValues(t, l1.Height, h.Height)
  791. mockPrimary.AssertExpectations(t)
  792. mockWitness.AssertExpectations(t)
  793. })
  794. t.Run("RemovesWitnessIfItSendsUsIncorrectHeader", func(t *testing.T) {
  795. logger := log.NewNopLogger()
  796. // different headers hash then primary plus less than 1/3 signed (no fork)
  797. headers1 := map[int64]*types.SignedHeader{
  798. 1: h1,
  799. 2: keys.GenSignedHeaderLastBlockID(t, chainID, 2, bTime.Add(30*time.Minute), nil, vals, vals,
  800. hash("app_hash2"), hash("cons_hash"), hash("results_hash"),
  801. len(keys), len(keys), types.BlockID{Hash: h1.Hash()}),
  802. }
  803. vals1 := map[int64]*types.ValidatorSet{
  804. 1: vals,
  805. 2: vals,
  806. }
  807. mockBadNode1 := mockNodeFromHeadersAndVals(headers1, vals1)
  808. mockBadNode1.On("LightBlock", mock.Anything, mock.Anything).Return(nil, provider.ErrLightBlockNotFound)
  809. mockBadNode1.On("ID").Return("mockBadNode1")
  810. // header is empty
  811. headers2 := map[int64]*types.SignedHeader{
  812. 1: h1,
  813. 2: h2,
  814. }
  815. vals2 := map[int64]*types.ValidatorSet{
  816. 1: vals,
  817. 2: vals,
  818. }
  819. mockBadNode2 := mockNodeFromHeadersAndVals(headers2, vals2)
  820. mockBadNode2.On("LightBlock", mock.Anything, mock.Anything).Return(nil, provider.ErrLightBlockNotFound)
  821. mockBadNode2.On("ID").Return("mockBadNode2")
  822. mockFullNode := mockNodeFromHeadersAndVals(headerSet, valSet)
  823. mockFullNode.On("ID").Return("mockFullNode")
  824. ctx, cancel := context.WithCancel(context.Background())
  825. defer cancel()
  826. lb1, _ := mockBadNode1.LightBlock(ctx, 2)
  827. require.NotEqual(t, lb1.Hash(), l1.Hash())
  828. c, err := light.NewClient(
  829. ctx,
  830. chainID,
  831. trustOptions,
  832. mockFullNode,
  833. []provider.Provider{mockBadNode1, mockBadNode2},
  834. dbs.New(dbm.NewMemDB()),
  835. light.Logger(logger),
  836. )
  837. // witness should have behaved properly -> no error
  838. require.NoError(t, err)
  839. assert.EqualValues(t, 2, len(c.Witnesses()))
  840. // witness behaves incorrectly -> removed from list, no error
  841. l, err := c.VerifyLightBlockAtHeight(ctx, 2, bTime.Add(2*time.Hour))
  842. assert.NoError(t, err)
  843. assert.EqualValues(t, 1, len(c.Witnesses()))
  844. // light block should still be verified
  845. assert.EqualValues(t, 2, l.Height)
  846. // remaining witnesses don't have light block -> error
  847. _, err = c.VerifyLightBlockAtHeight(ctx, 3, bTime.Add(2*time.Hour))
  848. if assert.Error(t, err) {
  849. assert.Equal(t, light.ErrFailedHeaderCrossReferencing, err)
  850. }
  851. // witness does not have a light block -> left in the list
  852. assert.EqualValues(t, 1, len(c.Witnesses()))
  853. mockBadNode1.AssertExpectations(t)
  854. mockBadNode2.AssertExpectations(t)
  855. })
  856. t.Run("TrustedValidatorSet", func(t *testing.T) {
  857. ctx, cancel := context.WithCancel(context.Background())
  858. defer cancel()
  859. logger := log.NewNopLogger()
  860. differentVals, _ := factory.ValidatorSet(ctx, t, 10, 100)
  861. mockBadValSetNode := mockNodeFromHeadersAndVals(
  862. map[int64]*types.SignedHeader{
  863. 1: h1,
  864. // 3/3 signed, but validator set at height 2 below is invalid -> witness
  865. // should be removed.
  866. 2: keys.GenSignedHeaderLastBlockID(t, chainID, 2, bTime.Add(30*time.Minute), nil, vals, vals,
  867. hash("app_hash2"), hash("cons_hash"), hash("results_hash"),
  868. 0, len(keys), types.BlockID{Hash: h1.Hash()}),
  869. },
  870. map[int64]*types.ValidatorSet{
  871. 1: vals,
  872. 2: differentVals,
  873. })
  874. mockBadValSetNode.On("ID").Return("mockBadValSetNode")
  875. mockFullNode := mockNodeFromHeadersAndVals(
  876. map[int64]*types.SignedHeader{
  877. 1: h1,
  878. 2: h2,
  879. },
  880. map[int64]*types.ValidatorSet{
  881. 1: vals,
  882. 2: vals,
  883. })
  884. mockFullNode.On("ID").Return("mockFullNode")
  885. mockGoodWitness := mockNodeFromHeadersAndVals(
  886. map[int64]*types.SignedHeader{
  887. 1: h1,
  888. 2: h2,
  889. },
  890. map[int64]*types.ValidatorSet{
  891. 1: vals,
  892. 2: vals,
  893. })
  894. mockGoodWitness.On("ID").Return("mockGoodWitness")
  895. c, err := light.NewClient(
  896. ctx,
  897. chainID,
  898. trustOptions,
  899. mockFullNode,
  900. []provider.Provider{mockBadValSetNode, mockGoodWitness},
  901. dbs.New(dbm.NewMemDB()),
  902. light.Logger(logger),
  903. )
  904. require.NoError(t, err)
  905. assert.Equal(t, 2, len(c.Witnesses()))
  906. _, err = c.VerifyLightBlockAtHeight(ctx, 2, bTime.Add(2*time.Hour).Add(1*time.Second))
  907. assert.NoError(t, err)
  908. assert.Equal(t, 1, len(c.Witnesses()))
  909. mockBadValSetNode.AssertExpectations(t)
  910. mockFullNode.AssertExpectations(t)
  911. })
  912. t.Run("PrunesHeadersAndValidatorSets", func(t *testing.T) {
  913. mockFullNode := mockNodeFromHeadersAndVals(
  914. map[int64]*types.SignedHeader{
  915. 1: h1,
  916. 0: h3,
  917. },
  918. map[int64]*types.ValidatorSet{
  919. 1: vals,
  920. 0: vals,
  921. })
  922. mockFullNode.On("ID").Return("mockFullNode")
  923. mockGoodWitness := mockNodeFromHeadersAndVals(
  924. map[int64]*types.SignedHeader{
  925. 1: h1,
  926. 3: h3,
  927. },
  928. map[int64]*types.ValidatorSet{
  929. 1: vals,
  930. 3: vals,
  931. })
  932. mockGoodWitness.On("ID").Return("mockGoodWitness")
  933. ctx, cancel := context.WithCancel(context.Background())
  934. defer cancel()
  935. logger := log.NewNopLogger()
  936. c, err := light.NewClient(
  937. ctx,
  938. chainID,
  939. trustOptions,
  940. mockFullNode,
  941. []provider.Provider{mockGoodWitness},
  942. dbs.New(dbm.NewMemDB()),
  943. light.Logger(logger),
  944. light.PruningSize(1),
  945. )
  946. require.NoError(t, err)
  947. _, err = c.TrustedLightBlock(1)
  948. require.NoError(t, err)
  949. h, err := c.Update(ctx, bTime.Add(2*time.Hour))
  950. require.NoError(t, err)
  951. require.Equal(t, int64(3), h.Height)
  952. _, err = c.TrustedLightBlock(1)
  953. assert.Error(t, err)
  954. mockFullNode.AssertExpectations(t)
  955. mockGoodWitness.AssertExpectations(t)
  956. })
  957. t.Run("EnsureValidHeadersAndValSets", func(t *testing.T) {
  958. emptyValSet := &types.ValidatorSet{
  959. Validators: nil,
  960. Proposer: nil,
  961. }
  962. testCases := []struct {
  963. headers map[int64]*types.SignedHeader
  964. vals map[int64]*types.ValidatorSet
  965. errorToThrow error
  966. errorHeight int64
  967. err bool
  968. }{
  969. {
  970. headers: map[int64]*types.SignedHeader{
  971. 1: h1,
  972. 3: h3,
  973. },
  974. vals: map[int64]*types.ValidatorSet{
  975. 1: vals,
  976. 3: vals,
  977. },
  978. err: false,
  979. },
  980. {
  981. headers: map[int64]*types.SignedHeader{
  982. 1: h1,
  983. },
  984. vals: map[int64]*types.ValidatorSet{
  985. 1: vals,
  986. },
  987. errorToThrow: provider.ErrBadLightBlock{Reason: errors.New("nil header or vals")},
  988. errorHeight: 3,
  989. err: true,
  990. },
  991. {
  992. headers: map[int64]*types.SignedHeader{
  993. 1: h1,
  994. },
  995. errorToThrow: provider.ErrBadLightBlock{Reason: errors.New("nil header or vals")},
  996. errorHeight: 3,
  997. vals: valSet,
  998. err: true,
  999. },
  1000. {
  1001. headers: map[int64]*types.SignedHeader{
  1002. 1: h1,
  1003. 3: h3,
  1004. },
  1005. vals: map[int64]*types.ValidatorSet{
  1006. 1: vals,
  1007. 3: emptyValSet,
  1008. },
  1009. err: true,
  1010. },
  1011. }
  1012. for i, tc := range testCases {
  1013. testCase := tc
  1014. t.Run(fmt.Sprintf("case: %d", i), func(t *testing.T) {
  1015. ctx, cancel := context.WithCancel(context.Background())
  1016. defer cancel()
  1017. mockBadNode := mockNodeFromHeadersAndVals(testCase.headers, testCase.vals)
  1018. if testCase.errorToThrow != nil {
  1019. mockBadNode.On("LightBlock", mock.Anything, testCase.errorHeight).Return(nil, testCase.errorToThrow)
  1020. }
  1021. c, err := light.NewClient(
  1022. ctx,
  1023. chainID,
  1024. trustOptions,
  1025. mockBadNode,
  1026. nil,
  1027. dbs.New(dbm.NewMemDB()),
  1028. )
  1029. require.NoError(t, err)
  1030. _, err = c.VerifyLightBlockAtHeight(ctx, 3, bTime.Add(2*time.Hour))
  1031. if testCase.err {
  1032. assert.Error(t, err)
  1033. } else {
  1034. assert.NoError(t, err)
  1035. }
  1036. mockBadNode.AssertExpectations(t)
  1037. })
  1038. }
  1039. })
  1040. }