github.com/adoriasoft/tendermint@v0.34.0-dev1.0.20200722151356-96d84601a75a/light/client.go (about) 1 package light 2 3 import ( 4 "bytes" 5 "errors" 6 "fmt" 7 "math/rand" 8 "time" 9 10 "github.com/tendermint/tendermint/libs/log" 11 tmmath "github.com/tendermint/tendermint/libs/math" 12 tmsync "github.com/tendermint/tendermint/libs/sync" 13 "github.com/tendermint/tendermint/light/provider" 14 "github.com/tendermint/tendermint/light/store" 15 "github.com/tendermint/tendermint/types" 16 ) 17 18 type mode byte 19 20 const ( 21 sequential mode = iota + 1 22 skipping 23 24 defaultPruningSize = 1000 25 defaultMaxRetryAttempts = 10 26 // For bisection, when using the cache of headers from the previous batch, 27 // they will always be at a height greater than 1/2 (normal bisection) so to 28 // find something in between the range, 9/16 is used. 29 bisectionNumerator = 9 30 bisectionDenominator = 16 31 32 // 10s should cover most of the clients. 33 // References: 34 // - http://vancouver-webpages.com/time/web.html 35 // - https://blog.codinghorror.com/keeping-time-on-the-pc/ 36 defaultMaxClockDrift = 10 * time.Second 37 ) 38 39 // Option sets a parameter for the light client. 40 type Option func(*Client) 41 42 // SequentialVerification option configures the light client to sequentially 43 // check the headers (every header, in ascending height order). Note this is 44 // much slower than SkippingVerification, albeit more secure. 45 func SequentialVerification() Option { 46 return func(c *Client) { 47 c.verificationMode = sequential 48 } 49 } 50 51 // SkippingVerification option configures the light client to skip headers as 52 // long as {trustLevel} of the old validator set signed the new header. The 53 // bisection algorithm from the specification is used for finding the minimal 54 // "trust path". 55 // 56 // trustLevel - fraction of the old validator set (in terms of voting power), 57 // which must sign the new header in order for us to trust it. NOTE this only 58 // applies to non-adjacent headers. For adjacent headers, sequential 59 // verification is used. 60 func SkippingVerification(trustLevel tmmath.Fraction) Option { 61 return func(c *Client) { 62 c.verificationMode = skipping 63 c.trustLevel = trustLevel 64 } 65 } 66 67 // PruningSize option sets the maximum amount of headers & validator set pairs 68 // that the light client stores. When Prune() is run, all headers (along with 69 // the associated validator sets) that are earlier than the h amount of headers 70 // will be removed from the store. Default: 1000. A pruning size of 0 will not 71 // prune the light client at all. 72 func PruningSize(h uint16) Option { 73 return func(c *Client) { 74 c.pruningSize = h 75 } 76 } 77 78 // ConfirmationFunction option can be used to prompt to confirm an action. For 79 // example, remove newer headers if the light client is being reset with an 80 // older header. No confirmation is required by default! 81 func ConfirmationFunction(fn func(action string) bool) Option { 82 return func(c *Client) { 83 c.confirmationFn = fn 84 } 85 } 86 87 // Logger option can be used to set a logger for the client. 88 func Logger(l log.Logger) Option { 89 return func(c *Client) { 90 c.logger = l 91 } 92 } 93 94 // MaxRetryAttempts option can be used to set max attempts before replacing 95 // primary with a witness. 96 func MaxRetryAttempts(max uint16) Option { 97 return func(c *Client) { 98 c.maxRetryAttempts = max 99 } 100 } 101 102 // MaxClockDrift defines how much new (untrusted) header's Time can drift into 103 // the future. Default: 10s. 104 func MaxClockDrift(d time.Duration) Option { 105 return func(c *Client) { 106 c.maxClockDrift = d 107 } 108 } 109 110 // Client represents a light client, connected to a single chain, which gets 111 // headers from a primary provider, verifies them either sequentially or by 112 // skipping some and stores them in a trusted store (usually, a local FS). 113 // 114 // Default verification: SkippingVerification(DefaultTrustLevel) 115 type Client struct { 116 chainID string 117 trustingPeriod time.Duration // see TrustOptions.Period 118 verificationMode mode 119 trustLevel tmmath.Fraction 120 maxRetryAttempts uint16 // see MaxRetryAttempts option 121 maxClockDrift time.Duration 122 123 // Mutex for locking during changes of the light clients providers 124 providerMutex tmsync.Mutex 125 // Primary provider of new headers. 126 primary provider.Provider 127 // See Witnesses option 128 witnesses []provider.Provider 129 130 // Where trusted headers are stored. 131 trustedStore store.Store 132 // Highest trusted header from the store (height=H). 133 latestTrustedHeader *types.SignedHeader 134 // Highest validator set from the store (height=H). 135 latestTrustedVals *types.ValidatorSet 136 137 // See RemoveNoLongerTrustedHeadersPeriod option 138 pruningSize uint16 139 // See ConfirmationFunction option 140 confirmationFn func(action string) bool 141 142 quit chan struct{} 143 144 logger log.Logger 145 } 146 147 // NewClient returns a new light client. It returns an error if it fails to 148 // obtain the header & vals from the primary or they are invalid (e.g. trust 149 // hash does not match with the one from the header). 150 // 151 // Witnesses are providers, which will be used for cross-checking the primary 152 // provider. At least one witness must be given when skipping verification is 153 // used (default). A witness can become a primary iff the current primary is 154 // 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 && c.verificationMode == skipping { 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. 352 func (c *Client) initializeWithTrustOptions(options TrustOptions) error { 353 // 1) Fetch and verify the header. 354 h, err := c.signedHeaderFromPrimary(options.Height) 355 if err != nil { 356 return err 357 } 358 359 // NOTE: - Verify func will check if it's expired or not. 360 // - h.Time is not being checked against time.Now() because we don't 361 // want to add yet another argument to NewClient* functions. 362 if err := h.ValidateBasic(c.chainID); err != nil { 363 return err 364 } 365 366 if !bytes.Equal(h.Hash(), options.Hash) { 367 return fmt.Errorf("expected header's hash %X, but got %X", options.Hash, h.Hash()) 368 } 369 370 // 2) Fetch and verify the vals. 371 vals, err := c.validatorSetFromPrimary(options.Height) 372 if err != nil { 373 return err 374 } 375 376 if !bytes.Equal(h.ValidatorsHash, vals.Hash()) { 377 return fmt.Errorf("expected header's validators (%X) to match those that were supplied (%X)", 378 h.ValidatorsHash, 379 vals.Hash(), 380 ) 381 } 382 383 // Ensure that +2/3 of validators signed correctly. 384 err = vals.VerifyCommitLight(c.chainID, h.Commit.BlockID, h.Height, h.Commit) 385 if err != nil { 386 return fmt.Errorf("invalid commit: %w", err) 387 } 388 389 // 3) Persist both of them and continue. 390 return c.updateTrustedHeaderAndVals(h, vals) 391 } 392 393 // TrustedHeader returns a trusted header at the given height (0 - the latest). 394 // 395 // Headers along with validator sets, which can't be trusted anymore, are 396 // removed once a day (can be changed with RemoveNoLongerTrustedHeadersPeriod 397 // option). 398 // . 399 // height must be >= 0. 400 // 401 // It returns an error if: 402 // - there are some issues with the trusted store, although that should not 403 // happen normally; 404 // - negative height is passed; 405 // - header has not been verified yet and is therefore not in the store 406 // 407 // Safe for concurrent use by multiple goroutines. 408 func (c *Client) TrustedHeader(height int64) (*types.SignedHeader, error) { 409 height, err := c.compareWithLatestHeight(height) 410 if err != nil { 411 return nil, err 412 } 413 return c.trustedStore.SignedHeader(height) 414 } 415 416 // TrustedValidatorSet returns a trusted validator set at the given height (0 - 417 // latest). The second return parameter is the height used (useful if 0 was 418 // passed; otherwise can be ignored). 419 // 420 // height must be >= 0. 421 // 422 // Headers along with validator sets are 423 // removed once a day (can be changed with RemoveNoLongerTrustedHeadersPeriod 424 // option). 425 // 426 // Function returns an error if: 427 // - there are some issues with the trusted store, although that should not 428 // happen normally; 429 // - negative height is passed; 430 // - header signed by that validator set has not been verified yet 431 // 432 // Safe for concurrent use by multiple goroutines. 433 func (c *Client) TrustedValidatorSet(height int64) (valSet *types.ValidatorSet, heightUsed int64, err error) { 434 heightUsed, err = c.compareWithLatestHeight(height) 435 if err != nil { 436 return nil, heightUsed, err 437 } 438 valSet, err = c.trustedStore.ValidatorSet(heightUsed) 439 if err != nil { 440 return nil, heightUsed, err 441 } 442 return valSet, heightUsed, err 443 } 444 445 func (c *Client) compareWithLatestHeight(height int64) (int64, error) { 446 latestHeight, err := c.LastTrustedHeight() 447 if err != nil { 448 return 0, fmt.Errorf("can't get last trusted height: %w", err) 449 } 450 if latestHeight == -1 { 451 return 0, errors.New("no headers exist") 452 } 453 454 switch { 455 case height > latestHeight: 456 return 0, fmt.Errorf("unverified header/valset requested (latest: %d)", latestHeight) 457 case height == 0: 458 return latestHeight, nil 459 case height < 0: 460 return 0, errors.New("negative height") 461 } 462 463 return height, nil 464 } 465 466 // VerifyHeaderAtHeight fetches header and validators at the given height 467 // and calls VerifyHeader. It returns header immediately if such exists in 468 // trustedStore (no verification is needed). 469 // 470 // height must be > 0. 471 // 472 // It returns provider.ErrSignedHeaderNotFound if header is not found by 473 // primary. 474 // 475 // It will replace the primary provider if an error from a request to the provider occurs 476 func (c *Client) VerifyHeaderAtHeight(height int64, now time.Time) (*types.SignedHeader, error) { 477 if height <= 0 { 478 return nil, errors.New("negative or zero height") 479 } 480 481 // Check if header already verified. 482 h, err := c.TrustedHeader(height) 483 if err == nil { 484 c.logger.Info("Header has already been verified", "height", height, "hash", hash2str(h.Hash())) 485 // Return already trusted header 486 return h, nil 487 } 488 489 // Request the header and the vals. 490 newHeader, newVals, err := c.signedHeaderAndValSetFromPrimary(height) 491 if err != nil { 492 return nil, err 493 } 494 495 return newHeader, c.verifyHeader(newHeader, newVals, now) 496 } 497 498 // VerifyHeader verifies new header against the trusted state. It returns 499 // immediately if newHeader exists in trustedStore (no verification is 500 // needed). Else it performs one of the two types of verification: 501 // 502 // SequentialVerification: verifies that 2/3 of the trusted validator set has 503 // signed the new header. If the headers are not adjacent, **all** intermediate 504 // headers will be requested. Intermediate headers are not saved to database. 505 // 506 // SkippingVerification(trustLevel): verifies that {trustLevel} of the trusted 507 // validator set has signed the new header. If it's not the case and the 508 // headers are not adjacent, bisection is performed and necessary (not all) 509 // intermediate headers will be requested. See the specification for details. 510 // Intermediate headers are not saved to database. 511 // https://github.com/tendermint/spec/blob/master/spec/consensus/light-client.md 512 // 513 // If the header, which is older than the currently trusted header, is 514 // requested and the light client does not have it, VerifyHeader will perform: 515 // a) bisection verification if nearest trusted header is found & not expired 516 // b) backwards verification in all other cases 517 // 518 // It returns ErrOldHeaderExpired if the latest trusted header expired. 519 // 520 // If the primary provides an invalid header (ErrInvalidHeader), it is rejected 521 // and replaced by another provider until all are exhausted. 522 // 523 // If, at any moment, SignedHeader or ValidatorSet are not found by the primary 524 // provider, provider.ErrSignedHeaderNotFound / 525 // provider.ErrValidatorSetNotFound error is returned. 526 func (c *Client) VerifyHeader(newHeader *types.SignedHeader, newVals *types.ValidatorSet, now time.Time) error { 527 if newHeader.Height <= 0 { 528 return errors.New("negative or zero height") 529 } 530 531 // Check if newHeader already verified. 532 h, err := c.TrustedHeader(newHeader.Height) 533 if err == nil { 534 // Make sure it's the same header. 535 if !bytes.Equal(h.Hash(), newHeader.Hash()) { 536 return fmt.Errorf("existing trusted header %X does not match newHeader %X", h.Hash(), newHeader.Hash()) 537 } 538 c.logger.Info("Header has already been verified", 539 "height", newHeader.Height, "hash", hash2str(newHeader.Hash())) 540 return nil 541 } 542 543 return c.verifyHeader(newHeader, newVals, now) 544 } 545 546 func (c *Client) verifyHeader(newHeader *types.SignedHeader, newVals *types.ValidatorSet, now time.Time) error { 547 c.logger.Info("VerifyHeader", "height", newHeader.Height, "hash", hash2str(newHeader.Hash()), 548 "vals", hash2str(newVals.Hash())) 549 550 var err error 551 552 // 1) If going forward, perform either bisection or sequential verification. 553 if newHeader.Height >= c.latestTrustedHeader.Height { 554 switch c.verificationMode { 555 case sequential: 556 err = c.sequence(c.latestTrustedHeader, newHeader, newVals, now) 557 case skipping: 558 err = c.bisectionAgainstPrimary(c.latestTrustedHeader, c.latestTrustedVals, newHeader, newVals, now) 559 default: 560 panic(fmt.Sprintf("Unknown verification mode: %b", c.verificationMode)) 561 } 562 } else { 563 // 2) If verifying before the first trusted header, perform backwards 564 // verification. 565 var ( 566 closestHeader *types.SignedHeader 567 firstHeaderHeight int64 568 ) 569 firstHeaderHeight, err = c.FirstTrustedHeight() 570 if err != nil { 571 return fmt.Errorf("can't get first header height: %w", err) 572 } 573 if newHeader.Height < firstHeaderHeight { 574 closestHeader, err = c.TrustedHeader(firstHeaderHeight) 575 if err != nil { 576 return fmt.Errorf("can't get first signed header: %w", err) 577 } 578 if HeaderExpired(closestHeader, c.trustingPeriod, now) { 579 closestHeader = c.latestTrustedHeader 580 } 581 err = c.backwards(closestHeader, newHeader, now) 582 } else { 583 // 3) OR if between trusted headers where the nearest has not expired, 584 // perform bisection verification, else backwards. 585 closestHeader, err = c.trustedStore.SignedHeaderBefore(newHeader.Height) 586 if err != nil { 587 return fmt.Errorf("can't get signed header before height %d: %w", newHeader.Height, err) 588 } 589 var closestValidatorSet *types.ValidatorSet 590 if c.verificationMode == sequential || HeaderExpired(closestHeader, c.trustingPeriod, now) { 591 err = c.backwards(c.latestTrustedHeader, newHeader, now) 592 } else { 593 closestValidatorSet, _, err = c.TrustedValidatorSet(closestHeader.Height) 594 if err != nil { 595 return fmt.Errorf("can't get validator set at height %d: %w", closestHeader.Height, err) 596 } 597 err = c.bisectionAgainstPrimary(closestHeader, closestValidatorSet, newHeader, newVals, now) 598 } 599 } 600 } 601 if err != nil { 602 c.logger.Error("Can't verify", "err", err) 603 return err 604 } 605 606 // 4) Once verified, save and return 607 return c.updateTrustedHeaderAndVals(newHeader, newVals) 608 } 609 610 // see VerifyHeader 611 func (c *Client) sequence( 612 initiallyTrustedHeader *types.SignedHeader, 613 newHeader *types.SignedHeader, 614 newVals *types.ValidatorSet, 615 now time.Time) error { 616 617 var ( 618 trustedHeader = initiallyTrustedHeader 619 620 interimHeader *types.SignedHeader 621 interimVals *types.ValidatorSet 622 623 err error 624 ) 625 626 for height := initiallyTrustedHeader.Height + 1; height <= newHeader.Height; height++ { 627 // 1) Fetch interim headers and vals if needed. 628 if height == newHeader.Height { // last header 629 interimHeader, interimVals = newHeader, newVals 630 } else { // intermediate headers 631 interimHeader, interimVals, err = c.signedHeaderAndValSetFromPrimary(height) 632 if err != nil { 633 return ErrVerificationFailed{From: trustedHeader.Height, To: height, Reason: err} 634 } 635 } 636 637 // 2) Verify them 638 c.logger.Debug("Verify adjacent newHeader against trustedHeader", 639 "trustedHeight", trustedHeader.Height, 640 "trustedHash", hash2str(trustedHeader.Hash()), 641 "newHeight", interimHeader.Height, 642 "newHash", hash2str(interimHeader.Hash())) 643 644 err = VerifyAdjacent(c.chainID, trustedHeader, interimHeader, interimVals, 645 c.trustingPeriod, now, c.maxClockDrift) 646 if err != nil { 647 err := ErrVerificationFailed{From: trustedHeader.Height, To: interimHeader.Height, Reason: err} 648 649 switch errors.Unwrap(err).(type) { 650 case ErrInvalidHeader: 651 // If the target header is invalid, return immediately. 652 if err.To == newHeader.Height { 653 c.logger.Debug("Target header is invalid", "err", err) 654 return err 655 } 656 657 // If some intermediate header is invalid, replace the primary and try 658 // again. 659 c.logger.Error("primary sent invalid header -> replacing", "err", err) 660 replaceErr := c.replacePrimaryProvider() 661 if replaceErr != nil { 662 c.logger.Error("Can't replace primary", "err", replaceErr) 663 // return original error 664 return err 665 } 666 667 replacementHeader, replacementVals, fErr := c.signedHeaderAndValSetFromPrimary(newHeader.Height) 668 if fErr != nil { 669 c.logger.Error("Can't fetch header/vals from primary", "err", fErr) 670 // return original error 671 return err 672 } 673 674 if !bytes.Equal(replacementHeader.Hash(), newHeader.Hash()) || 675 !bytes.Equal(replacementVals.Hash(), newVals.Hash()) { 676 c.logger.Error("Replacement provider has a different header/vals", 677 "newHash", newHeader.Hash(), 678 "newVals", newVals.Hash(), 679 "replHash", replacementHeader.Hash(), 680 "replVals", replacementVals.Hash()) 681 // return original error 682 return err 683 } 684 685 // attempt to verify header again 686 height-- 687 688 continue 689 default: 690 return err 691 } 692 } 693 694 // 3) Update trustedHeader 695 trustedHeader = interimHeader 696 } 697 698 return nil 699 } 700 701 // see VerifyHeader 702 // 703 // Bisection finds the middle header between a trusted and new header, 704 // reiterating the action until it verifies a header. A cache of headers 705 // requested from source is kept such that when a verification is made, and the 706 // light client tries again to verify the new header in the middle, the light 707 // client does not need to ask for all the same headers again. 708 func (c *Client) bisection( 709 source provider.Provider, 710 initiallyTrustedHeader *types.SignedHeader, 711 initiallyTrustedVals *types.ValidatorSet, 712 newHeader *types.SignedHeader, 713 newVals *types.ValidatorSet, 714 now time.Time) error { 715 716 type headerSet struct { 717 sh *types.SignedHeader 718 valSet *types.ValidatorSet 719 } 720 721 var ( 722 headerCache = []headerSet{{newHeader, newVals}} 723 depth = 0 724 725 trustedHeader = initiallyTrustedHeader 726 trustedVals = initiallyTrustedVals 727 ) 728 729 for { 730 c.logger.Debug("Verify non-adjacent newHeader against trustedHeader", 731 "trustedHeight", trustedHeader.Height, 732 "trustedHash", hash2str(trustedHeader.Hash()), 733 "newHeight", headerCache[depth].sh.Height, 734 "newHash", hash2str(headerCache[depth].sh.Hash())) 735 736 err := Verify(c.chainID, trustedHeader, trustedVals, headerCache[depth].sh, headerCache[depth].valSet, 737 c.trustingPeriod, now, c.maxClockDrift, c.trustLevel) 738 switch err.(type) { 739 case nil: 740 // Have we verified the last header 741 if depth == 0 { 742 return nil 743 } 744 // If not, update the lower bound to the previous upper bound 745 trustedHeader, trustedVals = headerCache[depth].sh, headerCache[depth].valSet 746 // Remove the untrusted header at the lower bound in the header cache - it's no longer useful 747 headerCache = headerCache[:depth] 748 // Reset the cache depth so that we start from the upper bound again 749 depth = 0 750 751 case ErrNewValSetCantBeTrusted: 752 // do add another header to the end of the cache 753 if depth == len(headerCache)-1 { 754 pivotHeight := trustedHeader.Height + (headerCache[depth].sh.Height-trustedHeader. 755 Height)*bisectionNumerator/bisectionDenominator 756 interimHeader, interimVals, err := c.signedHeaderAndValSetFrom(pivotHeight, source) 757 if err != nil { 758 return ErrVerificationFailed{From: trustedHeader.Height, To: pivotHeight, Reason: err} 759 } 760 headerCache = append(headerCache, headerSet{interimHeader, interimVals}) 761 } 762 depth++ 763 764 default: 765 return ErrVerificationFailed{From: trustedHeader.Height, To: headerCache[depth].sh.Height, Reason: err} 766 } 767 } 768 } 769 770 // bisectionAgainstPrimary does bisection plus it compares new header with 771 // witnesses and replaces primary if it does not respond after 772 // MaxRetryAttempts. 773 func (c *Client) bisectionAgainstPrimary( 774 initiallyTrustedHeader *types.SignedHeader, 775 initiallyTrustedVals *types.ValidatorSet, 776 newHeader *types.SignedHeader, 777 newVals *types.ValidatorSet, 778 now time.Time) error { 779 780 err := c.bisection(c.primary, initiallyTrustedHeader, initiallyTrustedVals, newHeader, newVals, now) 781 782 switch errors.Unwrap(err).(type) { 783 case ErrInvalidHeader: 784 // If the target header is invalid, return immediately. 785 invalidHeaderHeight := err.(ErrVerificationFailed).To 786 if invalidHeaderHeight == newHeader.Height { 787 c.logger.Debug("Target header is invalid", "err", err) 788 return err 789 } 790 791 // If some intermediate header is invalid, replace the primary and try 792 // again. 793 c.logger.Error("primary sent invalid header -> replacing", "err", err) 794 replaceErr := c.replacePrimaryProvider() 795 if replaceErr != nil { 796 c.logger.Error("Can't replace primary", "err", replaceErr) 797 // return original error 798 return err 799 } 800 801 replacementHeader, replacementVals, fErr := c.signedHeaderAndValSetFromPrimary(newHeader.Height) 802 if fErr != nil { 803 c.logger.Error("Can't fetch header/vals from primary", "err", fErr) 804 // return original error 805 return err 806 } 807 808 if !bytes.Equal(replacementHeader.Hash(), newHeader.Hash()) || 809 !bytes.Equal(replacementVals.Hash(), newVals.Hash()) { 810 c.logger.Error("Replacement provider has a different header/vals", 811 "newHash", newHeader.Hash(), 812 "newVals", newVals.Hash(), 813 "replHash", replacementHeader.Hash(), 814 "replVals", replacementVals.Hash()) 815 // return original error 816 return err 817 } 818 819 // attempt to verify the header again 820 return c.bisectionAgainstPrimary( 821 initiallyTrustedHeader, 822 initiallyTrustedVals, 823 replacementHeader, 824 replacementVals, 825 now, 826 ) 827 case nil: 828 // Compare header with the witnesses to ensure it's not a fork. 829 // More witnesses we have, more chance to notice one. 830 // 831 // CORRECTNESS ASSUMPTION: there's at least 1 correct full node 832 // (primary or one of the witnesses). 833 if cmpErr := c.compareNewHeaderWithWitnesses(newHeader, now); cmpErr != nil { 834 return cmpErr 835 } 836 default: 837 return err 838 } 839 840 return nil 841 } 842 843 // LastTrustedHeight returns a last trusted height. -1 and nil are returned if 844 // there are no trusted headers. 845 // 846 // Safe for concurrent use by multiple goroutines. 847 func (c *Client) LastTrustedHeight() (int64, error) { 848 return c.trustedStore.LastSignedHeaderHeight() 849 } 850 851 // FirstTrustedHeight returns a first trusted height. -1 and nil are returned if 852 // there are no trusted headers. 853 // 854 // Safe for concurrent use by multiple goroutines. 855 func (c *Client) FirstTrustedHeight() (int64, error) { 856 return c.trustedStore.FirstSignedHeaderHeight() 857 } 858 859 // ChainID returns the chain ID the light client was configured with. 860 // 861 // Safe for concurrent use by multiple goroutines. 862 func (c *Client) ChainID() string { 863 return c.chainID 864 } 865 866 // Primary returns the primary provider. 867 // 868 // NOTE: provider may be not safe for concurrent access. 869 func (c *Client) Primary() provider.Provider { 870 c.providerMutex.Lock() 871 defer c.providerMutex.Unlock() 872 return c.primary 873 } 874 875 // Witnesses returns the witness providers. 876 // 877 // NOTE: providers may be not safe for concurrent access. 878 func (c *Client) Witnesses() []provider.Provider { 879 c.providerMutex.Lock() 880 defer c.providerMutex.Unlock() 881 return c.witnesses 882 } 883 884 // Cleanup removes all the data (headers and validator sets) stored. Note: the 885 // client must be stopped at this point. 886 func (c *Client) Cleanup() error { 887 c.logger.Info("Removing all the data") 888 c.latestTrustedHeader = nil 889 c.latestTrustedVals = nil 890 return c.trustedStore.Prune(0) 891 } 892 893 // cleanupAfter deletes all headers & validator sets after +height+. It also 894 // resets latestTrustedHeader to the latest header. 895 func (c *Client) cleanupAfter(height int64) error { 896 prevHeight := c.latestTrustedHeader.Height 897 898 for { 899 h, err := c.trustedStore.SignedHeaderBefore(prevHeight) 900 if err == store.ErrSignedHeaderNotFound || (h != nil && h.Height <= height) { 901 break 902 } else if err != nil { 903 return fmt.Errorf("failed to get header before %d: %w", prevHeight, err) 904 } 905 906 err = c.trustedStore.DeleteSignedHeaderAndValidatorSet(h.Height) 907 if err != nil { 908 c.logger.Error("can't remove a trusted header & validator set", "err", err, 909 "height", h.Height) 910 } 911 912 prevHeight = h.Height 913 } 914 915 c.latestTrustedHeader = nil 916 c.latestTrustedVals = nil 917 err := c.restoreTrustedHeaderAndVals() 918 if err != nil { 919 return err 920 } 921 922 return nil 923 } 924 925 func (c *Client) updateTrustedHeaderAndVals(h *types.SignedHeader, vals *types.ValidatorSet) error { 926 if !bytes.Equal(h.ValidatorsHash, vals.Hash()) { 927 return fmt.Errorf("expected validator's hash %X, but got %X", h.ValidatorsHash, vals.Hash()) 928 } 929 930 if err := c.trustedStore.SaveSignedHeaderAndValidatorSet(h, vals); err != nil { 931 return fmt.Errorf("failed to save trusted header: %w", err) 932 } 933 934 if c.pruningSize > 0 { 935 if err := c.trustedStore.Prune(c.pruningSize); err != nil { 936 return fmt.Errorf("prune: %w", err) 937 } 938 } 939 940 if c.latestTrustedHeader == nil || h.Height > c.latestTrustedHeader.Height { 941 c.latestTrustedHeader = h 942 c.latestTrustedVals = vals 943 } 944 945 return nil 946 } 947 948 // 0 - latest header 949 // Note it swaps the primary with a witness if primary is not responding after 950 // MaxRetryAttempts. 951 func (c *Client) signedHeaderAndValSetFromPrimary(height int64) (*types.SignedHeader, *types.ValidatorSet, error) { 952 h, err := c.signedHeaderFromPrimary(height) 953 if err != nil { 954 return nil, nil, fmt.Errorf("can't fetch header: %w", err) 955 } 956 vals, err := c.validatorSetFromPrimary(height) 957 if err != nil { 958 return nil, nil, fmt.Errorf("can't fetch vals: %w", err) 959 } 960 return h, vals, nil 961 } 962 963 // 0 - latest header 964 // Note it does not do retries nor swapping. 965 func (c *Client) signedHeaderAndValSetFromWitness(height int64, 966 witness provider.Provider) (*types.SignedHeader, *types.ValidatorSet, *errBadWitness) { 967 968 h, err := witness.SignedHeader(height) 969 if err != nil { 970 return nil, nil, &errBadWitness{err, noResponse, -1} 971 } 972 err = c.validateHeader(h, height) 973 if err != nil { 974 return nil, nil, &errBadWitness{err, invalidHeader, -1} 975 } 976 977 vals, err := witness.ValidatorSet(height) 978 if err != nil { 979 return nil, nil, &errBadWitness{err, noResponse, -1} 980 } 981 err = c.validateValidatorSet(vals) 982 if err != nil { 983 return nil, nil, &errBadWitness{err, invalidValidatorSet, -1} 984 } 985 986 return h, vals, nil 987 } 988 989 func (c *Client) signedHeaderAndValSetFrom(height int64, 990 source provider.Provider) (*types.SignedHeader, *types.ValidatorSet, error) { 991 992 c.providerMutex.Lock() 993 sourceIsPrimary := (c.primary == source) 994 c.providerMutex.Unlock() 995 996 if sourceIsPrimary { 997 return c.signedHeaderAndValSetFromPrimary(height) 998 } 999 return c.signedHeaderAndValSetFromWitness(height, source) 1000 } 1001 1002 // backwards verification (see VerifyHeaderBackwards func in the spec) verifies 1003 // headers before a trusted header. If a sent header is invalid the primary is 1004 // replaced with another provider and the operation is repeated. 1005 func (c *Client) backwards( 1006 initiallyTrustedHeader *types.SignedHeader, 1007 newHeader *types.SignedHeader, 1008 now time.Time) error { 1009 1010 if HeaderExpired(initiallyTrustedHeader, c.trustingPeriod, now) { 1011 c.logger.Error("Header Expired") 1012 return ErrOldHeaderExpired{initiallyTrustedHeader.Time.Add(c.trustingPeriod), now} 1013 } 1014 1015 var ( 1016 trustedHeader = initiallyTrustedHeader 1017 interimHeader *types.SignedHeader 1018 err error 1019 ) 1020 1021 for trustedHeader.Height > newHeader.Height { 1022 interimHeader, err = c.signedHeaderFromPrimary(trustedHeader.Height - 1) 1023 if err != nil { 1024 return fmt.Errorf("failed to obtain the header at height #%d: %w", trustedHeader.Height-1, err) 1025 } 1026 c.logger.Debug("Verify newHeader against trustedHeader", 1027 "trustedHeight", trustedHeader.Height, 1028 "trustedHash", hash2str(trustedHeader.Hash()), 1029 "newHeight", interimHeader.Height, 1030 "newHash", hash2str(interimHeader.Hash())) 1031 if err := VerifyBackwards(c.chainID, interimHeader, trustedHeader); err != nil { 1032 c.logger.Error("primary sent invalid header -> replacing", "err", err) 1033 if replaceErr := c.replacePrimaryProvider(); replaceErr != nil { 1034 c.logger.Error("Can't replace primary", "err", replaceErr) 1035 // return original error 1036 return fmt.Errorf("verify backwards from %d to %d failed: %w", 1037 trustedHeader.Height, interimHeader.Height, err) 1038 } 1039 } 1040 1041 trustedHeader = interimHeader 1042 } 1043 1044 // Initially trusted header might have expired at this point. 1045 if HeaderExpired(initiallyTrustedHeader, c.trustingPeriod, now) { 1046 return ErrOldHeaderExpired{initiallyTrustedHeader.Time.Add(c.trustingPeriod), now} 1047 } 1048 1049 return nil 1050 } 1051 1052 // compare header with all witnesses provided. 1053 func (c *Client) compareNewHeaderWithWitnesses(h *types.SignedHeader, now time.Time) error { 1054 c.providerMutex.Lock() 1055 defer c.providerMutex.Unlock() 1056 1057 // 1. Make sure AT LEAST ONE witness returns the same header. 1058 var ( 1059 headerMatched bool 1060 lastErrConfHeaders error 1061 ) 1062 for attempt := uint16(1); attempt <= c.maxRetryAttempts; attempt++ { 1063 if len(c.witnesses) == 0 { 1064 return errNoWitnesses{} 1065 } 1066 1067 // launch one goroutine per witness 1068 errc := make(chan error, len(c.witnesses)) 1069 for i, witness := range c.witnesses { 1070 go c.compareNewHeaderWithWitness(errc, h, witness, i, now) 1071 } 1072 1073 witnessesToRemove := make([]int, 0) 1074 1075 // handle errors as they come 1076 for i := 0; i < cap(errc); i++ { 1077 err := <-errc 1078 1079 switch e := err.(type) { 1080 case nil: // at least one header matched 1081 headerMatched = true 1082 case ErrConflictingHeaders: // fork detected 1083 c.logger.Info("FORK DETECTED", "witness", e.Witness, "err", err) 1084 c.sendConflictingHeadersEvidence(&types.ConflictingHeadersEvidence{H1: h, H2: e.H2}) 1085 lastErrConfHeaders = e 1086 case errBadWitness: 1087 c.logger.Info("Bad witness", "witness", c.witnesses[e.WitnessIndex], "err", err) 1088 // if witness sent us invalid header / vals, remove it 1089 if e.Code == invalidHeader || e.Code == invalidValidatorSet { 1090 c.logger.Info("Witness sent us invalid header / vals -> removing it", "witness", c.witnesses[e.WitnessIndex]) 1091 witnessesToRemove = append(witnessesToRemove, e.WitnessIndex) 1092 } 1093 } 1094 } 1095 1096 for _, idx := range witnessesToRemove { 1097 c.removeWitness(idx) 1098 } 1099 1100 if lastErrConfHeaders != nil { 1101 // NOTE: all of the potential forks will be reported, but we only return 1102 // the last ErrConflictingHeaders error here. 1103 return lastErrConfHeaders 1104 } else if headerMatched { 1105 return nil 1106 } 1107 1108 // 2. Otherwise, sleep 1109 time.Sleep(backoffTimeout(attempt)) 1110 } 1111 1112 return errors.New("awaiting response from all witnesses exceeded dropout time") 1113 } 1114 1115 func (c *Client) compareNewHeaderWithWitness(errc chan error, h *types.SignedHeader, 1116 witness provider.Provider, witnessIndex int, now time.Time) { 1117 1118 altH, altVals, err := c.signedHeaderAndValSetFromWitness(h.Height, witness) 1119 if err != nil { 1120 err.WitnessIndex = witnessIndex 1121 errc <- err 1122 return 1123 } 1124 1125 if !bytes.Equal(h.Hash(), altH.Hash()) { 1126 if bsErr := c.bisection(witness, c.latestTrustedHeader, c.latestTrustedVals, altH, altVals, now); bsErr != nil { 1127 errc <- errBadWitness{bsErr, invalidHeader, witnessIndex} 1128 return 1129 } 1130 errc <- ErrConflictingHeaders{H1: h, Primary: c.primary, H2: altH, Witness: witness} 1131 } 1132 1133 errc <- nil 1134 } 1135 1136 // NOTE: requires a providerMutex locked. 1137 func (c *Client) removeWitness(idx int) { 1138 switch len(c.witnesses) { 1139 case 0: 1140 panic(fmt.Sprintf("wanted to remove %d element from empty witnesses slice", idx)) 1141 case 1: 1142 c.witnesses = make([]provider.Provider, 0) 1143 default: 1144 c.witnesses[idx] = c.witnesses[len(c.witnesses)-1] 1145 c.witnesses = c.witnesses[:len(c.witnesses)-1] 1146 } 1147 } 1148 1149 // Update attempts to advance the state by downloading the latest header and 1150 // comparing it with the existing one. It returns a new header on a successful 1151 // update. Otherwise, it returns nil (plus an error, if any). 1152 func (c *Client) Update(now time.Time) (*types.SignedHeader, error) { 1153 lastTrustedHeight, err := c.LastTrustedHeight() 1154 if err != nil { 1155 return nil, fmt.Errorf("can't get last trusted height: %w", err) 1156 } 1157 1158 if lastTrustedHeight == -1 { 1159 // no headers yet => wait 1160 return nil, nil 1161 } 1162 1163 latestHeader, latestVals, err := c.signedHeaderAndValSetFromPrimary(0) 1164 if err != nil { 1165 return nil, err 1166 } 1167 1168 if latestHeader.Height > lastTrustedHeight { 1169 err = c.VerifyHeader(latestHeader, latestVals, now) 1170 if err != nil { 1171 return nil, err 1172 } 1173 c.logger.Info("Advanced to new state", "height", latestHeader.Height, "hash", hash2str(latestHeader.Hash())) 1174 return latestHeader, nil 1175 } 1176 1177 return nil, nil 1178 } 1179 1180 // replaceProvider takes the first alternative provider and promotes it as the 1181 // primary provider. 1182 func (c *Client) replacePrimaryProvider() error { 1183 c.providerMutex.Lock() 1184 defer c.providerMutex.Unlock() 1185 1186 c.logger.Info("Primary is unavailable. Replacing with the first witness") 1187 if len(c.witnesses) <= 1 { 1188 return errNoWitnesses{} 1189 } 1190 c.primary = c.witnesses[0] 1191 c.witnesses = c.witnesses[1:] 1192 c.logger.Info("New primary", "p", c.primary) 1193 1194 return nil 1195 } 1196 1197 // signedHeaderFromPrimary retrieves the SignedHeader from the primary provider 1198 // at the specified height. Handles dropout by the primary provider by swapping 1199 // with an alternative provider. 1200 func (c *Client) signedHeaderFromPrimary(height int64) (*types.SignedHeader, error) { 1201 for attempt := uint16(1); attempt <= c.maxRetryAttempts; attempt++ { 1202 c.providerMutex.Lock() 1203 h, providerErr := c.primary.SignedHeader(height) 1204 c.providerMutex.Unlock() 1205 if providerErr == nil { 1206 err := c.validateHeader(h, height) 1207 if err != nil { 1208 replaceErr := c.replacePrimaryProvider() 1209 if replaceErr != nil { 1210 return nil, fmt.Errorf("%v. Tried to replace primary but: %w", err.Error(), replaceErr) 1211 } 1212 // replace primary and request signed header again 1213 return c.signedHeaderFromPrimary(height) 1214 } 1215 // valid header has been received 1216 return h, nil 1217 } 1218 if providerErr == provider.ErrSignedHeaderNotFound { 1219 return nil, providerErr 1220 } 1221 c.logger.Error("Failed to get signed header from primary", "attempt", attempt, "err", providerErr) 1222 time.Sleep(backoffTimeout(attempt)) 1223 } 1224 1225 err := c.replacePrimaryProvider() 1226 if err != nil { 1227 return nil, fmt.Errorf("primary dropped out. Tried to replace but: %w", err) 1228 } 1229 1230 return c.signedHeaderFromPrimary(height) 1231 } 1232 1233 func (c *Client) validateHeader(h *types.SignedHeader, expectedHeight int64) error { 1234 if h == nil { 1235 return errors.New("nil header") 1236 } 1237 err := h.ValidateBasic(c.chainID) 1238 if err != nil { 1239 return err 1240 } 1241 if expectedHeight > 0 && h.Height != expectedHeight { 1242 return errors.New("height mismatch") 1243 } 1244 return nil 1245 } 1246 1247 // validatorSetFromPrimary retrieves the ValidatorSet from the primary provider 1248 // at the specified height. Handles dropout by the primary provider after 5 1249 // attempts by replacing it with an alternative provider. 1250 func (c *Client) validatorSetFromPrimary(height int64) (*types.ValidatorSet, error) { 1251 for attempt := uint16(1); attempt <= c.maxRetryAttempts; attempt++ { 1252 c.providerMutex.Lock() 1253 vals, providerErr := c.primary.ValidatorSet(height) 1254 c.providerMutex.Unlock() 1255 if providerErr == nil { 1256 err := c.validateValidatorSet(vals) 1257 if err != nil { 1258 replaceErr := c.replacePrimaryProvider() 1259 if replaceErr != nil { 1260 return nil, fmt.Errorf("%v. Tried to replace primary but: %w", err.Error(), replaceErr) 1261 } 1262 // replace primary and request signed header again 1263 return c.validatorSetFromPrimary(height) 1264 } 1265 return vals, nil 1266 } 1267 1268 if providerErr == provider.ErrValidatorSetNotFound { 1269 return vals, providerErr 1270 } 1271 c.logger.Error("Failed to get validator set from primary", "attempt", attempt, "err", providerErr) 1272 time.Sleep(backoffTimeout(attempt)) 1273 } 1274 1275 err := c.replacePrimaryProvider() 1276 if err != nil { 1277 return nil, fmt.Errorf("primary dropped out. Tried to replace but: %w", err) 1278 } 1279 1280 return c.validatorSetFromPrimary(height) 1281 } 1282 1283 func (c *Client) validateValidatorSet(vals *types.ValidatorSet) error { 1284 if vals == nil { 1285 return errors.New("validator set is nil") 1286 } 1287 return vals.ValidateBasic() 1288 } 1289 1290 // sendConflictingHeadersEvidence sends evidence to all witnesses and primary 1291 // on best effort basis. 1292 // 1293 // Evidence needs to be submitted to all full nodes since there's no way to 1294 // determine which full node is correct (honest). 1295 func (c *Client) sendConflictingHeadersEvidence(ev *types.ConflictingHeadersEvidence) { 1296 err := c.primary.ReportEvidence(ev) 1297 if err != nil { 1298 c.logger.Error("Failed to report evidence to primary", "ev", ev, "primary", c.primary) 1299 } 1300 1301 for _, w := range c.witnesses { 1302 err := w.ReportEvidence(ev) 1303 if err != nil { 1304 c.logger.Error("Failed to report evidence to witness", "ev", ev, "witness", w) 1305 } 1306 } 1307 } 1308 1309 // exponential backoff (with jitter) 1310 // 0.5s -> 2s -> 4.5s -> 8s -> 12.5 with 1s variation 1311 func backoffTimeout(attempt uint16) time.Duration { 1312 return time.Duration(500*attempt*attempt)*time.Millisecond + time.Duration(rand.Intn(1000))*time.Millisecond 1313 } 1314 1315 func hash2str(hash []byte) string { 1316 return fmt.Sprintf("%X", hash) 1317 }