|
9 | 9 | "fmt" |
10 | 10 | "io" |
11 | 11 | "math/big" |
| 12 | + "slices" |
12 | 13 | "sort" |
13 | 14 | "strconv" |
14 | 15 | "sync" |
@@ -111,8 +112,8 @@ var ( |
111 | 112 | // be modified via out-of-range or non-contiguous headers. |
112 | 113 | errOutOfRangeChain = errors.New("out of range or non-contiguous chain") |
113 | 114 |
|
114 | | - errUncleDetected = errors.New("uncles not allowed") |
115 | | - // errUnknownValidators = errors.New("unknown validators") |
| 115 | + errUncleDetected = errors.New("uncles not allowed") |
| 116 | + errUnknownValidators = errors.New("unknown validators") |
116 | 117 | ) |
117 | 118 |
|
118 | 119 | // SignerFn is a signer callback function to request a header to be signed by a |
@@ -523,6 +524,69 @@ func (c *Bor) verifyCascadingFields(chain consensus.ChainHeaderReader, header *t |
523 | 524 | return ErrInvalidTimestamp |
524 | 525 | } |
525 | 526 |
|
| 527 | + if !c.config.IsRio(header.Number) && !slices.Contains(c.config.SkipValidatorByteCheck, number) { |
| 528 | + // Retrieve the snapshot needed to verify this header and cache it |
| 529 | + snap, err := c.snapshot(chain, header, parents, false) |
| 530 | + if err != nil { |
| 531 | + return err |
| 532 | + } |
| 533 | + |
| 534 | + // Verify if the producer set in header's extra data matches with the list in span. |
| 535 | + // We skip the check for 0th span as the producer set in contract v/s producer set |
| 536 | + // in heimdall span is different which will lead a mismatch. Moreover, to make the |
| 537 | + // validation stateless, we use the span from heimdall (via span store) instead of |
| 538 | + // span from validator set genesis contract as both are supposed to be equivalent. |
| 539 | + if number > zerothSpanEnd && IsSprintStart(number+1, c.config.CalculateSprint(number)) { |
| 540 | + span, err := c.spanStore.spanByBlockNumber(context.Background(), number+1) |
| 541 | + if err != nil { |
| 542 | + return err |
| 543 | + } |
| 544 | + |
| 545 | + // Use producer set from span as it's equivalent to the data we get from genesis contract |
| 546 | + selectedProducers := borSpan.ConvertHeimdallValidatorsToBorValidators(span.SelectedProducers) |
| 547 | + newValidators := make([]*valset.Validator, len(selectedProducers)) |
| 548 | + for i, val := range selectedProducers { |
| 549 | + newValidators[i] = &val |
| 550 | + } |
| 551 | + sort.Sort(valset.ValidatorsByAddress(newValidators)) |
| 552 | + |
| 553 | + headerVals, err := valset.ParseValidators(header.GetValidatorBytes(c.chainConfig)) |
| 554 | + if err != nil { |
| 555 | + return err |
| 556 | + } |
| 557 | + |
| 558 | + if len(newValidators) != len(headerVals) { |
| 559 | + log.Warn("Invalid validator set", "block number", number, "newValidators", newValidators, "headerVals", headerVals) |
| 560 | + return errInvalidSpanValidators |
| 561 | + } |
| 562 | + |
| 563 | + for i, val := range newValidators { |
| 564 | + if !bytes.Equal(val.HeaderBytes(), headerVals[i].HeaderBytes()) { |
| 565 | + log.Warn("Invalid validator set", "block number", number, "index", i, "local validator", val, "header validator", headerVals[i]) |
| 566 | + return errInvalidSpanValidators |
| 567 | + } |
| 568 | + } |
| 569 | + } |
| 570 | + |
| 571 | + // verify the validator list in the last sprint block |
| 572 | + if IsSprintStart(number, c.config.CalculateSprint(number)) && !slices.Contains(c.config.SkipValidatorByteCheck, number-1) { |
| 573 | + parentValidatorBytes := parent.GetValidatorBytes(c.chainConfig) |
| 574 | + validatorsBytes := make([]byte, len(snap.ValidatorSet.Validators)*validatorHeaderBytesLength) |
| 575 | + |
| 576 | + currentValidators := snap.ValidatorSet.Copy().Validators |
| 577 | + // sort validator by address |
| 578 | + sort.Sort(valset.ValidatorsByAddress(currentValidators)) |
| 579 | + |
| 580 | + for i, validator := range currentValidators { |
| 581 | + copy(validatorsBytes[i*validatorHeaderBytesLength:], validator.HeaderBytes()) |
| 582 | + } |
| 583 | + // len(header.Extra) >= extraVanity+extraSeal has already been validated in validateHeaderExtraField, so this won't result in a panic |
| 584 | + if !bytes.Equal(parentValidatorBytes, validatorsBytes) { |
| 585 | + return &MismatchingValidatorsError{number - 1, validatorsBytes, parentValidatorBytes} |
| 586 | + } |
| 587 | + } |
| 588 | + } |
| 589 | + |
526 | 590 | // All basic checks passed, verify the seal and return |
527 | 591 | return c.verifySeal(chain, header, parents) |
528 | 592 | } |
@@ -854,17 +918,9 @@ func (c *Bor) Prepare(chain consensus.ChainHeaderReader, header *types.Header) e |
854 | 918 |
|
855 | 919 | // get validator set if number |
856 | 920 | if IsSprintStart(number+1, c.config.CalculateSprint(number)) && !c.config.IsRio(header.Number) { |
857 | | - span, err := c.spanStore.spanByBlockNumber(context.Background(), number+1) |
| 921 | + newValidators, err := c.spanner.GetCurrentValidatorsByHash(context.Background(), header.ParentHash, number+1) |
858 | 922 | if err != nil { |
859 | | - return err |
860 | | - } |
861 | | - |
862 | | - newValidators := make([]*valset.Validator, len(span.SelectedProducers)) |
863 | | - for i, val := range span.SelectedProducers { |
864 | | - newValidators[i] = &valset.Validator{ |
865 | | - Address: common.HexToAddress(val.Signer), |
866 | | - VotingPower: val.VotingPower, |
867 | | - } |
| 923 | + return errUnknownValidators |
868 | 924 | } |
869 | 925 |
|
870 | 926 | // sort validator by address |
|
0 commit comments