github.com/fiagdao/tendermint@v0.32.11-0.20220824195748-2087fcc480c1/lite2/client.go (about) 1 package lite 2 3 import ( 4 "bytes" 5 "fmt" 6 "math/rand" 7 "sync" 8 "time" 9 10 "github.com/pkg/errors" 11 12 "github.com/tendermint/tendermint/libs/log" 13 tmmath "github.com/tendermint/tendermint/libs/math" 14 "github.com/tendermint/tendermint/lite2/provider" 15 "github.com/tendermint/tendermint/lite2/store" 16 "github.com/tendermint/tendermint/types" 17 ) 18 19 type mode byte 20 21 const ( 22 sequential mode = iota + 1 23 skipping 24 25 defaultPruningSize = 1000 26 defaultMaxRetryAttempts = 10 27 // For bisection, when using the cache of headers from the previous batch, 28 // they will always be at a height greater than 1/2 (normal bisection) so to 29 // find something in between the range, 9/16 is used. 30 bisectionNumerator = 9 31 bisectionDenominator = 16 32 33 // 10s should cover most of the clients. 34 // References: 35 // - http://vancouver-webpages.com/time/web.html 36 // - https://blog.codinghorror.com/keeping-time-on-the-pc/ 37 defaultMaxClockDrift = 10 * time.Second 38 ) 39 40 // Option sets a parameter for the light client. 41 type Option func(*Client) 42 43 // SequentialVerification option configures the light client to sequentially 44 // check the headers (every header, in ascending height order). Note this is 45 // much slower than SkippingVerification, albeit more secure. 46 func SequentialVerification() Option { 47 return func(c *Client) { 48 c.verificationMode = sequential 49 } 50 } 51 52 // SkippingVerification option configures the light client to skip headers as 53 // long as {trustLevel} of the old validator set signed the new header. The 54 // bisection algorithm from the specification is used for finding the minimal 55 // "trust path". 56 // 57 // trustLevel - fraction of the old validator set (in terms of voting power), 58 // which must sign the new header in order for us to trust it. NOTE this only 59 // applies to non-adjacent headers. For adjacent headers, sequential 60 // verification is used. 61 func SkippingVerification(trustLevel tmmath.Fraction) Option { 62 return func(c *Client) { 63 c.verificationMode = skipping 64 c.trustLevel = trustLevel 65 } 66 } 67 68 // PruningSize option sets the maximum amount of headers & validator set pairs 69 // that the light client stores. When Prune() is run, all headers (along with 70 // the associated validator sets) that are earlier than the h amount of headers 71 // will be removed from the store. Default: 1000. A pruning size of 0 will not 72 // prune the lite client at all. 73 func PruningSize(h uint16) Option { 74 return func(c *Client) { 75 c.pruningSize = h 76 } 77 } 78 79 // ConfirmationFunction option can be used to prompt to confirm an action. For 80 // example, remove newer headers if the light client is being reset with an 81 // older header. No confirmation is required by default! 82 func ConfirmationFunction(fn func(action string) bool) Option { 83 return func(c *Client) { 84 c.confirmationFn = fn 85 } 86 } 87 88 // Logger option can be used to set a logger for the client. 89 func Logger(l log.Logger) Option { 90 return func(c *Client) { 91 c.logger = l 92 } 93 } 94 95 // MaxRetryAttempts option can be used to set max attempts before replacing 96 // primary with a witness. 97 func MaxRetryAttempts(max uint16) Option { 98 return func(c *Client) { 99 c.maxRetryAttempts = max 100 } 101 } 102 103 // MaxClockDrift defines how much new (untrusted) header's Time can drift into 104 // the future. Default: 10s. 105 func MaxClockDrift(d time.Duration) Option { 106 return func(c *Client) { 107 c.maxClockDrift = d 108 } 109 } 110 111 // Client represents a light client, connected to a single chain, which gets 112 // headers from a primary provider, verifies them either sequentially or by 113 // skipping some and stores them in a trusted store (usually, a local FS). 114 // 115 // Default verification: SkippingVerification(DefaultTrustLevel) 116 type Client struct { 117 chainID string 118 trustingPeriod time.Duration // see TrustOptions.Period 119 verificationMode mode 120 trustLevel tmmath.Fraction 121 maxRetryAttempts uint16 // see MaxRetryAttempts option 122 maxClockDrift time.Duration 123 124 // Mutex for locking during changes of the lite clients providers 125 providerMutex sync.Mutex 126 // Primary provider of new headers. 127 primary provider.Provider 128 // See Witnesses option 129 witnesses []provider.Provider 130 131 // Where trusted headers are stored. 132 trustedStore store.Store 133 // Highest trusted header from the store (height=H). 134 latestTrustedHeader *types.SignedHeader 135 // Highest validator set from the store (height=H). 136 latestTrustedVals *types.ValidatorSet 137 138 // See RemoveNoLongerTrustedHeadersPeriod option 139 pruningSize uint16 140 // See ConfirmationFunction option 141 confirmationFn func(action string) bool 142 143 quit chan struct{} 144 145 logger log.Logger 146 } 147 148 // NewClient returns a new light client. It returns an error if it fails to 149 // obtain the header & vals from the primary or they are invalid (e.g. trust 150 // hash does not match with the one from the header). 151 // 152 // Witnesses are providers, which will be used for cross-checking the primary 153 // provider. At least one witness must be given. A witness can become a primary 154 // iff the current primary is unavailable. 155 // 156 // See all Option(s) for the additional configuration. 157 func NewClient( 158 chainID string, 159 trustOptions TrustOptions, 160 primary provider.Provider, 161 witnesses []provider.Provider, 162 trustedStore store.Store, 163 options ...Option) (*Client, error) { 164 165 if err := trustOptions.ValidateBasic(); err != nil { 166 return nil, fmt.Errorf("invalid TrustOptions: %w", err) 167 } 168 169 c, err := NewClientFromTrustedStore(chainID, trustOptions.Period, primary, witnesses, trustedStore, options...) 170 if err != nil { 171 return nil, err 172 } 173 174 if c.latestTrustedHeader != nil { 175 c.logger.Info("Checking trusted header using options") 176 if err := c.checkTrustedHeaderUsingOptions(trustOptions); err != nil { 177 return nil, err 178 } 179 } 180 181 if c.latestTrustedHeader == nil || c.latestTrustedHeader.Height < trustOptions.Height { 182 c.logger.Info("Downloading trusted header using options") 183 if err := c.initializeWithTrustOptions(trustOptions); err != nil { 184 return nil, err 185 } 186 } 187 188 return c, err 189 } 190 191 // NewClientFromTrustedStore initializes existing client from the trusted store. 192 // 193 // See NewClient 194 func NewClientFromTrustedStore( 195 chainID string, 196 trustingPeriod time.Duration, 197 primary provider.Provider, 198 witnesses []provider.Provider, 199 trustedStore store.Store, 200 options ...Option) (*Client, error) { 201 202 c := &Client{ 203 chainID: chainID, 204 trustingPeriod: trustingPeriod, 205 verificationMode: skipping, 206 trustLevel: DefaultTrustLevel, 207 maxRetryAttempts: defaultMaxRetryAttempts, 208 maxClockDrift: defaultMaxClockDrift, 209 primary: primary, 210 witnesses: witnesses, 211 trustedStore: trustedStore, 212 pruningSize: defaultPruningSize, 213 confirmationFn: func(action string) bool { return true }, 214 quit: make(chan struct{}), 215 logger: log.NewNopLogger(), 216 } 217 218 for _, o := range options { 219 o(c) 220 } 221 222 // Validate the number of witnesses. 223 if len(c.witnesses) < 1 { 224 return nil, errNoWitnesses{} 225 } 226 227 // Verify witnesses are all on the same chain. 228 for i, w := range witnesses { 229 if w.ChainID() != chainID { 230 return nil, fmt.Errorf("witness #%d: %v is on another chain %s, expected %s", 231 i, w, w.ChainID(), chainID) 232 } 233 } 234 235 // Validate trust level. 236 if err := ValidateTrustLevel(c.trustLevel); err != nil { 237 return nil, err 238 } 239 240 if err := c.restoreTrustedHeaderAndVals(); err != nil { 241 return nil, err 242 } 243 244 return c, nil 245 } 246 247 // restoreTrustedHeaderAndVals loads trustedHeader and trustedVals from 248 // trustedStore. 249 func (c *Client) restoreTrustedHeaderAndVals() error { 250 lastHeight, err := c.trustedStore.LastSignedHeaderHeight() 251 if err != nil { 252 return fmt.Errorf("can't get last trusted header height: %w", err) 253 } 254 255 if lastHeight > 0 { 256 trustedHeader, err := c.trustedStore.SignedHeader(lastHeight) 257 if err != nil { 258 return fmt.Errorf("can't get last trusted header: %w", err) 259 } 260 261 trustedVals, err := c.trustedStore.ValidatorSet(lastHeight) 262 if err != nil { 263 return fmt.Errorf("can't get last trusted validators: %w", err) 264 } 265 266 c.latestTrustedHeader = trustedHeader 267 c.latestTrustedVals = trustedVals 268 269 c.logger.Info("Restored trusted header and vals", "height", lastHeight) 270 } 271 272 return nil 273 } 274 275 // if options.Height: 276 // 277 // 1) ahead of trustedHeader.Height => fetch header (same height as 278 // trustedHeader) from primary provider and check it's hash matches the 279 // trustedHeader's hash (if not, remove trustedHeader and all the headers 280 // before) 281 // 282 // 2) equals trustedHeader.Height => check options.Hash matches the 283 // trustedHeader's hash (if not, remove trustedHeader and all the headers 284 // before) 285 // 286 // 3) behind trustedHeader.Height => remove all the headers between 287 // options.Height and trustedHeader.Height, update trustedHeader, then 288 // check options.Hash matches the trustedHeader's hash (if not, remove 289 // trustedHeader and all the headers before) 290 // 291 // The intuition here is the user is always right. I.e. if she decides to reset 292 // the light client with an older header, there must be a reason for it. 293 func (c *Client) checkTrustedHeaderUsingOptions(options TrustOptions) error { 294 var primaryHash []byte 295 switch { 296 case options.Height > c.latestTrustedHeader.Height: 297 h, err := c.signedHeaderFromPrimary(c.latestTrustedHeader.Height) 298 if err != nil { 299 return err 300 } 301 primaryHash = h.Hash() 302 case options.Height == c.latestTrustedHeader.Height: 303 primaryHash = options.Hash 304 case options.Height < c.latestTrustedHeader.Height: 305 c.logger.Info("Client initialized with old header (trusted is more recent)", 306 "old", options.Height, 307 "trustedHeight", c.latestTrustedHeader.Height, 308 "trustedHash", hash2str(c.latestTrustedHeader.Hash())) 309 310 action := fmt.Sprintf( 311 "Rollback to %d (%X)? Note this will remove newer headers up to %d (%X)", 312 options.Height, options.Hash, 313 c.latestTrustedHeader.Height, c.latestTrustedHeader.Hash()) 314 if c.confirmationFn(action) { 315 // remove all the headers (options.Height, trustedHeader.Height] 316 err := c.cleanupAfter(options.Height) 317 if err != nil { 318 return fmt.Errorf("cleanupAfter(%d): %w", options.Height, err) 319 } 320 321 c.logger.Info("Rolled back to older header (newer headers were removed)", 322 "old", options.Height) 323 } else { 324 return nil 325 } 326 327 primaryHash = options.Hash 328 } 329 330 if !bytes.Equal(primaryHash, c.latestTrustedHeader.Hash()) { 331 c.logger.Info("Prev. trusted header's hash (h1) doesn't match hash from primary provider (h2)", 332 "h1", hash2str(c.latestTrustedHeader.Hash()), "h2", hash2str(primaryHash)) 333 334 action := fmt.Sprintf( 335 "Prev. trusted header's hash %X doesn't match hash %X from primary provider. Remove all the stored headers?", 336 c.latestTrustedHeader.Hash(), primaryHash) 337 if c.confirmationFn(action) { 338 err := c.Cleanup() 339 if err != nil { 340 return fmt.Errorf("failed to cleanup: %w", err) 341 } 342 } else { 343 return errors.New("refused to remove the stored headers despite hashes mismatch") 344 } 345 } 346 347 return nil 348 } 349 350 // initializeWithTrustOptions fetches the weakly-trusted header and vals from 351 // primary provider. The header is cross-checked with witnesses for additional 352 // security. 353 func (c *Client) initializeWithTrustOptions(options TrustOptions) error { 354 // 1) Fetch and verify the header. 355 h, err := c.signedHeaderFromPrimary(options.Height) 356 if err != nil { 357 return err 358 } 359 360 // NOTE: - Verify func will check if it's expired or not. 361 // - h.Time is not being checked against time.Now() because we don't 362 // want to add yet another argument to NewClient* functions. 363 if err := h.ValidateBasic(c.chainID); err != nil { 364 return err 365 } 366 367 if !bytes.Equal(h.Hash(), options.Hash) { 368 return fmt.Errorf("expected header's hash %X, but got %X", options.Hash, h.Hash()) 369 } 370 371 err = c.compareNewHeaderWithWitnesses(h) 372 if err != nil { 373 return err 374 } 375 376 // 2) Fetch and verify the vals. 377 vals, err := c.validatorSetFromPrimary(options.Height) 378 if err != nil { 379 return err 380 } 381 382 if !bytes.Equal(h.ValidatorsHash, vals.Hash()) { 383 return fmt.Errorf("expected header's validators (%X) to match those that were supplied (%X)", 384 h.ValidatorsHash, 385 vals.Hash(), 386 ) 387 } 388 389 // Ensure that +2/3 of validators signed correctly. 390 err = vals.VerifyCommitLight(c.chainID, h.Commit.BlockID, h.Height, h.Commit) 391 if err != nil { 392 return fmt.Errorf("invalid commit: %w", err) 393 } 394 395 // 3) Persist both of them and continue. 396 return c.updateTrustedHeaderAndVals(h, vals) 397 } 398 399 // TrustedHeader returns a trusted header at the given height (0 - the latest). 400 // 401 // Headers along with validator sets, which can't be trusted anymore, are 402 // removed once a day (can be changed with RemoveNoLongerTrustedHeadersPeriod 403 // option). 404 // . 405 // height must be >= 0. 406 // 407 // It returns an error if: 408 // - there are some issues with the trusted store, although that should not 409 // happen normally; 410 // - negative height is passed; 411 // - header has not been verified yet and is therefore not in the store 412 // 413 // Safe for concurrent use by multiple goroutines. 414 func (c *Client) TrustedHeader(height int64) (*types.SignedHeader, error) { 415 height, err := c.compareWithLatestHeight(height) 416 if err != nil { 417 return nil, err 418 } 419 return c.trustedStore.SignedHeader(height) 420 } 421 422 // TrustedValidatorSet returns a trusted validator set at the given height (0 - 423 // latest). The second return parameter is the height used (useful if 0 was 424 // passed; otherwise can be ignored). 425 // 426 // height must be >= 0. 427 // 428 // Headers along with validator sets are 429 // removed once a day (can be changed with RemoveNoLongerTrustedHeadersPeriod 430 // option). 431 // 432 // Function returns an error if: 433 // - there are some issues with the trusted store, although that should not 434 // happen normally; 435 // - negative height is passed; 436 // - header signed by that validator set has not been verified yet 437 // 438 // Safe for concurrent use by multiple goroutines. 439 func (c *Client) TrustedValidatorSet(height int64) (valSet *types.ValidatorSet, heightUsed int64, err error) { 440 heightUsed, err = c.compareWithLatestHeight(height) 441 if err != nil { 442 return nil, heightUsed, err 443 } 444 valSet, err = c.trustedStore.ValidatorSet(heightUsed) 445 if err != nil { 446 return nil, heightUsed, err 447 } 448 return valSet, heightUsed, err 449 } 450 451 func (c *Client) compareWithLatestHeight(height int64) (int64, error) { 452 latestHeight, err := c.LastTrustedHeight() 453 if err != nil { 454 return 0, fmt.Errorf("can't get last trusted height: %w", err) 455 } 456 if latestHeight == -1 { 457 return 0, errors.New("no headers exist") 458 } 459 460 switch { 461 case height > latestHeight: 462 return 0, fmt.Errorf("unverified header/valset requested (latest: %d)", latestHeight) 463 case height == 0: 464 return latestHeight, nil 465 case height < 0: 466 return 0, errors.New("negative height") 467 } 468 469 return height, nil 470 } 471 472 // VerifyHeaderAtHeight fetches header and validators at the given height 473 // and calls VerifyHeader. It returns header immediately if such exists in 474 // trustedStore (no verification is needed). 475 // 476 // height must be > 0. 477 // 478 // It returns provider.ErrSignedHeaderNotFound if header is not found by 479 // primary. 480 func (c *Client) VerifyHeaderAtHeight(height int64, now time.Time) (*types.SignedHeader, error) { 481 if height <= 0 { 482 return nil, errors.New("negative or zero height") 483 } 484 485 // Check if header already verified. 486 h, err := c.TrustedHeader(height) 487 if err == nil { 488 c.logger.Info("Header has already been verified", "height", height, "hash", hash2str(h.Hash())) 489 // Return already trusted header 490 return h, nil 491 } 492 493 // Request the header and the vals. 494 newHeader, newVals, err := c.fetchHeaderAndValsAtHeight(height) 495 if err != nil { 496 return nil, err 497 } 498 499 return newHeader, c.verifyHeader(newHeader, newVals, now) 500 } 501 502 // VerifyHeader verifies new header against the trusted state. It returns 503 // immediately if newHeader exists in trustedStore (no verification is 504 // needed). Else it performs one of the two types of verification: 505 // 506 // SequentialVerification: verifies that 2/3 of the trusted validator set has 507 // signed the new header. If the headers are not adjacent, **all** intermediate 508 // headers will be requested. Intermediate headers are not saved to database. 509 // 510 // SkippingVerification(trustLevel): verifies that {trustLevel} of the trusted 511 // validator set has signed the new header. If it's not the case and the 512 // headers are not adjacent, bisection is performed and necessary (not all) 513 // intermediate headers will be requested. See the specification for details. 514 // Intermediate headers are not saved to database. 515 // https://github.com/tendermint/spec/blob/master/spec/consensus/light-client.md 516 // 517 // If the header, which is older than the currently trusted header, is 518 // requested and the light client does not have it, VerifyHeader will perform: 519 // a) bisection verification if nearest trusted header is found & not expired 520 // b) backwards verification in all other cases 521 // 522 // It returns ErrOldHeaderExpired if the latest trusted header expired. 523 // 524 // If the primary provides an invalid header (ErrInvalidHeader), it is rejected 525 // and replaced by another provider until all are exhausted. 526 // 527 // If, at any moment, SignedHeader or ValidatorSet are not found by the primary 528 // provider, provider.ErrSignedHeaderNotFound / 529 // provider.ErrValidatorSetNotFound error is returned. 530 func (c *Client) VerifyHeader(newHeader *types.SignedHeader, newVals *types.ValidatorSet, now time.Time) error { 531 if newHeader.Height <= 0 { 532 return errors.New("negative or zero height") 533 } 534 535 // Check if newHeader already verified. 536 h, err := c.TrustedHeader(newHeader.Height) 537 if err == nil { 538 // Make sure it's the same header. 539 if !bytes.Equal(h.Hash(), newHeader.Hash()) { 540 return fmt.Errorf("existing trusted header %X does not match newHeader %X", h.Hash(), newHeader.Hash()) 541 } 542 c.logger.Info("Header has already been verified", 543 "height", newHeader.Height, "hash", hash2str(newHeader.Hash())) 544 return nil 545 } 546 547 return c.verifyHeader(newHeader, newVals, now) 548 } 549 550 func (c *Client) verifyHeader(newHeader *types.SignedHeader, newVals *types.ValidatorSet, now time.Time) error { 551 c.logger.Info("VerifyHeader", "height", newHeader.Height, "hash", hash2str(newHeader.Hash()), 552 "vals", hash2str(newVals.Hash())) 553 554 var err error 555 556 // 1) If going forward, perform either bisection or sequential verification. 557 if newHeader.Height >= c.latestTrustedHeader.Height { 558 switch c.verificationMode { 559 case sequential: 560 err = c.sequence(c.latestTrustedHeader, newHeader, newVals, now) 561 case skipping: 562 err = c.bisection(c.latestTrustedHeader, c.latestTrustedVals, newHeader, newVals, now) 563 default: 564 panic(fmt.Sprintf("Unknown verification mode: %b", c.verificationMode)) 565 } 566 } else { 567 // 2) If verifying before the first trusted header, perform backwards 568 // verification. 569 var ( 570 closestHeader *types.SignedHeader 571 firstHeaderHeight int64 572 ) 573 firstHeaderHeight, err = c.FirstTrustedHeight() 574 if err != nil { 575 return fmt.Errorf("can't get first header height: %w", err) 576 } 577 if newHeader.Height < firstHeaderHeight { 578 closestHeader, err = c.TrustedHeader(firstHeaderHeight) 579 if err != nil { 580 return fmt.Errorf("can't get first signed header: %w", err) 581 } 582 if HeaderExpired(closestHeader, c.trustingPeriod, now) { 583 closestHeader = c.latestTrustedHeader 584 } 585 err = c.backwards(closestHeader, newHeader, now) 586 } else { 587 // 3) OR if between trusted headers where the nearest has not expired, 588 // perform bisection verification, else backwards. 589 closestHeader, err = c.trustedStore.SignedHeaderBefore(newHeader.Height) 590 if err != nil { 591 return fmt.Errorf("can't get signed header before height %d: %w", newHeader.Height, err) 592 } 593 var closestValidatorSet *types.ValidatorSet 594 if c.verificationMode == sequential || HeaderExpired(closestHeader, c.trustingPeriod, now) { 595 err = c.backwards(c.latestTrustedHeader, newHeader, now) 596 } else { 597 closestValidatorSet, _, err = c.TrustedValidatorSet(closestHeader.Height) 598 if err != nil { 599 return fmt.Errorf("can't get validator set at height %d: %w", closestHeader.Height, err) 600 } 601 err = c.bisection(closestHeader, closestValidatorSet, newHeader, newVals, now) 602 } 603 } 604 } 605 if err != nil { 606 c.logger.Error("Can't verify", "err", err) 607 return err 608 } 609 // 4) Compare header with other witnesses 610 if err := c.compareNewHeaderWithWitnesses(newHeader); err != nil { 611 c.logger.Error("Error when comparing new header with witnesses", "err", err) 612 return err 613 } 614 615 // 5) Once verified, save and return 616 return c.updateTrustedHeaderAndVals(newHeader, newVals) 617 } 618 619 // see VerifyHeader 620 func (c *Client) sequence( 621 initiallyTrustedHeader *types.SignedHeader, 622 newHeader *types.SignedHeader, 623 newVals *types.ValidatorSet, 624 now time.Time) error { 625 626 var ( 627 trustedHeader = initiallyTrustedHeader 628 629 interimHeader *types.SignedHeader 630 interimVals *types.ValidatorSet 631 632 err error 633 ) 634 635 for height := initiallyTrustedHeader.Height + 1; height <= newHeader.Height; height++ { 636 // 1) Fetch interim headers and vals if needed. 637 if height == newHeader.Height { // last header 638 interimHeader, interimVals = newHeader, newVals 639 } else { // intermediate headers 640 interimHeader, interimVals, err = c.fetchHeaderAndValsAtHeight(height) 641 if err != nil { 642 return err 643 } 644 } 645 646 // 2) Verify them 647 c.logger.Debug("Verify newHeader against trustedHeader", 648 "trustedHeight", trustedHeader.Height, 649 "trustedHash", hash2str(trustedHeader.Hash()), 650 "newHeight", interimHeader.Height, 651 "newHash", hash2str(interimHeader.Hash())) 652 653 err = VerifyAdjacent(c.chainID, trustedHeader, interimHeader, interimVals, 654 c.trustingPeriod, now, c.maxClockDrift) 655 if err != nil { 656 err = fmt.Errorf("verify adjacent from #%d to #%d failed: %w", 657 trustedHeader.Height, interimHeader.Height, err) 658 659 switch errors.Unwrap(err).(type) { 660 case ErrInvalidHeader: 661 c.logger.Error("primary sent invalid header -> replacing", "err", err) 662 replaceErr := c.replacePrimaryProvider() 663 if replaceErr != nil { 664 c.logger.Error("Can't replace primary", "err", replaceErr) 665 return err // return original error 666 } 667 // attempt to verify header again 668 height-- 669 continue 670 default: 671 return err 672 } 673 } 674 675 // 3) Update trustedHeader 676 trustedHeader = interimHeader 677 } 678 679 return nil 680 } 681 682 // see VerifyHeader 683 // Bisection finds the middle header between a trusted and new header, reiterating the action until it 684 // verifies a header. A cache of headers requested by the primary is kept such that when a 685 // verification is made, and the light client tries again to verify the new header in the middle, 686 // the light client does not need to ask for all the same headers again. 687 func (c *Client) bisection( 688 initiallyTrustedHeader *types.SignedHeader, 689 initiallyTrustedVals *types.ValidatorSet, 690 newHeader *types.SignedHeader, 691 newVals *types.ValidatorSet, 692 now time.Time) error { 693 694 type headerSet struct { 695 sh *types.SignedHeader 696 valSet *types.ValidatorSet 697 } 698 699 var ( 700 headerCache = []headerSet{{newHeader, newVals}} 701 depth = 0 702 703 trustedHeader = initiallyTrustedHeader 704 trustedVals = initiallyTrustedVals 705 ) 706 707 for { 708 c.logger.Debug("Verify newHeader against trustedHeader", 709 "trustedHeight", trustedHeader.Height, 710 "trustedHash", hash2str(trustedHeader.Hash()), 711 "newHeight", headerCache[depth].sh.Height, 712 "newHash", hash2str(headerCache[depth].sh.Hash())) 713 714 err := Verify(c.chainID, trustedHeader, trustedVals, headerCache[depth].sh, headerCache[depth].valSet, 715 c.trustingPeriod, now, c.maxClockDrift, c.trustLevel) 716 switch err.(type) { 717 case nil: 718 // Have we verified the last header 719 if depth == 0 { 720 return nil 721 } 722 // If not, update the lower bound to the previous upper bound 723 trustedHeader, trustedVals = headerCache[depth].sh, headerCache[depth].valSet 724 // Remove the untrusted header at the lower bound in the header cache - it's no longer useful 725 headerCache = headerCache[:depth] 726 // Reset the cache depth so that we start from the upper bound again 727 depth = 0 728 729 case ErrNewValSetCantBeTrusted: 730 // do add another header to the end of the cache 731 if depth == len(headerCache)-1 { 732 pivotHeight := trustedHeader.Height + (headerCache[depth].sh.Height-trustedHeader. 733 Height)*bisectionNumerator/bisectionDenominator 734 interimHeader, interimVals, err := c.fetchHeaderAndValsAtHeight(pivotHeight) 735 if err != nil { 736 return err 737 } 738 headerCache = append(headerCache, headerSet{interimHeader, interimVals}) 739 } 740 depth++ 741 742 case ErrInvalidHeader: 743 c.logger.Error("primary sent invalid header -> replacing", "err", err) 744 replaceErr := c.replacePrimaryProvider() 745 if replaceErr != nil { 746 c.logger.Error("Can't replace primary", "err", replaceErr) 747 // return original error 748 return fmt.Errorf("verify non adjacent from #%d to #%d failed: %w", 749 trustedHeader.Height, headerCache[depth].sh.Height, err) 750 } 751 // attempt to verify the header again 752 continue 753 754 default: 755 return fmt.Errorf("verify non adjacent from #%d to #%d failed: %w", 756 trustedHeader.Height, headerCache[depth].sh.Height, err) 757 } 758 } 759 } 760 761 // LastTrustedHeight returns a last trusted height. -1 and nil are returned if 762 // there are no trusted headers. 763 // 764 // Safe for concurrent use by multiple goroutines. 765 func (c *Client) LastTrustedHeight() (int64, error) { 766 return c.trustedStore.LastSignedHeaderHeight() 767 } 768 769 // FirstTrustedHeight returns a first trusted height. -1 and nil are returned if 770 // there are no trusted headers. 771 // 772 // Safe for concurrent use by multiple goroutines. 773 func (c *Client) FirstTrustedHeight() (int64, error) { 774 return c.trustedStore.FirstSignedHeaderHeight() 775 } 776 777 // ChainID returns the chain ID the light client was configured with. 778 // 779 // Safe for concurrent use by multiple goroutines. 780 func (c *Client) ChainID() string { 781 return c.chainID 782 } 783 784 // Primary returns the primary provider. 785 // 786 // NOTE: provider may be not safe for concurrent access. 787 func (c *Client) Primary() provider.Provider { 788 c.providerMutex.Lock() 789 defer c.providerMutex.Unlock() 790 return c.primary 791 } 792 793 // Witnesses returns the witness providers. 794 // 795 // NOTE: providers may be not safe for concurrent access. 796 func (c *Client) Witnesses() []provider.Provider { 797 c.providerMutex.Lock() 798 defer c.providerMutex.Unlock() 799 return c.witnesses 800 } 801 802 // Cleanup removes all the data (headers and validator sets) stored. Note: the 803 // client must be stopped at this point. 804 func (c *Client) Cleanup() error { 805 c.logger.Info("Removing all the data") 806 c.latestTrustedHeader = nil 807 c.latestTrustedVals = nil 808 return c.trustedStore.Prune(0) 809 } 810 811 // cleanupAfter deletes all headers & validator sets after +height+. It also 812 // resets latestTrustedHeader to the latest header. 813 func (c *Client) cleanupAfter(height int64) error { 814 prevHeight := c.latestTrustedHeader.Height 815 816 for { 817 h, err := c.trustedStore.SignedHeaderBefore(prevHeight) 818 if err == store.ErrSignedHeaderNotFound || (h != nil && h.Height <= height) { 819 break 820 } else if err != nil { 821 return fmt.Errorf("failed to get header before %d: %w", prevHeight, err) 822 } 823 824 err = c.trustedStore.DeleteSignedHeaderAndValidatorSet(h.Height) 825 if err != nil { 826 c.logger.Error("can't remove a trusted header & validator set", "err", err, 827 "height", h.Height) 828 } 829 830 prevHeight = h.Height 831 } 832 833 c.latestTrustedHeader = nil 834 c.latestTrustedVals = nil 835 err := c.restoreTrustedHeaderAndVals() 836 if err != nil { 837 return err 838 } 839 840 return nil 841 } 842 843 func (c *Client) updateTrustedHeaderAndVals(h *types.SignedHeader, vals *types.ValidatorSet) error { 844 if !bytes.Equal(h.ValidatorsHash, vals.Hash()) { 845 return fmt.Errorf("expected validator's hash %X, but got %X", h.ValidatorsHash, vals.Hash()) 846 } 847 848 if err := c.trustedStore.SaveSignedHeaderAndValidatorSet(h, vals); err != nil { 849 return fmt.Errorf("failed to save trusted header: %w", err) 850 } 851 852 if c.pruningSize > 0 { 853 if err := c.trustedStore.Prune(c.pruningSize); err != nil { 854 return fmt.Errorf("prune: %w", err) 855 } 856 } 857 858 if c.latestTrustedHeader == nil || h.Height > c.latestTrustedHeader.Height { 859 c.latestTrustedHeader = h 860 c.latestTrustedVals = vals 861 } 862 863 return nil 864 } 865 866 // fetch header and validators for the given height (0 - latest) from primary 867 // provider. 868 func (c *Client) fetchHeaderAndValsAtHeight(height int64) (*types.SignedHeader, *types.ValidatorSet, error) { 869 h, err := c.signedHeaderFromPrimary(height) 870 if err != nil { 871 return nil, nil, fmt.Errorf("failed to obtain the header #%d: %w", height, err) 872 } 873 vals, err := c.validatorSetFromPrimary(height) 874 if err != nil { 875 return nil, nil, fmt.Errorf("failed to obtain the vals #%d: %w", height, err) 876 } 877 return h, vals, nil 878 } 879 880 // backwards verification (see VerifyHeaderBackwards func in the spec) verifies 881 // headers before a trusted header. If a sent header is invalid the primary is 882 // replaced with another provider and the operation is repeated. 883 func (c *Client) backwards( 884 initiallyTrustedHeader *types.SignedHeader, 885 newHeader *types.SignedHeader, 886 now time.Time) error { 887 888 if HeaderExpired(initiallyTrustedHeader, c.trustingPeriod, now) { 889 c.logger.Error("Header Expired") 890 return ErrOldHeaderExpired{initiallyTrustedHeader.Time.Add(c.trustingPeriod), now} 891 } 892 893 var ( 894 trustedHeader = initiallyTrustedHeader 895 interimHeader *types.SignedHeader 896 err error 897 ) 898 899 for trustedHeader.Height > newHeader.Height { 900 interimHeader, err = c.signedHeaderFromPrimary(trustedHeader.Height - 1) 901 if err != nil { 902 return fmt.Errorf("failed to obtain the header at height #%d: %w", trustedHeader.Height-1, err) 903 } 904 c.logger.Debug("Verify newHeader against trustedHeader", 905 "trustedHeight", trustedHeader.Height, 906 "trustedHash", hash2str(trustedHeader.Hash()), 907 "newHeight", interimHeader.Height, 908 "newHash", hash2str(interimHeader.Hash())) 909 if err := VerifyBackwards(c.chainID, interimHeader, trustedHeader); err != nil { 910 c.logger.Error("primary sent invalid header -> replacing", "err", err) 911 if replaceErr := c.replacePrimaryProvider(); replaceErr != nil { 912 c.logger.Error("Can't replace primary", "err", replaceErr) 913 // return original error 914 return fmt.Errorf("verify backwards from %d to %d failed: %w", 915 trustedHeader.Height, interimHeader.Height, err) 916 } 917 } 918 919 trustedHeader = interimHeader 920 } 921 922 // Initially trusted header might have expired at this point. 923 if HeaderExpired(initiallyTrustedHeader, c.trustingPeriod, now) { 924 return ErrOldHeaderExpired{initiallyTrustedHeader.Time.Add(c.trustingPeriod), now} 925 } 926 927 return nil 928 } 929 930 // compare header with all witnesses provided. 931 func (c *Client) compareNewHeaderWithWitnesses(h *types.SignedHeader) error { 932 c.providerMutex.Lock() 933 defer c.providerMutex.Unlock() 934 935 // 1. Make sure AT LEAST ONE witness returns the same header. 936 headerMatched := false 937 witnessesToRemove := make([]int, 0) 938 for attempt := uint16(1); attempt <= c.maxRetryAttempts; attempt++ { 939 if len(c.witnesses) == 0 { 940 return errNoWitnesses{} 941 } 942 943 for i, witness := range c.witnesses { 944 altH, err := witness.SignedHeader(h.Height) 945 if err != nil { 946 c.logger.Error("Failed to get a header from witness", "height", h.Height, "witness", witness) 947 continue 948 } 949 950 if err = altH.ValidateBasic(c.chainID); err != nil { 951 c.logger.Error("Witness sent us incorrect header", "err", err, "witness", witness) 952 witnessesToRemove = append(witnessesToRemove, i) 953 continue 954 } 955 956 if !bytes.Equal(h.Hash(), altH.Hash()) { 957 if err = c.latestTrustedVals.VerifyCommitLightTrusting(c.chainID, altH.Commit.BlockID, 958 altH.Height, altH.Commit, c.trustLevel); err != nil { 959 c.logger.Error("Witness sent us incorrect header", "err", err, "witness", witness) 960 witnessesToRemove = append(witnessesToRemove, i) 961 continue 962 } 963 964 // TODO: send the diverged headers to primary && all witnesses 965 966 return fmt.Errorf( 967 "header hash %X does not match one %X from the witness %v", 968 h.Hash(), altH.Hash(), witness) 969 } 970 971 headerMatched = true 972 } 973 974 for _, idx := range witnessesToRemove { 975 c.removeWitness(idx) 976 } 977 witnessesToRemove = make([]int, 0) 978 979 if headerMatched { 980 return nil 981 } 982 983 // 2. Otherwise, sleep 984 time.Sleep(backoffTimeout(attempt)) 985 } 986 987 return errors.New("awaiting response from all witnesses exceeded dropout time") 988 } 989 990 // NOTE: requires a providerMutex locked. 991 func (c *Client) removeWitness(idx int) { 992 switch len(c.witnesses) { 993 case 0: 994 panic(fmt.Sprintf("wanted to remove %d element from empty witnesses slice", idx)) 995 case 1: 996 c.witnesses = make([]provider.Provider, 0) 997 default: 998 c.witnesses[idx] = c.witnesses[len(c.witnesses)-1] 999 c.witnesses = c.witnesses[:len(c.witnesses)-1] 1000 } 1001 } 1002 1003 // Update attempts to advance the state by downloading the latest header and 1004 // comparing it with the existing one. It returns a new header on a successful 1005 // update. Otherwise, it returns nil (plus an error, if any). 1006 func (c *Client) Update(now time.Time) (*types.SignedHeader, error) { 1007 lastTrustedHeight, err := c.LastTrustedHeight() 1008 if err != nil { 1009 return nil, fmt.Errorf("can't get last trusted height: %w", err) 1010 } 1011 1012 if lastTrustedHeight == -1 { 1013 // no headers yet => wait 1014 return nil, nil 1015 } 1016 1017 latestHeader, latestVals, err := c.fetchHeaderAndValsAtHeight(0) 1018 if err != nil { 1019 return nil, err 1020 } 1021 1022 if latestHeader.Height > lastTrustedHeight { 1023 err = c.VerifyHeader(latestHeader, latestVals, now) 1024 if err != nil { 1025 return nil, err 1026 } 1027 c.logger.Info("Advanced to new state", "height", latestHeader.Height, "hash", hash2str(latestHeader.Hash())) 1028 return latestHeader, nil 1029 } 1030 1031 return nil, nil 1032 } 1033 1034 // replaceProvider takes the first alternative provider and promotes it as the 1035 // primary provider. 1036 func (c *Client) replacePrimaryProvider() error { 1037 c.providerMutex.Lock() 1038 defer c.providerMutex.Unlock() 1039 1040 if len(c.witnesses) <= 1 { 1041 return errNoWitnesses{} 1042 } 1043 c.primary = c.witnesses[0] 1044 c.witnesses = c.witnesses[1:] 1045 c.logger.Info("New primary", "p", c.primary) 1046 1047 return nil 1048 } 1049 1050 // signedHeaderFromPrimary retrieves the SignedHeader from the primary provider 1051 // at the specified height. Handles dropout by the primary provider by swapping 1052 // with an alternative provider. 1053 func (c *Client) signedHeaderFromPrimary(height int64) (*types.SignedHeader, error) { 1054 for attempt := uint16(1); attempt <= c.maxRetryAttempts; attempt++ { 1055 c.providerMutex.Lock() 1056 h, err := c.primary.SignedHeader(height) 1057 c.providerMutex.Unlock() 1058 if err == nil { 1059 // sanity check 1060 if height > 0 && h.Height != height { 1061 return nil, fmt.Errorf("expected %d height, got %d", height, h.Height) 1062 } 1063 return h, nil 1064 } 1065 if err == provider.ErrSignedHeaderNotFound { 1066 return nil, err 1067 } 1068 c.logger.Error("Failed to get signed header from primary", "attempt", attempt, "err", err) 1069 time.Sleep(backoffTimeout(attempt)) 1070 } 1071 1072 c.logger.Info("Primary is unavailable. Replacing with the first witness") 1073 err := c.replacePrimaryProvider() 1074 if err != nil { 1075 return nil, err 1076 } 1077 1078 return c.signedHeaderFromPrimary(height) 1079 } 1080 1081 // validatorSetFromPrimary retrieves the ValidatorSet from the primary provider 1082 // at the specified height. Handles dropout by the primary provider after 5 1083 // attempts by replacing it with an alternative provider. 1084 func (c *Client) validatorSetFromPrimary(height int64) (*types.ValidatorSet, error) { 1085 for attempt := uint16(1); attempt <= c.maxRetryAttempts; attempt++ { 1086 c.providerMutex.Lock() 1087 vals, err := c.primary.ValidatorSet(height) 1088 c.providerMutex.Unlock() 1089 if err == nil || err == provider.ErrValidatorSetNotFound { 1090 return vals, err 1091 } 1092 c.logger.Error("Failed to get validator set from primary", "attempt", attempt, "err", err) 1093 time.Sleep(backoffTimeout(attempt)) 1094 } 1095 1096 c.logger.Info("Primary is unavailable. Replacing with the first witness") 1097 err := c.replacePrimaryProvider() 1098 if err != nil { 1099 return nil, err 1100 } 1101 1102 return c.validatorSetFromPrimary(height) 1103 } 1104 1105 // exponential backoff (with jitter) 1106 // 0.5s -> 2s -> 4.5s -> 8s -> 12.5 with 1s variation 1107 func backoffTimeout(attempt uint16) time.Duration { 1108 return time.Duration(500*attempt*attempt)*time.Millisecond + time.Duration(rand.Intn(1000))*time.Millisecond 1109 } 1110 1111 func hash2str(hash []byte) string { 1112 return fmt.Sprintf("%X", hash) 1113 }