internal/ethapi: make GetFinalizedHeader monotonically increasing (#2655)
This commit is contained in:
parent
99a2dd5ed9
commit
5d19f2182b
@ -441,14 +441,14 @@ func (b *EthAPIBackend) Engine() consensus.Engine {
|
|||||||
return b.eth.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 {
|
if p, ok := b.eth.engine.(*parlia.Parlia); ok {
|
||||||
service := p.APIs(b.Chain())[0].Service
|
service := p.APIs(b.Chain())[0].Service
|
||||||
currentHead := rpc.LatestBlockNumber
|
currentHead := rpc.LatestBlockNumber
|
||||||
return service.(*parlia.API).GetTurnLength(¤tHead)
|
return service.(*parlia.API).GetValidators(¤tHead)
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1, nil
|
return []common.Address{}, errors.New("not supported")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *EthAPIBackend) CurrentHeader() *types.Header {
|
func (b *EthAPIBackend) CurrentHeader() *types.Header {
|
||||||
|
@ -862,54 +862,72 @@ func (s *BlockChainAPI) Health() bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetFinalizedHeader returns the requested finalized block header.
|
func (s *BlockChainAPI) getFinalizedNumber(ctx context.Context, verifiedValidatorNum int64) (int64, error) {
|
||||||
// - probabilisticFinalized should be in range [2,21],
|
parliaConfig := s.b.ChainConfig().Parlia
|
||||||
// then the block header with number `max(fastFinalized, latest-probabilisticFinalized)` is returned
|
if parliaConfig == nil {
|
||||||
func (s *BlockChainAPI) GetFinalizedHeader(ctx context.Context, probabilisticFinalized int64) (map[string]interface{}, error) {
|
return 0, fmt.Errorf("only parlia engine supported")
|
||||||
if probabilisticFinalized < 2 || probabilisticFinalized > 21 {
|
|
||||||
return nil, fmt.Errorf("%d out of range [2,21]", probabilisticFinalized)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
currentTurnLength, err := s.b.CurrentTurnLength()
|
curValidators, err := s.b.CurrentValidators()
|
||||||
if err != nil { // impossible
|
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)
|
fastFinalizedHeader, err := s.b.HeaderByNumber(ctx, rpc.FinalizedBlockNumber)
|
||||||
if err != nil { // impossible
|
if err != nil { // impossible
|
||||||
return nil, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
latestHeader, err := s.b.HeaderByNumber(ctx, rpc.LatestBlockNumber)
|
latestHeader, err := s.b.HeaderByNumber(ctx, rpc.LatestBlockNumber)
|
||||||
|
if err != nil { // impossible
|
||||||
|
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(), lastHeader.Number.Int64())
|
||||||
|
log.Debug("getFinalizedNumber", "LatestBlockNumber", latestHeader.Number.Int64(), "fastFinalizedHeight", fastFinalizedHeader.Number.Int64(),
|
||||||
|
"lastHeader", lastHeader.Number.Int64(), "finalizedBlockNumber", finalizedBlockNumber, "len(confirmedValSet)", len(confirmedValSet))
|
||||||
|
|
||||||
|
return finalizedBlockNumber, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
if err != nil { // impossible
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
finalizedBlockNumber := max(fastFinalizedHeader.Number.Int64(), latestHeader.Number.Int64()-probabilisticFinalized*int64(currentTurnLength))
|
|
||||||
|
|
||||||
return s.GetHeaderByNumber(ctx, rpc.BlockNumber(finalizedBlockNumber))
|
return s.GetHeaderByNumber(ctx, rpc.BlockNumber(finalizedBlockNumber))
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetFinalizedBlock returns the requested finalized block.
|
// GetFinalizedBlock returns the finalized block based on the specified parameters.
|
||||||
// - probabilisticFinalized should be in range [2,21],
|
// - `verifiedValidatorNum` must be within the range [1, len(currentValidators)].
|
||||||
// then the block with number `max(fastFinalized, latest-probabilisticFinalized)` is returned
|
// - The function calculates `probabilisticFinalizedHeight` as the highest height of the block verified by `verifiedValidatorNum` validators,
|
||||||
// - When fullTx is true all transactions in the block are returned, otherwise
|
// it then returns the block with a height equal to `max(fastFinalizedHeight, probabilisticFinalizedHeight)`.
|
||||||
// only the transaction hash is returned.
|
// - If `fullTx` is true, the block includes all transactions; otherwise, only transaction hashes are included.
|
||||||
func (s *BlockChainAPI) GetFinalizedBlock(ctx context.Context, probabilisticFinalized int64, fullTx bool) (map[string]interface{}, error) {
|
// - The height of the returned block is guaranteed to be monotonically increasing.
|
||||||
if probabilisticFinalized < 2 || probabilisticFinalized > 21 {
|
func (s *BlockChainAPI) GetFinalizedBlock(ctx context.Context, verifiedValidatorNum int64, fullTx bool) (map[string]interface{}, error) {
|
||||||
return nil, fmt.Errorf("%d out of range [2,21]", probabilisticFinalized)
|
finalizedBlockNumber, err := s.getFinalizedNumber(ctx, verifiedValidatorNum)
|
||||||
}
|
|
||||||
|
|
||||||
currentTurnLength, err := s.b.CurrentTurnLength()
|
|
||||||
if err != nil { // impossible
|
if err != nil { // impossible
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
fastFinalizedHeader, err := s.b.HeaderByNumber(ctx, rpc.FinalizedBlockNumber)
|
|
||||||
if err != nil { // impossible
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
latestHeader, err := s.b.HeaderByNumber(ctx, rpc.LatestBlockNumber)
|
|
||||||
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)
|
return s.GetBlockByNumber(ctx, rpc.BlockNumber(finalizedBlockNumber), fullTx)
|
||||||
}
|
}
|
||||||
|
@ -633,7 +633,7 @@ func (b testBackend) SubscribeNewTxsEvent(events chan<- core.NewTxsEvent) event.
|
|||||||
}
|
}
|
||||||
func (b testBackend) ChainConfig() *params.ChainConfig { return b.chain.Config() }
|
func (b testBackend) ChainConfig() *params.ChainConfig { return b.chain.Config() }
|
||||||
func (b testBackend) Engine() consensus.Engine { return b.chain.Engine() }
|
func (b testBackend) Engine() consensus.Engine { return b.chain.Engine() }
|
||||||
func (b testBackend) CurrentTurnLength() (uint8, error) { return 1, nil }
|
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) {
|
func (b testBackend) GetLogs(ctx context.Context, blockHash common.Hash, number uint64) ([][]*types.Log, error) {
|
||||||
panic("implement me")
|
panic("implement me")
|
||||||
}
|
}
|
||||||
|
@ -89,8 +89,8 @@ type Backend interface {
|
|||||||
|
|
||||||
ChainConfig() *params.ChainConfig
|
ChainConfig() *params.ChainConfig
|
||||||
Engine() consensus.Engine
|
Engine() consensus.Engine
|
||||||
// CurrentTurnLength return the turnLength at the latest block
|
// CurrentValidators return the list of validator at the latest block
|
||||||
CurrentTurnLength() (uint8, error)
|
CurrentValidators() ([]common.Address, error)
|
||||||
|
|
||||||
// This is copied from filters.Backend
|
// This is copied from filters.Backend
|
||||||
// eth/filters needs to be initialized from this backend type, so methods needed by
|
// eth/filters needs to be initialized from this backend type, so methods needed by
|
||||||
|
@ -416,7 +416,7 @@ func (b *backendMock) SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent)
|
|||||||
|
|
||||||
func (b *backendMock) Engine() consensus.Engine { return nil }
|
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) MevRunning() bool { return false }
|
||||||
func (b *backendMock) HasBuilder(builder common.Address) bool { return false }
|
func (b *backendMock) HasBuilder(builder common.Address) bool { return false }
|
||||||
|
Loading…
Reference in New Issue
Block a user