Skip to content

Commit

Permalink
internal/ethapi: make GetFinalizedHeader monotonically increasing (#2655
Browse files Browse the repository at this point in the history
)
  • Loading branch information
buddh0 authored Aug 20, 2024
1 parent 99a2dd5 commit 5d19f21
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 38 deletions.
6 changes: 3 additions & 3 deletions eth/api_backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -441,14 +441,14 @@ func (b *EthAPIBackend) Engine() consensus.Engine {
return b.eth.engine
}

func (b *EthAPIBackend) CurrentTurnLength() (turnLength uint8, err error) {
func (b *EthAPIBackend) CurrentValidators() ([]common.Address, error) {
if p, ok := b.eth.engine.(*parlia.Parlia); ok {
service := p.APIs(b.Chain())[0].Service
currentHead := rpc.LatestBlockNumber
return service.(*parlia.API).GetTurnLength(&currentHead)
return service.(*parlia.API).GetValidators(&currentHead)
}

return 1, nil
return []common.Address{}, errors.New("not supported")
}

func (b *EthAPIBackend) CurrentHeader() *types.Header {
Expand Down
76 changes: 47 additions & 29 deletions internal/ethapi/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -862,54 +862,72 @@ func (s *BlockChainAPI) Health() bool {
return true
}

// GetFinalizedHeader returns the requested finalized block header.
// - probabilisticFinalized should be in range [2,21],
// then the block header with number `max(fastFinalized, latest-probabilisticFinalized)` is returned
func (s *BlockChainAPI) GetFinalizedHeader(ctx context.Context, probabilisticFinalized int64) (map[string]interface{}, error) {
if probabilisticFinalized < 2 || probabilisticFinalized > 21 {
return nil, fmt.Errorf("%d out of range [2,21]", probabilisticFinalized)
func (s *BlockChainAPI) getFinalizedNumber(ctx context.Context, verifiedValidatorNum int64) (int64, error) {
parliaConfig := s.b.ChainConfig().Parlia
if parliaConfig == nil {
return 0, fmt.Errorf("only parlia engine supported")
}

currentTurnLength, err := s.b.CurrentTurnLength()
curValidators, err := s.b.CurrentValidators()
if err != nil { // impossible
return nil, err
return 0, err
}
valLen := int64(len(curValidators))
if verifiedValidatorNum < 1 || verifiedValidatorNum > valLen {
return 0, fmt.Errorf("%d out of range [1,%d]", verifiedValidatorNum, valLen)
}

fastFinalizedHeader, err := s.b.HeaderByNumber(ctx, rpc.FinalizedBlockNumber)
if err != nil { // impossible
return nil, err
return 0, err
}

latestHeader, err := s.b.HeaderByNumber(ctx, rpc.LatestBlockNumber)
if err != nil { // impossible
return nil, err
return 0, err
}
lastHeader := latestHeader
confirmedValSet := make(map[common.Address]struct{}, valLen)
confirmedValSet[lastHeader.Coinbase] = struct{}{}
for count := 1; int64(len(confirmedValSet)) < verifiedValidatorNum && count <= int(parliaConfig.Epoch) && lastHeader.Number.Int64() > max(fastFinalizedHeader.Number.Int64(), 1); count++ {
lastHeader, err = s.b.HeaderByHash(ctx, lastHeader.ParentHash)
if err != nil { // impossible
return 0, err
}
confirmedValSet[lastHeader.Coinbase] = struct{}{}
}
finalizedBlockNumber := max(fastFinalizedHeader.Number.Int64(), latestHeader.Number.Int64()-probabilisticFinalized*int64(currentTurnLength))

return s.GetHeaderByNumber(ctx, rpc.BlockNumber(finalizedBlockNumber))
}
finalizedBlockNumber := max(fastFinalizedHeader.Number.Int64(), lastHeader.Number.Int64())
log.Debug("getFinalizedNumber", "LatestBlockNumber", latestHeader.Number.Int64(), "fastFinalizedHeight", fastFinalizedHeader.Number.Int64(),
"lastHeader", lastHeader.Number.Int64(), "finalizedBlockNumber", finalizedBlockNumber, "len(confirmedValSet)", len(confirmedValSet))

// GetFinalizedBlock returns the requested finalized block.
// - probabilisticFinalized should be in range [2,21],
// then the block with number `max(fastFinalized, latest-probabilisticFinalized)` is returned
// - When fullTx is true all transactions in the block are returned, otherwise
// only the transaction hash is returned.
func (s *BlockChainAPI) GetFinalizedBlock(ctx context.Context, probabilisticFinalized int64, fullTx bool) (map[string]interface{}, error) {
if probabilisticFinalized < 2 || probabilisticFinalized > 21 {
return nil, fmt.Errorf("%d out of range [2,21]", probabilisticFinalized)
}
return finalizedBlockNumber, nil
}

currentTurnLength, err := s.b.CurrentTurnLength()
if err != nil { // impossible
return nil, err
}
fastFinalizedHeader, err := s.b.HeaderByNumber(ctx, rpc.FinalizedBlockNumber)
// GetFinalizedHeader returns the finalized block header based on the specified parameters.
// - `verifiedValidatorNum` must be within the range [1, len(currentValidators)].
// - The function calculates `probabilisticFinalizedHeight` as the highest height of the block verified by `verifiedValidatorNum` validators,
// it then returns the block header with a height equal to `max(fastFinalizedHeight, probabilisticFinalizedHeight)`.
// - The height of the returned block header is guaranteed to be monotonically increasing.
func (s *BlockChainAPI) GetFinalizedHeader(ctx context.Context, verifiedValidatorNum int64) (map[string]interface{}, error) {
finalizedBlockNumber, err := s.getFinalizedNumber(ctx, verifiedValidatorNum)
if err != nil { // impossible
return nil, err
}
latestHeader, err := s.b.HeaderByNumber(ctx, rpc.LatestBlockNumber)
return s.GetHeaderByNumber(ctx, rpc.BlockNumber(finalizedBlockNumber))
}

// GetFinalizedBlock returns the finalized block based on the specified parameters.
// - `verifiedValidatorNum` must be within the range [1, len(currentValidators)].
// - The function calculates `probabilisticFinalizedHeight` as the highest height of the block verified by `verifiedValidatorNum` validators,
// it then returns the block with a height equal to `max(fastFinalizedHeight, probabilisticFinalizedHeight)`.
// - If `fullTx` is true, the block includes all transactions; otherwise, only transaction hashes are included.
// - The height of the returned block is guaranteed to be monotonically increasing.
func (s *BlockChainAPI) GetFinalizedBlock(ctx context.Context, verifiedValidatorNum int64, fullTx bool) (map[string]interface{}, error) {
finalizedBlockNumber, err := s.getFinalizedNumber(ctx, verifiedValidatorNum)
if err != nil { // impossible
return nil, err
}
finalizedBlockNumber := max(fastFinalizedHeader.Number.Int64(), latestHeader.Number.Int64()-probabilisticFinalized*int64(currentTurnLength))

return s.GetBlockByNumber(ctx, rpc.BlockNumber(finalizedBlockNumber), fullTx)
}
Expand Down
6 changes: 3 additions & 3 deletions internal/ethapi/api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -631,9 +631,9 @@ func (b testBackend) TxPoolContentFrom(addr common.Address) ([]*types.Transactio
func (b testBackend) SubscribeNewTxsEvent(events chan<- core.NewTxsEvent) event.Subscription {
panic("implement me")
}
func (b testBackend) ChainConfig() *params.ChainConfig { return b.chain.Config() }
func (b testBackend) Engine() consensus.Engine { return b.chain.Engine() }
func (b testBackend) CurrentTurnLength() (uint8, error) { return 1, nil }
func (b testBackend) ChainConfig() *params.ChainConfig { return b.chain.Config() }
func (b testBackend) Engine() consensus.Engine { return b.chain.Engine() }
func (b testBackend) CurrentValidators() ([]common.Address, error) { return []common.Address{}, nil }
func (b testBackend) GetLogs(ctx context.Context, blockHash common.Hash, number uint64) ([][]*types.Log, error) {
panic("implement me")
}
Expand Down
4 changes: 2 additions & 2 deletions internal/ethapi/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,8 +89,8 @@ type Backend interface {

ChainConfig() *params.ChainConfig
Engine() consensus.Engine
// CurrentTurnLength return the turnLength at the latest block
CurrentTurnLength() (uint8, error)
// CurrentValidators return the list of validator at the latest block
CurrentValidators() ([]common.Address, error)

// This is copied from filters.Backend
// eth/filters needs to be initialized from this backend type, so methods needed by
Expand Down
2 changes: 1 addition & 1 deletion internal/ethapi/transaction_args_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -416,7 +416,7 @@ func (b *backendMock) SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent)

func (b *backendMock) Engine() consensus.Engine { return nil }

func (b *backendMock) CurrentTurnLength() (uint8, error) { return 1, nil }
func (b *backendMock) CurrentValidators() ([]common.Address, error) { return []common.Address{}, nil }

func (b *backendMock) MevRunning() bool { return false }
func (b *backendMock) HasBuilder(builder common.Address) bool { return false }
Expand Down

0 comments on commit 5d19f21

Please sign in to comment.