Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix validator id on bor_getSnapshot, bor_getSnapshotAtHash and bor_getCurrentValidators #1415

Merged
merged 6 commits into from
Jan 31, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package abi

//go:generate mockgen -destination=./abi_mock.go -package=api . ABI
type ABI interface {
Pack(name string, args ...interface{}) ([]byte, error)
UnpackIntoInterface(v interface{}, name string, data []byte) error
Expand Down
68 changes: 68 additions & 0 deletions consensus/bor/abi/abi_mock.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion consensus/bor/bor.go
Original file line number Diff line number Diff line change
Expand Up @@ -620,7 +620,7 @@ func (c *Bor) snapshot(chain consensus.ChainHeaderReader, number uint64, hash co
headers[i], headers[len(headers)-1-i] = headers[len(headers)-1-i], headers[i]
}

snap, err := snap.apply(headers)
snap, err := snap.apply(headers, c)
if err != nil {
return nil, err
}
Expand Down
142 changes: 140 additions & 2 deletions consensus/bor/heimdall/span/spanner.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,13 @@ type ChainSpanner struct {
validatorContractAddress common.Address
}

// validator response on ValidatorSet contract
type contractValidator struct {
Id *big.Int
Power *big.Int
Signer common.Address
}

func NewChainSpanner(ethAPI api.Caller, validatorSet abi.ABI, chainConfig *params.ChainConfig, validatorContractAddress common.Address) *ChainSpanner {
return &ChainSpanner{
ethAPI: ethAPI,
Expand Down Expand Up @@ -93,6 +100,139 @@ func (c *ChainSpanner) GetCurrentValidatorsByBlockNrOrHash(ctx context.Context,
ctx, cancel := context.WithCancel(ctx)
defer cancel()

toAddress := c.validatorContractAddress
gas := (hexutil.Uint64)(uint64(math.MaxUint64 / 2))
lucca30 marked this conversation as resolved.
Show resolved Hide resolved

valz, err := c.tryGetBorValidatorsWithId(ctx, blockNrOrHash, blockNumber, toAddress, gas)
if err != nil {
return nil, err
}

return valz, nil
}

// tryGetBorValidatorsWithId Try to get bor validators with Id from ValidatorSet contract by querying each element on mapping(uint256 => Validator[]) public producers
// If fails then returns GetBorValidators without id
func (c *ChainSpanner) tryGetBorValidatorsWithId(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash, blockNumber uint64, toAddress common.Address, gas hexutil.Uint64) ([]*valset.Validator, error) {
firstEndBlock, err := c.getFirstEndBlock(ctx, blockNrOrHash, toAddress, gas)
if err != nil {
return nil, err
}
var spanNumber *big.Int
if big.NewInt(int64(blockNumber)).Cmp(firstEndBlock) <= 0 {
spanNumber = big.NewInt(0)
lucca30 marked this conversation as resolved.
Show resolved Hide resolved
} else {
spanNumber, err = c.getSpanByBlock(ctx, blockNrOrHash, blockNumber, toAddress, gas)
if err != nil {
return nil, err
}
}

borValidatorsWithoutId, err := c.getBorValidatorsWithoutId(ctx, blockNrOrHash, blockNumber, toAddress, gas)
if err != nil {
return nil, err
}

producersCount := len(borValidatorsWithoutId)

valz := make([]*valset.Validator, producersCount)

for i := 0; i < producersCount; i++ {
p, err := c.getProducersBySpanAndIndexMethod(ctx, blockNrOrHash, toAddress, gas, spanNumber, i)
// if fails, return validators without id
if err != nil {
manav2401 marked this conversation as resolved.
Show resolved Hide resolved
return borValidatorsWithoutId, nil
}

valz[i] = &valset.Validator{
ID: p.Id.Uint64(),
Address: p.Signer,
VotingPower: p.Power.Int64(),
}
}

return valz, nil
}

func (c *ChainSpanner) getSpanByBlock(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash, blockNumber uint64, toAddress common.Address, gas hexutil.Uint64) (*big.Int, error) {
const getSpanByBlockMethod = "getSpanByBlock"
spanData, err := c.validatorSet.Pack(getSpanByBlockMethod, big.NewInt(0).SetUint64(blockNumber))
if err != nil {
log.Error("Unable to pack tx for getSpanByBlock", "error", err)
return nil, err
}

spanMsgData := (hexutil.Bytes)(spanData)

spanResult, err := c.ethAPI.Call(ctx, ethapi.TransactionArgs{
Gas: &gas,
To: &toAddress,
Data: &spanMsgData,
}, &blockNrOrHash, nil, nil)
if err != nil {
return nil, err
}

var spanNumber *big.Int
if err := c.validatorSet.UnpackIntoInterface(&spanNumber, getSpanByBlockMethod, spanResult); err != nil {
return nil, err
}
return spanNumber, nil
}

func (c *ChainSpanner) getProducersBySpanAndIndexMethod(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash, toAddress common.Address, gas hexutil.Uint64, spanNumber *big.Int, index int) (*contractValidator, error) {
lucca30 marked this conversation as resolved.
Show resolved Hide resolved
const getProducersBySpanAndIndexMethod = "producers"
producerData, err := c.validatorSet.Pack(getProducersBySpanAndIndexMethod, spanNumber, big.NewInt(int64(index)))
if err != nil {
log.Error("Unable to pack tx for producers", "error", err)
return nil, err
}

producerMsgData := (hexutil.Bytes)(producerData)

result, err := c.ethAPI.Call(ctx, ethapi.TransactionArgs{
Gas: &gas,
To: &toAddress,
Data: &producerMsgData,
}, &blockNrOrHash, nil, nil)
if err != nil {
return nil, err
}

var producer contractValidator
if err := c.validatorSet.UnpackIntoInterface(&producer, getProducersBySpanAndIndexMethod, result); err != nil {
return nil, err
}
return &producer, nil
}

func (c *ChainSpanner) getFirstEndBlock(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash, toAddress common.Address, gas hexutil.Uint64) (*big.Int, error) {
const getFirstEndBlockMethod = "FIRST_END_BLOCK"
firstEndBlockData, err := c.validatorSet.Pack(getFirstEndBlockMethod)
if err != nil {
log.Error("Unable to pack tx for getFirstEndBlock", "error", err)
return nil, err
}

firstEndBlockMsgData := (hexutil.Bytes)(firstEndBlockData)

firstEndBlockResult, err := c.ethAPI.Call(ctx, ethapi.TransactionArgs{
Gas: &gas,
To: &toAddress,
Data: &firstEndBlockMsgData,
}, &blockNrOrHash, nil, nil)
if err != nil {
return nil, err
}

var firstEndBlockNumber *big.Int
if err := c.validatorSet.UnpackIntoInterface(&firstEndBlockNumber, getFirstEndBlockMethod, firstEndBlockResult); err != nil {
return nil, err
}
return firstEndBlockNumber, nil
}

func (c *ChainSpanner) getBorValidatorsWithoutId(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash, blockNumber uint64, toAddress common.Address, gas hexutil.Uint64) ([]*valset.Validator, error) {
// method
const method = "getBorValidators"

Expand All @@ -104,8 +244,6 @@ func (c *ChainSpanner) GetCurrentValidatorsByBlockNrOrHash(ctx context.Context,

// call
msgData := (hexutil.Bytes)(data)
toAddress := c.validatorContractAddress
gas := (hexutil.Uint64)(uint64(math.MaxUint64 / 2))

result, err := c.ethAPI.Call(ctx, ethapi.TransactionArgs{
Gas: &gas,
Expand Down
Loading
Loading