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.

1117 lines
30 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>
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
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>
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>
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>
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>
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>
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>
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>
5 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. var (
  34. keys = genPrivKeys(4)
  35. vals = keys.ToValidators(20, 10)
  36. trustPeriod = 4 * time.Hour
  37. valSet = map[int64]*types.ValidatorSet{
  38. 1: vals,
  39. 2: vals,
  40. 3: vals,
  41. 4: vals,
  42. }
  43. h1 = keys.GenSignedHeader(t, chainID, 1, bTime, nil, vals, vals,
  44. hash("app_hash"), hash("cons_hash"), hash("results_hash"), 0, len(keys))
  45. // 3/3 signed
  46. h2 = keys.GenSignedHeaderLastBlockID(t, chainID, 2, bTime.Add(30*time.Minute), nil, vals, vals,
  47. hash("app_hash"), hash("cons_hash"), hash("results_hash"), 0, len(keys), types.BlockID{Hash: h1.Hash()})
  48. // 3/3 signed
  49. h3 = keys.GenSignedHeaderLastBlockID(t, chainID, 3, bTime.Add(1*time.Hour), nil, vals, vals,
  50. hash("app_hash"), hash("cons_hash"), hash("results_hash"), 0, len(keys), types.BlockID{Hash: h2.Hash()})
  51. trustOptions = light.TrustOptions{
  52. Period: 4 * time.Hour,
  53. Height: 1,
  54. Hash: h1.Hash(),
  55. }
  56. headerSet = map[int64]*types.SignedHeader{
  57. 1: h1,
  58. // interim header (3/3 signed)
  59. 2: h2,
  60. // last header (3/3 signed)
  61. 3: h3,
  62. }
  63. l1 = &types.LightBlock{SignedHeader: h1, ValidatorSet: vals}
  64. l2 = &types.LightBlock{SignedHeader: h2, ValidatorSet: vals}
  65. l3 = &types.LightBlock{SignedHeader: h3, ValidatorSet: vals}
  66. )
  67. t.Run("ValidateTrustOptions", func(t *testing.T) {
  68. testCases := []struct {
  69. err bool
  70. to light.TrustOptions
  71. }{
  72. {
  73. false,
  74. trustOptions,
  75. },
  76. {
  77. true,
  78. light.TrustOptions{
  79. Period: -1 * time.Hour,
  80. Height: 1,
  81. Hash: h1.Hash(),
  82. },
  83. },
  84. {
  85. true,
  86. light.TrustOptions{
  87. Period: 1 * time.Hour,
  88. Height: 0,
  89. Hash: h1.Hash(),
  90. },
  91. },
  92. {
  93. true,
  94. light.TrustOptions{
  95. Period: 1 * time.Hour,
  96. Height: 1,
  97. Hash: []byte("incorrect hash"),
  98. },
  99. },
  100. }
  101. for idx, tc := range testCases {
  102. t.Run(fmt.Sprint(idx), func(t *testing.T) {
  103. err := tc.to.ValidateBasic()
  104. if tc.err {
  105. assert.Error(t, err)
  106. } else {
  107. assert.NoError(t, err)
  108. }
  109. })
  110. }
  111. })
  112. t.Run("SequentialVerification", func(t *testing.T) {
  113. ctx, cancel := context.WithCancel(context.Background())
  114. defer cancel()
  115. newKeys := genPrivKeys(4)
  116. newVals := newKeys.ToValidators(10, 1)
  117. differentVals, _ := factory.RandValidatorSet(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.NewTestingLogger(t)
  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. []provider.Provider{mockNode},
  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.NewTestingLogger(t)
  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. []provider.Provider{mockNode},
  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. []provider.Provider{mockNode},
  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. []provider.Provider{mockFullNode},
  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.NewTestingLogger(t)
  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. []provider.Provider{mockFullNode},
  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.NewTestingLogger(t)
  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. []provider.Provider{mockNode},
  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.NewTestingLogger(t)
  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. []provider.Provider{mockNode},
  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("LightBlock", mock.Anything, int64(0)).Return(l3, nil)
  526. mockFullNode.On("LightBlock", mock.Anything, int64(1)).Return(l1, nil)
  527. mockFullNode.On("LightBlock", mock.Anything, int64(3)).Return(l3, nil)
  528. logger := log.NewTestingLogger(t)
  529. c, err := light.NewClient(
  530. ctx,
  531. chainID,
  532. trustOptions,
  533. mockFullNode,
  534. []provider.Provider{mockFullNode},
  535. dbs.New(dbm.NewMemDB()),
  536. light.Logger(logger),
  537. )
  538. require.NoError(t, err)
  539. // should result in downloading & verifying header #3
  540. l, err := c.Update(ctx, bTime.Add(2*time.Hour))
  541. assert.NoError(t, err)
  542. if assert.NotNil(t, l) {
  543. assert.EqualValues(t, 3, l.Height)
  544. assert.NoError(t, l.ValidateBasic(chainID))
  545. }
  546. mockFullNode.AssertExpectations(t)
  547. })
  548. t.Run("Concurrency", func(t *testing.T) {
  549. ctx, cancel := context.WithCancel(context.Background())
  550. defer cancel()
  551. logger := log.NewTestingLogger(t)
  552. mockFullNode := &provider_mocks.Provider{}
  553. mockFullNode.On("LightBlock", mock.Anything, int64(2)).Return(l2, nil)
  554. mockFullNode.On("LightBlock", mock.Anything, int64(1)).Return(l1, nil)
  555. c, err := light.NewClient(
  556. ctx,
  557. chainID,
  558. trustOptions,
  559. mockFullNode,
  560. []provider.Provider{mockFullNode},
  561. dbs.New(dbm.NewMemDB()),
  562. light.Logger(logger),
  563. )
  564. require.NoError(t, err)
  565. _, err = c.VerifyLightBlockAtHeight(ctx, 2, bTime.Add(2*time.Hour))
  566. require.NoError(t, err)
  567. var wg sync.WaitGroup
  568. for i := 0; i < 100; i++ {
  569. wg.Add(1)
  570. go func() {
  571. defer wg.Done()
  572. // NOTE: Cleanup, Stop, VerifyLightBlockAtHeight and Verify are not supposed
  573. // to be concurrently safe.
  574. assert.Equal(t, chainID, c.ChainID())
  575. _, err := c.LastTrustedHeight()
  576. assert.NoError(t, err)
  577. _, err = c.FirstTrustedHeight()
  578. assert.NoError(t, err)
  579. l, err := c.TrustedLightBlock(1)
  580. assert.NoError(t, err)
  581. assert.NotNil(t, l)
  582. }()
  583. }
  584. wg.Wait()
  585. mockFullNode.AssertExpectations(t)
  586. })
  587. t.Run("AddProviders", func(t *testing.T) {
  588. ctx, cancel := context.WithCancel(context.Background())
  589. defer cancel()
  590. mockFullNode := mockNodeFromHeadersAndVals(map[int64]*types.SignedHeader{
  591. 1: h1,
  592. 2: h2,
  593. }, valSet)
  594. logger := log.NewTestingLogger(t)
  595. c, err := light.NewClient(
  596. ctx,
  597. chainID,
  598. trustOptions,
  599. mockFullNode,
  600. []provider.Provider{mockFullNode},
  601. dbs.New(dbm.NewMemDB()),
  602. light.Logger(logger),
  603. )
  604. require.NoError(t, err)
  605. closeCh := make(chan struct{})
  606. go func() {
  607. // run verification concurrently to make sure it doesn't dead lock
  608. _, err = c.VerifyLightBlockAtHeight(ctx, 2, bTime.Add(2*time.Hour))
  609. require.NoError(t, err)
  610. close(closeCh)
  611. }()
  612. // NOTE: the light client doesn't check uniqueness of providers
  613. c.AddProvider(mockFullNode)
  614. require.Len(t, c.Witnesses(), 2)
  615. select {
  616. case <-closeCh:
  617. case <-time.After(5 * time.Second):
  618. t.Fatal("concurent light block verification failed to finish in 5s")
  619. }
  620. mockFullNode.AssertExpectations(t)
  621. })
  622. t.Run("ReplacesPrimaryWithWitnessIfPrimaryIsUnavailable", func(t *testing.T) {
  623. ctx, cancel := context.WithCancel(context.Background())
  624. defer cancel()
  625. mockFullNode := &provider_mocks.Provider{}
  626. mockFullNode.On("LightBlock", mock.Anything, mock.Anything).Return(l1, nil)
  627. mockDeadNode := &provider_mocks.Provider{}
  628. mockDeadNode.On("LightBlock", mock.Anything, mock.Anything).Return(nil, provider.ErrNoResponse)
  629. logger := log.NewTestingLogger(t)
  630. c, err := light.NewClient(
  631. ctx,
  632. chainID,
  633. trustOptions,
  634. mockDeadNode,
  635. []provider.Provider{mockDeadNode, mockFullNode},
  636. dbs.New(dbm.NewMemDB()),
  637. light.Logger(logger),
  638. )
  639. require.NoError(t, err)
  640. _, err = c.Update(ctx, bTime.Add(2*time.Hour))
  641. require.NoError(t, err)
  642. // the primary should no longer be the deadNode
  643. assert.NotEqual(t, c.Primary(), mockDeadNode)
  644. // we should still have the dead node as a witness because it
  645. // hasn't repeatedly been unresponsive yet
  646. assert.Equal(t, 2, len(c.Witnesses()))
  647. mockDeadNode.AssertExpectations(t)
  648. mockFullNode.AssertExpectations(t)
  649. })
  650. t.Run("ReplacesPrimaryWithWitnessIfPrimaryDoesntHaveBlock", func(t *testing.T) {
  651. ctx, cancel := context.WithCancel(context.Background())
  652. defer cancel()
  653. mockFullNode := &provider_mocks.Provider{}
  654. mockFullNode.On("LightBlock", mock.Anything, mock.Anything).Return(l1, nil)
  655. logger := log.NewTestingLogger(t)
  656. mockDeadNode := &provider_mocks.Provider{}
  657. mockDeadNode.On("LightBlock", mock.Anything, mock.Anything).Return(nil, provider.ErrLightBlockNotFound)
  658. c, err := light.NewClient(
  659. ctx,
  660. chainID,
  661. trustOptions,
  662. mockDeadNode,
  663. []provider.Provider{mockDeadNode, mockFullNode},
  664. dbs.New(dbm.NewMemDB()),
  665. light.Logger(logger),
  666. )
  667. require.NoError(t, err)
  668. _, err = c.Update(ctx, bTime.Add(2*time.Hour))
  669. require.NoError(t, err)
  670. // we should still have the dead node as a witness because it
  671. // hasn't repeatedly been unresponsive yet
  672. assert.Equal(t, 2, len(c.Witnesses()))
  673. mockDeadNode.AssertExpectations(t)
  674. mockFullNode.AssertExpectations(t)
  675. })
  676. t.Run("BackwardsVerification", func(t *testing.T) {
  677. ctx, cancel := context.WithCancel(context.Background())
  678. defer cancel()
  679. logger := log.NewTestingLogger(t)
  680. {
  681. headers, vals, _ := genLightBlocksWithKeys(t, chainID, 9, 3, 0, bTime)
  682. delete(headers, 1)
  683. delete(headers, 2)
  684. delete(vals, 1)
  685. delete(vals, 2)
  686. mockLargeFullNode := mockNodeFromHeadersAndVals(headers, vals)
  687. trustHeader, _ := mockLargeFullNode.LightBlock(ctx, 6)
  688. c, err := light.NewClient(
  689. ctx,
  690. chainID,
  691. light.TrustOptions{
  692. Period: 4 * time.Minute,
  693. Height: trustHeader.Height,
  694. Hash: trustHeader.Hash(),
  695. },
  696. mockLargeFullNode,
  697. []provider.Provider{mockLargeFullNode},
  698. dbs.New(dbm.NewMemDB()),
  699. light.Logger(logger),
  700. )
  701. require.NoError(t, err)
  702. // 1) verify before the trusted header using backwards => expect no error
  703. h, err := c.VerifyLightBlockAtHeight(ctx, 5, bTime.Add(6*time.Minute))
  704. require.NoError(t, err)
  705. if assert.NotNil(t, h) {
  706. assert.EqualValues(t, 5, h.Height)
  707. }
  708. // 2) untrusted header is expired but trusted header is not => expect no error
  709. h, err = c.VerifyLightBlockAtHeight(ctx, 3, bTime.Add(8*time.Minute))
  710. assert.NoError(t, err)
  711. assert.NotNil(t, h)
  712. // 3) already stored headers should return the header without error
  713. h, err = c.VerifyLightBlockAtHeight(ctx, 5, bTime.Add(6*time.Minute))
  714. assert.NoError(t, err)
  715. assert.NotNil(t, h)
  716. // 4a) First verify latest header
  717. _, err = c.VerifyLightBlockAtHeight(ctx, 9, bTime.Add(9*time.Minute))
  718. require.NoError(t, err)
  719. // 4b) Verify backwards using bisection => expect no error
  720. _, err = c.VerifyLightBlockAtHeight(ctx, 7, bTime.Add(9*time.Minute))
  721. assert.NoError(t, err)
  722. // shouldn't have verified this header in the process
  723. _, err = c.TrustedLightBlock(8)
  724. assert.Error(t, err)
  725. // 5) Try bisection method, but closest header (at 7) has expired
  726. // so expect error
  727. _, err = c.VerifyLightBlockAtHeight(ctx, 8, bTime.Add(12*time.Minute))
  728. assert.Error(t, err)
  729. mockLargeFullNode.AssertExpectations(t)
  730. }
  731. {
  732. // 8) provides incorrect hash
  733. headers := map[int64]*types.SignedHeader{
  734. 2: keys.GenSignedHeader(t, chainID, 2, bTime.Add(30*time.Minute), nil, vals, vals,
  735. hash("app_hash2"), hash("cons_hash23"), hash("results_hash30"), 0, len(keys)),
  736. 3: h3,
  737. }
  738. vals := valSet
  739. mockNode := mockNodeFromHeadersAndVals(headers, vals)
  740. c, err := light.NewClient(
  741. ctx,
  742. chainID,
  743. light.TrustOptions{
  744. Period: 1 * time.Hour,
  745. Height: 3,
  746. Hash: h3.Hash(),
  747. },
  748. mockNode,
  749. []provider.Provider{mockNode},
  750. dbs.New(dbm.NewMemDB()),
  751. light.Logger(logger),
  752. )
  753. require.NoError(t, err)
  754. _, err = c.VerifyLightBlockAtHeight(ctx, 2, bTime.Add(1*time.Hour).Add(1*time.Second))
  755. assert.Error(t, err)
  756. mockNode.AssertExpectations(t)
  757. }
  758. })
  759. t.Run("NewClientFromTrustedStore", func(t *testing.T) {
  760. // 1) Initiate DB and fill with a "trusted" header
  761. db := dbs.New(dbm.NewMemDB())
  762. err := db.SaveLightBlock(l1)
  763. require.NoError(t, err)
  764. mockNode := &provider_mocks.Provider{}
  765. c, err := light.NewClientFromTrustedStore(
  766. chainID,
  767. trustPeriod,
  768. mockNode,
  769. []provider.Provider{mockNode},
  770. db,
  771. )
  772. require.NoError(t, err)
  773. // 2) Check light block exists
  774. h, err := c.TrustedLightBlock(1)
  775. assert.NoError(t, err)
  776. assert.EqualValues(t, l1.Height, h.Height)
  777. mockNode.AssertExpectations(t)
  778. })
  779. t.Run("RemovesWitnessIfItSendsUsIncorrectHeader", func(t *testing.T) {
  780. logger := log.NewTestingLogger(t)
  781. // different headers hash then primary plus less than 1/3 signed (no fork)
  782. headers1 := map[int64]*types.SignedHeader{
  783. 1: h1,
  784. 2: keys.GenSignedHeaderLastBlockID(t, chainID, 2, bTime.Add(30*time.Minute), nil, vals, vals,
  785. hash("app_hash2"), hash("cons_hash"), hash("results_hash"),
  786. len(keys), len(keys), types.BlockID{Hash: h1.Hash()}),
  787. }
  788. vals1 := map[int64]*types.ValidatorSet{
  789. 1: vals,
  790. 2: vals,
  791. }
  792. mockBadNode1 := mockNodeFromHeadersAndVals(headers1, vals1)
  793. mockBadNode1.On("LightBlock", mock.Anything, mock.Anything).Return(nil, provider.ErrLightBlockNotFound)
  794. // header is empty
  795. headers2 := map[int64]*types.SignedHeader{
  796. 1: h1,
  797. 2: h2,
  798. }
  799. vals2 := map[int64]*types.ValidatorSet{
  800. 1: vals,
  801. 2: vals,
  802. }
  803. mockBadNode2 := mockNodeFromHeadersAndVals(headers2, vals2)
  804. mockBadNode2.On("LightBlock", mock.Anything, mock.Anything).Return(nil, provider.ErrLightBlockNotFound)
  805. mockFullNode := mockNodeFromHeadersAndVals(headerSet, valSet)
  806. ctx, cancel := context.WithCancel(context.Background())
  807. defer cancel()
  808. lb1, _ := mockBadNode1.LightBlock(ctx, 2)
  809. require.NotEqual(t, lb1.Hash(), l1.Hash())
  810. c, err := light.NewClient(
  811. ctx,
  812. chainID,
  813. trustOptions,
  814. mockFullNode,
  815. []provider.Provider{mockBadNode1, mockBadNode2},
  816. dbs.New(dbm.NewMemDB()),
  817. light.Logger(logger),
  818. )
  819. // witness should have behaved properly -> no error
  820. require.NoError(t, err)
  821. assert.EqualValues(t, 2, len(c.Witnesses()))
  822. // witness behaves incorrectly -> removed from list, no error
  823. l, err := c.VerifyLightBlockAtHeight(ctx, 2, bTime.Add(2*time.Hour))
  824. assert.NoError(t, err)
  825. assert.EqualValues(t, 1, len(c.Witnesses()))
  826. // light block should still be verified
  827. assert.EqualValues(t, 2, l.Height)
  828. // remaining witnesses don't have light block -> error
  829. _, err = c.VerifyLightBlockAtHeight(ctx, 3, bTime.Add(2*time.Hour))
  830. if assert.Error(t, err) {
  831. assert.Equal(t, light.ErrFailedHeaderCrossReferencing, err)
  832. }
  833. // witness does not have a light block -> left in the list
  834. assert.EqualValues(t, 1, len(c.Witnesses()))
  835. mockBadNode1.AssertExpectations(t)
  836. mockBadNode2.AssertExpectations(t)
  837. })
  838. t.Run("TrustedValidatorSet", func(t *testing.T) {
  839. ctx, cancel := context.WithCancel(context.Background())
  840. defer cancel()
  841. logger := log.NewTestingLogger(t)
  842. differentVals, _ := factory.RandValidatorSet(ctx, t, 10, 100)
  843. mockBadValSetNode := mockNodeFromHeadersAndVals(
  844. map[int64]*types.SignedHeader{
  845. 1: h1,
  846. // 3/3 signed, but validator set at height 2 below is invalid -> witness
  847. // should be removed.
  848. 2: keys.GenSignedHeaderLastBlockID(t, chainID, 2, bTime.Add(30*time.Minute), nil, vals, vals,
  849. hash("app_hash2"), hash("cons_hash"), hash("results_hash"),
  850. 0, len(keys), types.BlockID{Hash: h1.Hash()}),
  851. },
  852. map[int64]*types.ValidatorSet{
  853. 1: vals,
  854. 2: differentVals,
  855. })
  856. mockFullNode := mockNodeFromHeadersAndVals(
  857. map[int64]*types.SignedHeader{
  858. 1: h1,
  859. 2: h2,
  860. },
  861. map[int64]*types.ValidatorSet{
  862. 1: vals,
  863. 2: vals,
  864. })
  865. c, err := light.NewClient(
  866. ctx,
  867. chainID,
  868. trustOptions,
  869. mockFullNode,
  870. []provider.Provider{mockBadValSetNode, mockFullNode},
  871. dbs.New(dbm.NewMemDB()),
  872. light.Logger(logger),
  873. )
  874. require.NoError(t, err)
  875. assert.Equal(t, 2, len(c.Witnesses()))
  876. _, err = c.VerifyLightBlockAtHeight(ctx, 2, bTime.Add(2*time.Hour).Add(1*time.Second))
  877. assert.NoError(t, err)
  878. assert.Equal(t, 1, len(c.Witnesses()))
  879. mockBadValSetNode.AssertExpectations(t)
  880. mockFullNode.AssertExpectations(t)
  881. })
  882. t.Run("PrunesHeadersAndValidatorSets", func(t *testing.T) {
  883. mockFullNode := mockNodeFromHeadersAndVals(
  884. map[int64]*types.SignedHeader{
  885. 1: h1,
  886. 3: h3,
  887. 0: h3,
  888. },
  889. map[int64]*types.ValidatorSet{
  890. 1: vals,
  891. 3: vals,
  892. 0: vals,
  893. })
  894. ctx, cancel := context.WithCancel(context.Background())
  895. defer cancel()
  896. logger := log.NewTestingLogger(t)
  897. c, err := light.NewClient(
  898. ctx,
  899. chainID,
  900. trustOptions,
  901. mockFullNode,
  902. []provider.Provider{mockFullNode},
  903. dbs.New(dbm.NewMemDB()),
  904. light.Logger(logger),
  905. light.PruningSize(1),
  906. )
  907. require.NoError(t, err)
  908. _, err = c.TrustedLightBlock(1)
  909. require.NoError(t, err)
  910. h, err := c.Update(ctx, bTime.Add(2*time.Hour))
  911. require.NoError(t, err)
  912. require.Equal(t, int64(3), h.Height)
  913. _, err = c.TrustedLightBlock(1)
  914. assert.Error(t, err)
  915. mockFullNode.AssertExpectations(t)
  916. })
  917. t.Run("EnsureValidHeadersAndValSets", func(t *testing.T) {
  918. emptyValSet := &types.ValidatorSet{
  919. Validators: nil,
  920. Proposer: nil,
  921. }
  922. testCases := []struct {
  923. headers map[int64]*types.SignedHeader
  924. vals map[int64]*types.ValidatorSet
  925. errorToThrow error
  926. errorHeight int64
  927. err bool
  928. }{
  929. {
  930. headers: map[int64]*types.SignedHeader{
  931. 1: h1,
  932. 3: h3,
  933. },
  934. vals: map[int64]*types.ValidatorSet{
  935. 1: vals,
  936. 3: vals,
  937. },
  938. err: false,
  939. },
  940. {
  941. headers: map[int64]*types.SignedHeader{
  942. 1: h1,
  943. },
  944. vals: map[int64]*types.ValidatorSet{
  945. 1: vals,
  946. },
  947. errorToThrow: provider.ErrBadLightBlock{Reason: errors.New("nil header or vals")},
  948. errorHeight: 3,
  949. err: true,
  950. },
  951. {
  952. headers: map[int64]*types.SignedHeader{
  953. 1: h1,
  954. },
  955. errorToThrow: provider.ErrBadLightBlock{Reason: errors.New("nil header or vals")},
  956. errorHeight: 3,
  957. vals: valSet,
  958. err: true,
  959. },
  960. {
  961. headers: map[int64]*types.SignedHeader{
  962. 1: h1,
  963. 3: h3,
  964. },
  965. vals: map[int64]*types.ValidatorSet{
  966. 1: vals,
  967. 3: emptyValSet,
  968. },
  969. err: true,
  970. },
  971. }
  972. for i, tc := range testCases {
  973. testCase := tc
  974. t.Run(fmt.Sprintf("case: %d", i), func(t *testing.T) {
  975. ctx, cancel := context.WithCancel(context.Background())
  976. defer cancel()
  977. mockBadNode := mockNodeFromHeadersAndVals(testCase.headers, testCase.vals)
  978. if testCase.errorToThrow != nil {
  979. mockBadNode.On("LightBlock", mock.Anything, testCase.errorHeight).Return(nil, testCase.errorToThrow)
  980. }
  981. c, err := light.NewClient(
  982. ctx,
  983. chainID,
  984. trustOptions,
  985. mockBadNode,
  986. []provider.Provider{mockBadNode, mockBadNode},
  987. dbs.New(dbm.NewMemDB()),
  988. )
  989. require.NoError(t, err)
  990. _, err = c.VerifyLightBlockAtHeight(ctx, 3, bTime.Add(2*time.Hour))
  991. if testCase.err {
  992. assert.Error(t, err)
  993. } else {
  994. assert.NoError(t, err)
  995. }
  996. mockBadNode.AssertExpectations(t)
  997. })
  998. }
  999. })
  1000. }