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.

661 lines
17 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
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
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
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
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
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
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 lite
  2. import (
  3. "testing"
  4. "time"
  5. "github.com/stretchr/testify/assert"
  6. "github.com/stretchr/testify/require"
  7. dbm "github.com/tendermint/tm-db"
  8. "github.com/tendermint/tendermint/libs/log"
  9. mockp "github.com/tendermint/tendermint/lite2/provider/mock"
  10. dbs "github.com/tendermint/tendermint/lite2/store/db"
  11. "github.com/tendermint/tendermint/types"
  12. )
  13. func TestClient_SequentialVerification(t *testing.T) {
  14. const (
  15. chainID = "sequential-verification"
  16. )
  17. var (
  18. keys = genPrivKeys(4)
  19. // 20, 30, 40, 50 - the first 3 don't have 2/3, the last 3 do!
  20. vals = keys.ToValidators(20, 10)
  21. bTime, _ = time.Parse(time.RFC3339, "2006-01-02T15:04:05Z")
  22. header = keys.GenSignedHeader(chainID, 1, bTime, nil, vals, vals,
  23. []byte("app_hash"), []byte("cons_hash"), []byte("results_hash"), 0, len(keys))
  24. )
  25. testCases := []struct {
  26. otherHeaders map[int64]*types.SignedHeader // all except ^
  27. vals map[int64]*types.ValidatorSet
  28. initErr bool
  29. verifyErr bool
  30. }{
  31. // good
  32. {
  33. map[int64]*types.SignedHeader{
  34. // trusted header
  35. 1: header,
  36. // interim header (3/3 signed)
  37. 2: keys.GenSignedHeader(chainID, 2, bTime.Add(1*time.Hour), nil, vals, vals,
  38. []byte("app_hash"), []byte("cons_hash"), []byte("results_hash"), 0, len(keys)),
  39. // last header (3/3 signed)
  40. 3: keys.GenSignedHeader(chainID, 3, bTime.Add(2*time.Hour), nil, vals, vals,
  41. []byte("app_hash"), []byte("cons_hash"), []byte("results_hash"), 0, len(keys)),
  42. },
  43. map[int64]*types.ValidatorSet{
  44. 1: vals,
  45. 2: vals,
  46. 3: vals,
  47. 4: vals,
  48. },
  49. false,
  50. false,
  51. },
  52. // bad: different first header
  53. {
  54. map[int64]*types.SignedHeader{
  55. // different header
  56. 1: keys.GenSignedHeader(chainID, 1, bTime.Add(1*time.Hour), nil, vals, vals,
  57. []byte("app_hash"), []byte("cons_hash"), []byte("results_hash"), 0, len(keys)),
  58. },
  59. map[int64]*types.ValidatorSet{
  60. 1: vals,
  61. },
  62. true,
  63. false,
  64. },
  65. // bad: 1/3 signed interim header
  66. {
  67. map[int64]*types.SignedHeader{
  68. // trusted header
  69. 1: header,
  70. // interim header (1/3 signed)
  71. 2: keys.GenSignedHeader(chainID, 2, bTime.Add(1*time.Hour), nil, vals, vals,
  72. []byte("app_hash"), []byte("cons_hash"), []byte("results_hash"), len(keys)-1, len(keys)),
  73. // last header (3/3 signed)
  74. 3: keys.GenSignedHeader(chainID, 3, bTime.Add(2*time.Hour), nil, vals, vals,
  75. []byte("app_hash"), []byte("cons_hash"), []byte("results_hash"), 0, len(keys)),
  76. },
  77. map[int64]*types.ValidatorSet{
  78. 1: vals,
  79. 2: vals,
  80. 3: vals,
  81. 4: vals,
  82. },
  83. false,
  84. true,
  85. },
  86. // bad: 1/3 signed last header
  87. {
  88. map[int64]*types.SignedHeader{
  89. // trusted header
  90. 1: header,
  91. // interim header (3/3 signed)
  92. 2: keys.GenSignedHeader(chainID, 2, bTime.Add(1*time.Hour), nil, vals, vals,
  93. []byte("app_hash"), []byte("cons_hash"), []byte("results_hash"), 0, len(keys)),
  94. // last header (1/3 signed)
  95. 3: keys.GenSignedHeader(chainID, 3, bTime.Add(2*time.Hour), nil, vals, vals,
  96. []byte("app_hash"), []byte("cons_hash"), []byte("results_hash"), len(keys)-1, len(keys)),
  97. },
  98. map[int64]*types.ValidatorSet{
  99. 1: vals,
  100. 2: vals,
  101. 3: vals,
  102. 4: vals,
  103. },
  104. false,
  105. true,
  106. },
  107. }
  108. for _, tc := range testCases {
  109. c, err := NewClient(
  110. chainID,
  111. TrustOptions{
  112. Period: 4 * time.Hour,
  113. Height: 1,
  114. Hash: header.Hash(),
  115. },
  116. mockp.New(
  117. chainID,
  118. tc.otherHeaders,
  119. tc.vals,
  120. ),
  121. dbs.New(dbm.NewMemDB(), chainID),
  122. SequentialVerification(),
  123. )
  124. if tc.initErr {
  125. require.Error(t, err)
  126. continue
  127. } else {
  128. require.NoError(t, err)
  129. }
  130. defer c.Stop()
  131. _, err = c.VerifyHeaderAtHeight(3, bTime.Add(3*time.Hour))
  132. if tc.verifyErr {
  133. assert.Error(t, err)
  134. } else {
  135. assert.NoError(t, err)
  136. }
  137. }
  138. }
  139. func TestClient_SkippingVerification(t *testing.T) {
  140. const (
  141. chainID = "skipping-verification"
  142. )
  143. var (
  144. keys = genPrivKeys(4)
  145. // 20, 30, 40, 50 - the first 3 don't have 2/3, the last 3 do!
  146. vals = keys.ToValidators(20, 10)
  147. bTime, _ = time.Parse(time.RFC3339, "2006-01-02T15:04:05Z")
  148. header = keys.GenSignedHeader(chainID, 1, bTime, nil, vals, vals,
  149. []byte("app_hash"), []byte("cons_hash"), []byte("results_hash"), 0, len(keys))
  150. )
  151. // required for 2nd test case
  152. newKeys := genPrivKeys(4)
  153. newVals := newKeys.ToValidators(10, 1)
  154. testCases := []struct {
  155. otherHeaders map[int64]*types.SignedHeader // all except ^
  156. vals map[int64]*types.ValidatorSet
  157. initErr bool
  158. verifyErr bool
  159. }{
  160. // good
  161. {
  162. map[int64]*types.SignedHeader{
  163. // trusted header
  164. 1: header,
  165. // last header (3/3 signed)
  166. 3: keys.GenSignedHeader(chainID, 3, bTime.Add(2*time.Hour), nil, vals, vals,
  167. []byte("app_hash"), []byte("cons_hash"), []byte("results_hash"), 0, len(keys)),
  168. },
  169. map[int64]*types.ValidatorSet{
  170. 1: vals,
  171. 2: vals,
  172. 3: vals,
  173. 4: vals,
  174. },
  175. false,
  176. false,
  177. },
  178. // good, val set changes 100% at height 2
  179. {
  180. map[int64]*types.SignedHeader{
  181. // trusted header
  182. 1: header,
  183. // interim header (3/3 signed)
  184. 2: keys.GenSignedHeader(chainID, 2, bTime.Add(1*time.Hour), nil, vals, newVals,
  185. []byte("app_hash"), []byte("cons_hash"), []byte("results_hash"), 0, len(keys)),
  186. // last header (0/4 of the original val set signed)
  187. 3: newKeys.GenSignedHeader(chainID, 3, bTime.Add(2*time.Hour), nil, newVals, newVals,
  188. []byte("app_hash"), []byte("cons_hash"), []byte("results_hash"), 0, len(newKeys)),
  189. },
  190. map[int64]*types.ValidatorSet{
  191. 1: vals,
  192. 2: vals,
  193. 3: newVals,
  194. 4: newVals,
  195. },
  196. false,
  197. false,
  198. },
  199. }
  200. for _, tc := range testCases {
  201. c, err := NewClient(
  202. chainID,
  203. TrustOptions{
  204. Period: 4 * time.Hour,
  205. Height: 1,
  206. Hash: header.Hash(),
  207. },
  208. mockp.New(
  209. chainID,
  210. tc.otherHeaders,
  211. tc.vals,
  212. ),
  213. dbs.New(dbm.NewMemDB(), chainID),
  214. SkippingVerification(DefaultTrustLevel),
  215. )
  216. if tc.initErr {
  217. require.Error(t, err)
  218. continue
  219. } else {
  220. require.NoError(t, err)
  221. }
  222. defer c.Stop()
  223. _, err = c.VerifyHeaderAtHeight(3, bTime.Add(3*time.Hour))
  224. if tc.verifyErr {
  225. assert.Error(t, err)
  226. } else {
  227. assert.NoError(t, err)
  228. }
  229. }
  230. }
  231. func TestClientRemovesNoLongerTrustedHeaders(t *testing.T) {
  232. const (
  233. chainID = "TestClientRemovesNoLongerTrustedHeaders"
  234. )
  235. var (
  236. keys = genPrivKeys(4)
  237. // 20, 30, 40, 50 - the first 3 don't have 2/3, the last 3 do!
  238. vals = keys.ToValidators(20, 10)
  239. bTime, _ = time.Parse(time.RFC3339, "2006-01-02T15:04:05Z")
  240. header = keys.GenSignedHeader(chainID, 1, bTime, nil, vals, vals,
  241. []byte("app_hash"), []byte("cons_hash"), []byte("results_hash"), 0, len(keys))
  242. )
  243. c, err := NewClient(
  244. chainID,
  245. TrustOptions{
  246. Period: 4 * time.Hour,
  247. Height: 1,
  248. Hash: header.Hash(),
  249. },
  250. mockp.New(
  251. chainID,
  252. map[int64]*types.SignedHeader{
  253. // trusted header
  254. 1: header,
  255. // interim header (3/3 signed)
  256. 2: keys.GenSignedHeader(chainID, 2, bTime.Add(2*time.Hour), nil, vals, vals,
  257. []byte("app_hash"), []byte("cons_hash"), []byte("results_hash"), 0, len(keys)),
  258. // last header (3/3 signed)
  259. 3: keys.GenSignedHeader(chainID, 3, bTime.Add(4*time.Hour), nil, vals, vals,
  260. []byte("app_hash"), []byte("cons_hash"), []byte("results_hash"), 0, len(keys)),
  261. },
  262. map[int64]*types.ValidatorSet{
  263. 1: vals,
  264. 2: vals,
  265. 3: vals,
  266. 4: vals,
  267. },
  268. ),
  269. dbs.New(dbm.NewMemDB(), chainID),
  270. )
  271. require.NoError(t, err)
  272. defer c.Stop()
  273. c.SetLogger(log.TestingLogger())
  274. // Verify new headers.
  275. _, err = c.VerifyHeaderAtHeight(2, bTime.Add(2*time.Hour).Add(1*time.Second))
  276. require.NoError(t, err)
  277. now := bTime.Add(4 * time.Hour).Add(1 * time.Second)
  278. _, err = c.VerifyHeaderAtHeight(3, now)
  279. require.NoError(t, err)
  280. // Remove expired headers.
  281. c.RemoveNoLongerTrustedHeaders(now)
  282. // Check expired headers are no longer available.
  283. h, err := c.TrustedHeader(1, now)
  284. assert.NoError(t, err)
  285. assert.Nil(t, h)
  286. // Check not expired headers are available.
  287. h, err = c.TrustedHeader(2, now)
  288. assert.NoError(t, err)
  289. assert.NotNil(t, h)
  290. }
  291. func TestClient_Cleanup(t *testing.T) {
  292. const (
  293. chainID = "TestClient_Cleanup"
  294. )
  295. var (
  296. keys = genPrivKeys(4)
  297. // 20, 30, 40, 50 - the first 3 don't have 2/3, the last 3 do!
  298. vals = keys.ToValidators(20, 10)
  299. bTime, _ = time.Parse(time.RFC3339, "2006-01-02T15:04:05Z")
  300. header = keys.GenSignedHeader(chainID, 1, bTime, nil, vals, vals,
  301. []byte("app_hash"), []byte("cons_hash"), []byte("results_hash"), 0, len(keys))
  302. )
  303. c, err := NewClient(
  304. chainID,
  305. TrustOptions{
  306. Period: 4 * time.Hour,
  307. Height: 1,
  308. Hash: header.Hash(),
  309. },
  310. mockp.New(
  311. chainID,
  312. map[int64]*types.SignedHeader{
  313. // trusted header
  314. 1: header,
  315. },
  316. map[int64]*types.ValidatorSet{
  317. 1: vals,
  318. 2: vals,
  319. },
  320. ),
  321. dbs.New(dbm.NewMemDB(), chainID),
  322. )
  323. require.NoError(t, err)
  324. c.SetLogger(log.TestingLogger())
  325. c.Cleanup()
  326. // Check no headers exist after Cleanup.
  327. h, err := c.TrustedHeader(1, bTime.Add(1*time.Second))
  328. assert.NoError(t, err)
  329. assert.Nil(t, h)
  330. }
  331. // trustedHeader.Height == options.Height
  332. func TestClientRestoreTrustedHeaderAfterStartup1(t *testing.T) {
  333. const (
  334. chainID = "TestClientRestoreTrustedHeaderAfterStartup1"
  335. )
  336. var (
  337. keys = genPrivKeys(4)
  338. // 20, 30, 40, 50 - the first 3 don't have 2/3, the last 3 do!
  339. vals = keys.ToValidators(20, 10)
  340. bTime, _ = time.Parse(time.RFC3339, "2006-01-02T15:04:05Z")
  341. header = keys.GenSignedHeader(chainID, 1, bTime, nil, vals, vals,
  342. []byte("app_hash"), []byte("cons_hash"), []byte("results_hash"), 0, len(keys))
  343. )
  344. // 1. options.Hash == trustedHeader.Hash
  345. {
  346. trustedStore := dbs.New(dbm.NewMemDB(), chainID)
  347. err := trustedStore.SaveSignedHeaderAndNextValidatorSet(header, vals)
  348. require.NoError(t, err)
  349. c, err := NewClient(
  350. chainID,
  351. TrustOptions{
  352. Period: 4 * time.Hour,
  353. Height: 1,
  354. Hash: header.Hash(),
  355. },
  356. mockp.New(
  357. chainID,
  358. map[int64]*types.SignedHeader{
  359. // trusted header
  360. 1: header,
  361. },
  362. map[int64]*types.ValidatorSet{
  363. 1: vals,
  364. 2: vals,
  365. },
  366. ),
  367. trustedStore,
  368. )
  369. require.NoError(t, err)
  370. c.SetLogger(log.TestingLogger())
  371. h, err := c.TrustedHeader(1, bTime.Add(1*time.Second))
  372. assert.NoError(t, err)
  373. assert.NotNil(t, h)
  374. assert.Equal(t, h.Hash(), header.Hash())
  375. }
  376. // 2. options.Hash != trustedHeader.Hash
  377. {
  378. trustedStore := dbs.New(dbm.NewMemDB(), chainID)
  379. err := trustedStore.SaveSignedHeaderAndNextValidatorSet(header, vals)
  380. require.NoError(t, err)
  381. // header1 != header
  382. header1 := keys.GenSignedHeader(chainID, 1, bTime.Add(1*time.Hour), nil, vals, vals,
  383. []byte("app_hash"), []byte("cons_hash"), []byte("results_hash"), 0, len(keys))
  384. c, err := NewClient(
  385. chainID,
  386. TrustOptions{
  387. Period: 4 * time.Hour,
  388. Height: 1,
  389. Hash: header1.Hash(),
  390. },
  391. mockp.New(
  392. chainID,
  393. map[int64]*types.SignedHeader{
  394. // trusted header
  395. 1: header1,
  396. },
  397. map[int64]*types.ValidatorSet{
  398. 1: vals,
  399. 2: vals,
  400. },
  401. ),
  402. trustedStore,
  403. )
  404. require.NoError(t, err)
  405. c.SetLogger(log.TestingLogger())
  406. h, err := c.TrustedHeader(1, bTime.Add(1*time.Second))
  407. assert.NoError(t, err)
  408. assert.NotNil(t, h)
  409. assert.Equal(t, h.Hash(), header1.Hash())
  410. }
  411. }
  412. // trustedHeader.Height < options.Height
  413. func TestClientRestoreTrustedHeaderAfterStartup2(t *testing.T) {
  414. const (
  415. chainID = "TestClientRestoreTrustedHeaderAfterStartup2"
  416. )
  417. var (
  418. keys = genPrivKeys(4)
  419. // 20, 30, 40, 50 - the first 3 don't have 2/3, the last 3 do!
  420. vals = keys.ToValidators(20, 10)
  421. bTime, _ = time.Parse(time.RFC3339, "2006-01-02T15:04:05Z")
  422. header = keys.GenSignedHeader(chainID, 1, bTime, nil, vals, vals,
  423. []byte("app_hash"), []byte("cons_hash"), []byte("results_hash"), 0, len(keys))
  424. )
  425. // 1. options.Hash == trustedHeader.Hash
  426. {
  427. trustedStore := dbs.New(dbm.NewMemDB(), chainID)
  428. err := trustedStore.SaveSignedHeaderAndNextValidatorSet(header, vals)
  429. require.NoError(t, err)
  430. header2 := keys.GenSignedHeader(chainID, 2, bTime.Add(2*time.Hour), nil, vals, vals,
  431. []byte("app_hash"), []byte("cons_hash"), []byte("results_hash"), 0, len(keys))
  432. c, err := NewClient(
  433. chainID,
  434. TrustOptions{
  435. Period: 4 * time.Hour,
  436. Height: 2,
  437. Hash: header2.Hash(),
  438. },
  439. mockp.New(
  440. chainID,
  441. map[int64]*types.SignedHeader{
  442. 1: header,
  443. 2: header2,
  444. },
  445. map[int64]*types.ValidatorSet{
  446. 1: vals,
  447. 2: vals,
  448. 3: vals,
  449. },
  450. ),
  451. trustedStore,
  452. )
  453. require.NoError(t, err)
  454. c.SetLogger(log.TestingLogger())
  455. // Check we still have the 1st header (+header+).
  456. h, err := c.TrustedHeader(1, bTime.Add(2*time.Hour).Add(1*time.Second))
  457. assert.NoError(t, err)
  458. assert.NotNil(t, h)
  459. assert.Equal(t, h.Hash(), header.Hash())
  460. }
  461. // 2. options.Hash != trustedHeader.Hash
  462. // This could happen if previous provider was lying to us.
  463. {
  464. trustedStore := dbs.New(dbm.NewMemDB(), chainID)
  465. err := trustedStore.SaveSignedHeaderAndNextValidatorSet(header, vals)
  466. require.NoError(t, err)
  467. // header1 != header
  468. header1 := keys.GenSignedHeader(chainID, 1, bTime.Add(1*time.Hour), nil, vals, vals,
  469. []byte("app_hash"), []byte("cons_hash"), []byte("results_hash"), 0, len(keys))
  470. header2 := keys.GenSignedHeader(chainID, 2, bTime.Add(2*time.Hour), nil, vals, vals,
  471. []byte("app_hash"), []byte("cons_hash"), []byte("results_hash"), 0, len(keys))
  472. c, err := NewClient(
  473. chainID,
  474. TrustOptions{
  475. Period: 4 * time.Hour,
  476. Height: 2,
  477. Hash: header2.Hash(),
  478. },
  479. mockp.New(
  480. chainID,
  481. map[int64]*types.SignedHeader{
  482. 1: header1,
  483. 2: header2,
  484. },
  485. map[int64]*types.ValidatorSet{
  486. 1: vals,
  487. 2: vals,
  488. 3: vals,
  489. },
  490. ),
  491. trustedStore,
  492. )
  493. require.NoError(t, err)
  494. c.SetLogger(log.TestingLogger())
  495. // Check we no longer have the invalid 1st header (+header+).
  496. h, err := c.TrustedHeader(1, bTime.Add(2*time.Hour).Add(1*time.Second))
  497. assert.NoError(t, err)
  498. assert.Nil(t, h)
  499. }
  500. }
  501. // trustedHeader.Height > options.Height
  502. func TestClientRestoreTrustedHeaderAfterStartup3(t *testing.T) {
  503. const (
  504. chainID = "TestClientRestoreTrustedHeaderAfterStartup3"
  505. )
  506. var (
  507. keys = genPrivKeys(4)
  508. // 20, 30, 40, 50 - the first 3 don't have 2/3, the last 3 do!
  509. vals = keys.ToValidators(20, 10)
  510. bTime, _ = time.Parse(time.RFC3339, "2006-01-02T15:04:05Z")
  511. header = keys.GenSignedHeader(chainID, 1, bTime, nil, vals, vals,
  512. []byte("app_hash"), []byte("cons_hash"), []byte("results_hash"), 0, len(keys))
  513. )
  514. // 1. options.Hash == trustedHeader.Hash
  515. {
  516. trustedStore := dbs.New(dbm.NewMemDB(), chainID)
  517. err := trustedStore.SaveSignedHeaderAndNextValidatorSet(header, vals)
  518. require.NoError(t, err)
  519. header2 := keys.GenSignedHeader(chainID, 2, bTime.Add(2*time.Hour), nil, vals, vals,
  520. []byte("app_hash"), []byte("cons_hash"), []byte("results_hash"), 0, len(keys))
  521. err = trustedStore.SaveSignedHeaderAndNextValidatorSet(header2, vals)
  522. require.NoError(t, err)
  523. c, err := NewClient(
  524. chainID,
  525. TrustOptions{
  526. Period: 4 * time.Hour,
  527. Height: 1,
  528. Hash: header.Hash(),
  529. },
  530. mockp.New(
  531. chainID,
  532. map[int64]*types.SignedHeader{
  533. 1: header,
  534. 2: header2,
  535. },
  536. map[int64]*types.ValidatorSet{
  537. 1: vals,
  538. 2: vals,
  539. 3: vals,
  540. },
  541. ),
  542. trustedStore,
  543. )
  544. require.NoError(t, err)
  545. c.SetLogger(log.TestingLogger())
  546. // Check we still have the 1st header (+header+).
  547. h, err := c.TrustedHeader(1, bTime.Add(2*time.Hour).Add(1*time.Second))
  548. assert.NoError(t, err)
  549. assert.NotNil(t, h)
  550. assert.Equal(t, h.Hash(), header.Hash())
  551. // Check we no longer have 2nd header (+header2+).
  552. h, err = c.TrustedHeader(2, bTime.Add(2*time.Hour).Add(1*time.Second))
  553. assert.NoError(t, err)
  554. assert.Nil(t, h)
  555. }
  556. // 2. options.Hash != trustedHeader.Hash
  557. // This could happen if previous provider was lying to us.
  558. {
  559. trustedStore := dbs.New(dbm.NewMemDB(), chainID)
  560. err := trustedStore.SaveSignedHeaderAndNextValidatorSet(header, vals)
  561. require.NoError(t, err)
  562. // header1 != header
  563. header1 := keys.GenSignedHeader(chainID, 1, bTime.Add(1*time.Hour), nil, vals, vals,
  564. []byte("app_hash"), []byte("cons_hash"), []byte("results_hash"), 0, len(keys))
  565. header2 := keys.GenSignedHeader(chainID, 2, bTime.Add(2*time.Hour), nil, vals, vals,
  566. []byte("app_hash"), []byte("cons_hash"), []byte("results_hash"), 0, len(keys))
  567. err = trustedStore.SaveSignedHeaderAndNextValidatorSet(header2, vals)
  568. require.NoError(t, err)
  569. c, err := NewClient(
  570. chainID,
  571. TrustOptions{
  572. Period: 4 * time.Hour,
  573. Height: 1,
  574. Hash: header1.Hash(),
  575. },
  576. mockp.New(
  577. chainID,
  578. map[int64]*types.SignedHeader{
  579. 1: header1,
  580. },
  581. map[int64]*types.ValidatorSet{
  582. 1: vals,
  583. 2: vals,
  584. },
  585. ),
  586. trustedStore,
  587. )
  588. require.NoError(t, err)
  589. c.SetLogger(log.TestingLogger())
  590. // Check we have swapped invalid 1st header (+header+) with correct one (+header1+).
  591. h, err := c.TrustedHeader(1, bTime.Add(2*time.Hour).Add(1*time.Second))
  592. assert.NoError(t, err)
  593. assert.NotNil(t, h)
  594. assert.Equal(t, h.Hash(), header1.Hash())
  595. // Check we no longer have invalid 2nd header (+header2+).
  596. h, err = c.TrustedHeader(2, bTime.Add(2*time.Hour).Add(1*time.Second))
  597. assert.NoError(t, err)
  598. assert.Nil(t, h)
  599. }
  600. }