Skip to content

Commit

Permalink
polygon: Support Producers API in bor.go (#12521)
Browse files Browse the repository at this point in the history
Fixes #12437
  • Loading branch information
shohamc1 authored Oct 29, 2024
1 parent bee376e commit 81fc257
Show file tree
Hide file tree
Showing 3 changed files with 135 additions and 53 deletions.
157 changes: 120 additions & 37 deletions polygon/bor/bor.go
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ var (
// backing account.
type SignerFn func(signer libcommon.Address, mimeType string, message []byte) ([]byte, error)

// ecrecover extracts the Ethereum account address from a signed header.
// Ecrecover extracts the Ethereum account address from a signed header.
func Ecrecover(header *types.Header, sigcache *lru.ARCCache[libcommon.Hash, libcommon.Address], c *borcfg.BorConfig) (libcommon.Address, error) {
// If the signature's already cached, return that
hash := header.Hash()
Expand Down Expand Up @@ -253,6 +253,7 @@ type ValidateHeaderTimeSignerSuccessionNumber interface {

type spanReader interface {
Span(ctx context.Context, id uint64) (*heimdall.Span, bool, error)
Producers(ctx context.Context, blockNum uint64) (*valset.ValidatorSet, error)
}

type bridgeReader interface {
Expand Down Expand Up @@ -845,18 +846,31 @@ func (c *Bor) VerifyUncles(_ consensus.ChainReader, _ *types.Header, uncles []*t
// VerifySeal implements consensus.Engine, checking whether the signature contained
// in the header satisfies the consensus protocol requirements.
func (c *Bor) VerifySeal(chain ChainHeaderReader, header *types.Header) error {
snap, err := c.snapshot(chain, header.Number.Uint64()-1, header.ParentHash, nil)
if err != nil {
return err
var validatorSet *valset.ValidatorSet
if c.spanReader != nil {
v, err := c.spanReader.Producers(context.Background(), header.Number.Uint64())
if err != nil {
return err
}

validatorSet = v
} else {
s, err := c.snapshot(chain, header.Number.Uint64()-1, header.ParentHash, nil)
if err != nil {
return err
}

validatorSet = s.ValidatorSet
}
return c.verifySeal(chain, header, nil, snap)

return c.verifySeal(chain, header, nil, validatorSet)
}

// verifySeal checks whether the signature contained in the header satisfies the
// consensus protocol requirements. The method accepts an optional list of parent
// headers that aren't yet part of the local blockchain to generate the snapshots
// from.
func (c *Bor) verifySeal(chain ChainHeaderReader, header *types.Header, parents []*types.Header, snap *Snapshot) error {
func (c *Bor) verifySeal(chain ChainHeaderReader, header *types.Header, parents []*types.Header, validatorSet *valset.ValidatorSet) error {
// Verifying the genesis block is not supported
number := header.Number.Uint64()
if number == 0 {
Expand All @@ -870,7 +884,7 @@ func (c *Bor) verifySeal(chain ChainHeaderReader, header *types.Header, parents
parent = chain.GetHeader(header.ParentHash, number-1)
}

if err := ValidateHeaderTime(header, time.Now(), parent, snap.ValidatorSet, c.config, c.Signatures); err != nil {
if err := ValidateHeaderTime(header, time.Now(), parent, validatorSet, c.config, c.Signatures); err != nil {
return err
}

Expand All @@ -881,7 +895,7 @@ func (c *Bor) verifySeal(chain ChainHeaderReader, header *types.Header, parents
return err
}

difficulty := snap.Difficulty(signer)
difficulty := validatorSet.SafeDifficulty(signer)
if header.Difficulty.Uint64() != difficulty {
return &WrongDifficultyError{number, difficulty, header.Difficulty.Uint64(), signer.Bytes()}
}
Expand All @@ -899,13 +913,25 @@ func (c *Bor) Prepare(chain consensus.ChainHeaderReader, header *types.Header, s

number := header.Number.Uint64()
// Assemble the validator snapshot to check which votes make sense
snap, err := c.snapshot(chain.(ChainHeaderReader), number-1, header.ParentHash, nil)
if err != nil {
return err
var validatorSet *valset.ValidatorSet
if c.spanReader != nil {
v, err := c.spanReader.Producers(context.Background(), header.Number.Uint64())
if err != nil {
return err
}

validatorSet = v
} else {
snap, err := c.snapshot(chain.(ChainHeaderReader), number-1, header.ParentHash, nil)
if err != nil {
return err
}

validatorSet = snap.ValidatorSet
}

// Set the correct difficulty
header.Difficulty = new(big.Int).SetUint64(snap.Difficulty(c.authorizedSigner.Load().signer))
header.Difficulty = new(big.Int).SetUint64(validatorSet.SafeDifficulty(c.authorizedSigner.Load().signer))

// Ensure the extra data has all it's components
if len(header.Extra) < types.ExtraVanityLength {
Expand Down Expand Up @@ -981,10 +1007,11 @@ func (c *Bor) Prepare(chain consensus.ChainHeaderReader, header *types.Header, s
}

var succession int
var err error
signer := c.authorizedSigner.Load().signer
// if signer is not empty
if !bytes.Equal(signer.Bytes(), libcommon.Address{}.Bytes()) {
succession, err = snap.ValidatorSet.GetSignerSuccessionNumber(signer, number)
succession, err = validatorSet.GetSignerSuccessionNumber(signer, number)
if err != nil {
return err
}
Expand Down Expand Up @@ -1157,14 +1184,27 @@ func (c *Bor) Seal(chain consensus.ChainHeaderReader, blockWithReceipts *types.B
currentSigner := c.authorizedSigner.Load()
signer, signFn := currentSigner.signer, currentSigner.signFn

snap, err := c.snapshot(chain.(ChainHeaderReader), number-1, header.ParentHash, nil)
if err != nil {
return err
}
var successionNumber int
if c.spanReader != nil {
validatorSet, err := c.spanReader.Producers(context.Background(), number)
if err != nil {
return err
}

successionNumber, err := snap.ValidatorSet.GetSignerSuccessionNumber(signer, number)
if err != nil {
return err
successionNumber, err = validatorSet.GetSignerSuccessionNumber(signer, number)
if err != nil {
return err
}
} else {
snap, err := c.snapshot(chain.(ChainHeaderReader), number-1, header.ParentHash, nil)
if err != nil {
return err
}

successionNumber, err = snap.ValidatorSet.GetSignerSuccessionNumber(signer, number)
if err != nil {
return err
}
}

// Sweet, the protocol permits us to sign the block, wait for our time
Expand Down Expand Up @@ -1232,6 +1272,16 @@ func (c *Bor) IsValidator(header *types.Header) (bool, error) {
return false, nil
}

currentSigner := c.authorizedSigner.Load()

if c.spanReader != nil {
validatorSet, err := c.spanReader.Producers(context.Background(), number)
if err != nil {
return false, err
}
return validatorSet.HasAddress(currentSigner.signer), nil
}

snap, err := c.snapshot(nil, number-1, header.ParentHash, nil)

if err != nil {
Expand All @@ -1242,8 +1292,6 @@ func (c *Bor) IsValidator(header *types.Header) (bool, error) {
return false, err
}

currentSigner := c.authorizedSigner.Load()

return snap.ValidatorSet.HasAddress(currentSigner.signer), nil
}

Expand All @@ -1254,26 +1302,49 @@ func (c *Bor) IsProposer(header *types.Header) (bool, error) {
return false, nil
}

snap, err := c.snapshot(nil, number-1, header.ParentHash, nil)
if err != nil {
return false, err
signer := c.authorizedSigner.Load().signer

var validatorSet *valset.ValidatorSet
var err error
if c.spanReader != nil {
validatorSet, err = c.spanReader.Producers(context.Background(), number)
if err != nil {
return false, err
}
} else {
snap, err := c.snapshot(nil, number-1, header.ParentHash, nil)
if err != nil {
return false, err
}

validatorSet = snap.ValidatorSet
}

signer := c.authorizedSigner.Load().signer
successionNumber, err := snap.ValidatorSet.GetSignerSuccessionNumber(signer, number)
successionNumber, err := validatorSet.GetSignerSuccessionNumber(signer, number)
return successionNumber == 0, err
}

// CalcDifficulty is the difficulty adjustment algorithm. It returns the difficulty
// that a new block should have based on the previous blocks in the chain and the
// current signer.
func (c *Bor) CalcDifficulty(chain consensus.ChainHeaderReader, _, _ uint64, _ *big.Int, parentNumber uint64, parentHash, _ libcommon.Hash, _ uint64) *big.Int {
signer := c.authorizedSigner.Load().signer

if c.spanReader != nil {
validatorSet, err := c.spanReader.Producers(context.Background(), parentNumber+1)
if err != nil {
return nil
}

return big.NewInt(int64(validatorSet.SafeDifficulty(signer)))
}

snap, err := c.snapshot(chain.(ChainHeaderReader), parentNumber, parentHash, nil)
if err != nil {
return nil
}

return new(big.Int).SetUint64(snap.Difficulty(c.authorizedSigner.Load().signer))
return new(big.Int).SetUint64(snap.ValidatorSet.SafeDifficulty(signer))
}

// SealHash returns the hash of a block prior to it being sealed.
Expand Down Expand Up @@ -1408,8 +1479,8 @@ func (c *Bor) fetchAndCommitSpan(
}

func (c *Bor) GetRootHash(ctx context.Context, tx kv.Tx, start, end uint64) (string, error) {
length := end - start + 1
if length > MaxCheckpointLength {
numHeaders := end - start + 1
if numHeaders > MaxCheckpointLength {
return "", &MaxCheckpointLengthExceededError{Start: start, End: end}
}

Expand All @@ -1432,7 +1503,7 @@ func (c *Bor) GetRootHash(ctx context.Context, tx kv.Tx, start, end uint64) (str
if start > end || end > currentHeaderNumber {
return "", &valset.InvalidStartEndBlockError{Start: start, End: end, CurrentHeader: currentHeaderNumber}
}
blockHeaders := make([]*types.Header, length)
blockHeaders := make([]*types.Header, numHeaders)
for number := start; number <= end; number++ {
blockHeaders[number-start], _ = c.getHeaderByNumber(ctx, tx, number)
}
Expand Down Expand Up @@ -1555,9 +1626,21 @@ func (c *Bor) getNextHeimdallSpanForTest(
}

// Retrieve the snapshot needed to verify this header and cache it
snap, err := c.snapshot(chain.Chain.(ChainHeaderReader), headerNumber-1, header.ParentHash, nil)
if err != nil {
return nil, err
var validatorSet *valset.ValidatorSet
if c.spanReader != nil {
v, err := c.spanReader.Producers(context.Background(), headerNumber)
if err != nil {
return nil, err
}

validatorSet = v
} else {
snap, err := c.snapshot(chain.Chain.(ChainHeaderReader), headerNumber-1, header.ParentHash, nil)
if err != nil {
return nil, err
}

validatorSet = snap.ValidatorSet
}

// new span
Expand All @@ -1570,14 +1653,14 @@ func (c *Bor) getNextHeimdallSpanForTest(

spanBor.EndBlock = spanBor.StartBlock + (100 * c.config.CalculateSprintLength(headerNumber)) - 1

selectedProducers := make([]valset.Validator, len(snap.ValidatorSet.Validators))
for i, v := range snap.ValidatorSet.Validators {
selectedProducers := make([]valset.Validator, len(validatorSet.Validators))
for i, v := range validatorSet.Validators {
selectedProducers[i] = *v
}

heimdallSpan := *spanBor

heimdallSpan.ValidatorSet = *snap.ValidatorSet
heimdallSpan.ValidatorSet = *validatorSet
heimdallSpan.SelectedProducers = selectedProducers
heimdallSpan.ChainID = c.chainConfig.ChainID.String()

Expand Down
17 changes: 1 addition & 16 deletions polygon/bor/snapshot.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
package bor

import (
"bytes"
"context"
"encoding/binary"
"encoding/json"
Expand Down Expand Up @@ -184,7 +183,7 @@ func (s *Snapshot) Apply(parent *types.Header, headers []*types.Header, logger l
return nil, err
}

difficulty := snap.Difficulty(signer)
difficulty := snap.ValidatorSet.SafeDifficulty(signer)
if header.Difficulty.Uint64() != difficulty {
return snap, &WrongDifficultyError{number, difficulty, header.Difficulty.Uint64(), signer.Bytes()}
}
Expand Down Expand Up @@ -224,17 +223,3 @@ func (s *Snapshot) signers() []common.Address {

return sigs
}

// Difficulty returns the difficulty for a particular signer at the current snapshot number
func (s *Snapshot) Difficulty(signer common.Address) uint64 {
// if signer is empty
if bytes.Equal(signer.Bytes(), common.Address{}.Bytes()) {
return 1
}

if d, err := s.ValidatorSet.Difficulty(signer); err == nil {
return d
} else {
return 0
}
}
14 changes: 14 additions & 0 deletions polygon/bor/valset/validator_set.go
Original file line number Diff line number Diff line change
Expand Up @@ -681,6 +681,20 @@ func (vals *ValidatorSet) Difficulty(signer libcommon.Address) (uint64, error) {
return uint64(len(vals.Validators) - indexDiff), nil
}

// SafeDifficulty returns the difficulty for a particular signer at the current snapshot number if available,
// otherwise it returns 1 for empty signer and 0 if it is not in the validator set.
func (vals *ValidatorSet) SafeDifficulty(signer libcommon.Address) uint64 {
if bytes.Equal(signer.Bytes(), libcommon.Address{}.Bytes()) {
return 1
}

if d, err := vals.Difficulty(signer); err == nil {
return d
} else {
return 0
}
}

// GetSignerSuccessionNumber returns the relative position of signer in terms of the in-turn proposer
func (vals *ValidatorSet) GetSignerSuccessionNumber(signer libcommon.Address, number uint64) (int, error) {
proposer := vals.GetProposer()
Expand Down

0 comments on commit 81fc257

Please sign in to comment.