Skip to content

Commit 974bf09

Browse files
authored
add base fee chart, safe and finalized blocks to monitor (#589)
1 parent 58d9b39 commit 974bf09

File tree

3 files changed

+93
-14
lines changed

3 files changed

+93
-14
lines changed

cmd/monitor/monitor.go

Lines changed: 54 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import (
1616
_ "embed"
1717

1818
"github.com/ethereum/go-ethereum/ethclient"
19+
"github.com/ethereum/go-ethereum/rpc"
1920
ethrpc "github.com/ethereum/go-ethereum/rpc"
2021

2122
"github.com/0xPolygon/polygon-cli/cmd/monitor/ui"
@@ -64,6 +65,8 @@ type (
6465
ChainID *big.Int
6566
ForkID uint64
6667
HeadBlock *big.Int
68+
SafeBlock *big.Int
69+
FinalizedBlock *big.Int
6770
PeerCount uint64
6871
GasPrice *big.Int
6972
TxPoolStatus txPoolStatus
@@ -77,6 +80,8 @@ type (
7780
}
7881
chainState struct {
7982
HeadBlock uint64
83+
SafeBlock uint64
84+
FinalizedBlock uint64
8085
ChainID *big.Int
8186
PeerCount uint64
8287
GasPrice *big.Int
@@ -118,7 +123,8 @@ func monitor(ctx context.Context) error {
118123
return err
119124
}
120125
ec := ethclient.NewClient(rpc)
121-
if _, err = ec.BlockNumber(ctx); err != nil {
126+
latestBlockNumber, err := ec.BlockNumber(ctx)
127+
if err != nil {
122128
return err
123129
}
124130

@@ -151,6 +157,21 @@ func monitor(ctx context.Context) error {
151157
peerCountSupported = true
152158
}
153159

160+
// check if EIP-1559 is supported
161+
eip1559Supported := false
162+
latestBlock, err := ec.BlockByNumber(ctx, big.NewInt(0).SetUint64(latestBlockNumber))
163+
if err != nil {
164+
log.Debug().Err(err).Msg("Unable to get latest block")
165+
} else {
166+
if latestBlock.BaseFee() == nil {
167+
log.Debug().Msg("EIP-1559 not supported")
168+
eip1559Supported = false
169+
} else {
170+
log.Debug().Msg("EIP-1559 supported")
171+
eip1559Supported = true
172+
}
173+
}
174+
154175
ms := new(monitorStatus)
155176
ms.BlocksLock.Lock()
156177
ms.BlockCache, err = lru.New(blockCacheLimit)
@@ -191,7 +212,7 @@ func monitor(ctx context.Context) error {
191212
}
192213
if !isUiRendered {
193214
go func() {
194-
errChan <- renderMonitorUI(ctx, ec, ms, rpc, txPoolStatusSupported, zkEVMBatchesSupported)
215+
errChan <- renderMonitorUI(ctx, ec, ms, rpc, txPoolStatusSupported, zkEVMBatchesSupported, eip1559Supported)
195216
}()
196217
isUiRendered = true
197218
}
@@ -218,6 +239,22 @@ func getChainState(ctx context.Context, ec *ethclient.Client, txPoolStatusSuppor
218239
return nil, fmt.Errorf("couldn't fetch block number: %s", err.Error())
219240
}
220241

242+
safeBlock, err := ec.HeaderByNumber(ctx, big.NewInt(int64(rpc.SafeBlockNumber)))
243+
if err != nil {
244+
return nil, fmt.Errorf("couldn't fetch safe block number: %s", err.Error())
245+
}
246+
if safeBlock != nil {
247+
cs.SafeBlock = safeBlock.Number.Uint64()
248+
}
249+
250+
finalizedBlock, err := ec.HeaderByNumber(ctx, big.NewInt(int64(rpc.FinalizedBlockNumber)))
251+
if err != nil {
252+
return nil, fmt.Errorf("couldn't fetch finalized block number: %s", err.Error())
253+
}
254+
if finalizedBlock != nil {
255+
cs.FinalizedBlock = finalizedBlock.Number.Uint64()
256+
}
257+
221258
cs.ChainID, err = ec.ChainID(ctx)
222259
if err != nil {
223260
return nil, fmt.Errorf("couldn't fetch chain id: %s", err.Error())
@@ -301,6 +338,9 @@ func fetchCurrentBlockData(ctx context.Context, ec *ethclient.Client, ms *monito
301338
}
302339

303340
ms.HeadBlock = new(big.Int).SetUint64(cs.HeadBlock)
341+
ms.SafeBlock = new(big.Int).SetUint64(cs.SafeBlock)
342+
ms.FinalizedBlock = new(big.Int).SetUint64(cs.FinalizedBlock)
343+
304344
ms.ChainID = cs.ChainID
305345
ms.PeerCount = cs.PeerCount
306346
ms.GasPrice = cs.GasPrice
@@ -442,7 +482,7 @@ func (ms *monitorStatus) processBatchesConcurrently(ctx context.Context, rpc *et
442482
return errors.Join(errs...)
443483
}
444484

445-
func renderMonitorUI(ctx context.Context, ec *ethclient.Client, ms *monitorStatus, rpc *ethrpc.Client, txPoolStatusSupported, zkEVMBatchesSupported bool) error {
485+
func renderMonitorUI(ctx context.Context, ec *ethclient.Client, ms *monitorStatus, rpc *ethrpc.Client, txPoolStatusSupported, zkEVMBatchesSupported, eip1559Supported bool) error {
446486
if err := termui.Init(); err != nil {
447487
log.Error().Err(err).Msg("Failed to initialize UI")
448488
return err
@@ -451,7 +491,7 @@ func renderMonitorUI(ctx context.Context, ec *ethclient.Client, ms *monitorStatu
451491

452492
currentMode := monitorModeExplorer
453493

454-
blockTable, blockInfo, transactionList, transactionInformationList, transactionInfo, grid, selectGrid, blockGrid, transactionGrid, skeleton := ui.SetUISkeleton(txPoolStatusSupported, zkEVMBatchesSupported)
494+
blockTable, blockInfo, transactionList, transactionInformationList, transactionInfo, grid, selectGrid, blockGrid, transactionGrid, skeleton := ui.SetUISkeleton(txPoolStatusSupported, zkEVMBatchesSupported, eip1559Supported)
455495

456496
termWidth, termHeight := termui.TerminalDimensions()
457497
windowSize = termHeight/2 - 4
@@ -621,15 +661,22 @@ func renderMonitorUI(ctx context.Context, ec *ethclient.Client, ms *monitorStatu
621661
}
622662
ms.BlocksLock.RUnlock()
623663
renderedBlocks = renderedBlocksTemp
624-
renderedBlocksMeanGasPrice := metrics.GetMeanGasPricePerBlock(renderedBlocks)
664+
665+
var renderedBlocksMeanGasPrice []float64
666+
if eip1559Supported {
667+
renderedBlocksMeanGasPrice = metrics.GetMeanBaseFeePerBlock(renderedBlocks)
668+
} else {
669+
renderedBlocksMeanGasPrice = metrics.GetMeanGasPricePerBlock(renderedBlocks)
670+
}
671+
625672
// First initialization will render no gas price because the GasPriceChart will have no data.
626673
if renderedBlocksMeanGasPrice == nil {
627-
skeleton.Current.Text = ui.GetCurrentText(skeleton.Current, ms.HeadBlock, "--", ms.PeerCount, ms.ChainID, rpcUrl)
674+
skeleton.Current.Text = ui.GetCurrentText(skeleton.Current, ms.HeadBlock, ms.SafeBlock, ms.FinalizedBlock, "--", ms.PeerCount, ms.ChainID, rpcUrl)
628675
} else {
629676
if len(renderedBlocksMeanGasPrice) >= 1 {
630677
// Under normal cases, the gas price will be derived from the last element of the GasPriceChart with 2 decimal places precision.
631678
gasPriceStr := strconv.FormatFloat(renderedBlocksMeanGasPrice[len(renderedBlocksMeanGasPrice)-1]/1000000000, 'f', 2, 64)
632-
skeleton.Current.Text = ui.GetCurrentText(skeleton.Current, ms.HeadBlock, gasPriceStr, ms.PeerCount, ms.ChainID, rpcUrl)
679+
skeleton.Current.Text = ui.GetCurrentText(skeleton.Current, ms.HeadBlock, ms.SafeBlock, ms.FinalizedBlock, gasPriceStr, ms.PeerCount, ms.ChainID, rpcUrl)
633680
}
634681
}
635682

cmd/monitor/ui/ui.go

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -36,18 +36,29 @@ type UiSkeleton struct {
3636
Receipts *widgets.List
3737
}
3838

39-
func GetCurrentText(widget *widgets.Paragraph, headBlock *big.Int, gasPrice string, peerCount uint64, chainID *big.Int, rpcURL string) string {
39+
func GetCurrentText(widget *widgets.Paragraph, headBlock, safeBlock, finalizedBlock *big.Int, gasPrice string, peerCount uint64, chainID *big.Int, rpcURL string) string {
4040
// First column
4141
height := fmt.Sprintf("Height: %s", headBlock.String())
42-
timeInfo := fmt.Sprintf("Time: %s", time.Now().Format("02 Jan 06 15:04:05 MST"))
42+
safeBlockString := fmt.Sprintf("Safe: %s", safeBlock.String())
43+
finalizedString := fmt.Sprintf("Finalized: %s", finalizedBlock.String())
4344
gasPriceString := fmt.Sprintf("Gas Price: %s gwei", gasPrice)
44-
peers := fmt.Sprintf("Peers: %d", peerCount)
4545

4646
// Second column
47+
currentTimeString := fmt.Sprintf("Time: %s", time.Now().Format("02 Jan 06 15:04:05 MST"))
4748
rpcURLString := fmt.Sprintf("RPC URL: %s", rpcURL)
48-
chainIdString := fmt.Sprintf("Chain ID: %s", chainID.String())
49+
chainIDString := fmt.Sprintf("Chain ID: %s", chainID.String())
50+
peers := fmt.Sprintf("Peers: %d", peerCount)
4951

50-
return formatParagraph(widget, []string{height, timeInfo, gasPriceString, peers, chainIdString, rpcURLString})
52+
return formatParagraph(widget, []string{
53+
height,
54+
safeBlockString,
55+
finalizedString,
56+
gasPriceString,
57+
currentTimeString,
58+
chainIDString,
59+
rpcURLString,
60+
peers,
61+
})
5162
}
5263

5364
func GetTxPoolText(widget *widgets.Paragraph, pendingTxCount, queuedTxCount uint64) string {
@@ -500,7 +511,7 @@ func GetSimpleReceipt(ctx context.Context, rpc *ethrpc.Client, tx rpctypes.PolyT
500511
return fields
501512
}
502513

503-
func SetUISkeleton(txPoolStatusSupported, zkEVMBatchesSupported bool) (blockList *widgets.List, blockInfo *widgets.List, transactionList *widgets.List, transactionInformationList *widgets.List, transactionInfo *widgets.Table, grid *ui.Grid, selectGrid *ui.Grid, blockGrid *ui.Grid, transactionGrid *ui.Grid, termUi UiSkeleton) {
514+
func SetUISkeleton(txPoolStatusSupported, zkEVMBatchesSupported, eip1559Supported bool) (blockList *widgets.List, blockInfo *widgets.List, transactionList *widgets.List, transactionInformationList *widgets.List, transactionInfo *widgets.Table, grid *ui.Grid, selectGrid *ui.Grid, blockGrid *ui.Grid, transactionGrid *ui.Grid, termUi UiSkeleton) {
504515
// help := widgets.NewParagraph()
505516
// help.Title = "Block Headers"
506517
// help.Text = "Use the arrow keys to scroll through the transactions. Press <Esc> to go back to the explorer view"
@@ -564,7 +575,11 @@ func SetUISkeleton(txPoolStatusSupported, zkEVMBatchesSupported bool) (blockList
564575
termUi.GasPriceChart.LineColor = ui.ColorGreen
565576
termUi.GasPriceChart.MaxHeight = 1000
566577
slg1 := widgets.NewSparklineGroup(termUi.GasPriceChart)
567-
slg1.Title = "Gas Price"
578+
if eip1559Supported {
579+
slg1.Title = "Base fee"
580+
} else {
581+
slg1.Title = "Gas Price"
582+
}
568583

569584
termUi.BlockSizeChart = widgets.NewSparkline()
570585
termUi.BlockSizeChart.LineColor = ui.ColorYellow

metrics/metrics.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,23 @@ func GetMeanGasPricePerBlock(blocks []rpctypes.PolyBlock) []float64 {
107107
return gasPrices
108108
}
109109

110+
// GetMeanBaseFeePerBlock calculates the mean base fee for each block in the provided slice of PolyBlock.
111+
// It returns a slice of float64 values representing the base fee for each block.
112+
func GetMeanBaseFeePerBlock(blocks []rpctypes.PolyBlock) []float64 {
113+
bs := rpctypes.SortableBlocks(blocks)
114+
sort.Sort(bs)
115+
116+
fee := make([]float64, 0, len(bs))
117+
for _, b := range bs {
118+
if b.BaseFee() != nil {
119+
fee = append(fee, float64(b.BaseFee().Uint64()))
120+
} else {
121+
fee = append(fee, 0.0)
122+
}
123+
}
124+
return fee
125+
}
126+
110127
func TruncateHexString(hexStr string, totalLength int) string {
111128
hexStr = strings.TrimPrefix(hexStr, "0x")
112129

0 commit comments

Comments
 (0)