Skip to content

Commit e417f74

Browse files
authored
feat: add blocks node graph (#1215)
1 parent e17070b commit e417f74

File tree

6 files changed

+202
-11
lines changed

6 files changed

+202
-11
lines changed

lib/lambda_ethereum_consensus/beacon/pending_blocks.ex

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ defmodule LambdaEthereumConsensus.Beacon.PendingBlocks do
77
require Logger
88

99
alias LambdaEthereumConsensus.ForkChoice
10+
alias LambdaEthereumConsensus.Libp2pPort
11+
alias LambdaEthereumConsensus.P2P.BlockDownloader
12+
13+
alias LambdaEthereumConsensus.Metrics
1014
alias LambdaEthereumConsensus.P2P.BlobDownloader
1115
alias LambdaEthereumConsensus.Store.BlobDb
1216
alias LambdaEthereumConsensus.Store.Blocks
@@ -19,6 +23,8 @@ defmodule LambdaEthereumConsensus.Beacon.PendingBlocks do
1923
| {nil, :invalid | :download}
2024
@type state :: nil
2125

26+
@download_retries 100
27+
2228
@doc """
2329
If the block is not present, it will be stored as pending.
2430
@@ -44,7 +50,7 @@ defmodule LambdaEthereumConsensus.Beacon.PendingBlocks do
4450
Blocks.new_block_info(block_info)
4551
process_block_and_check_children(block_info)
4652
else
47-
BlobDownloader.request_blobs_by_root(missing_blobs, &process_blobs/1, 30)
53+
BlobDownloader.request_blobs_by_root(missing_blobs, &process_blobs/1, @download_retries)
4854

4955
block_info
5056
|> BlockInfo.change_status(:download_blobs)
@@ -90,7 +96,22 @@ defmodule LambdaEthereumConsensus.Beacon.PendingBlocks do
9096

9197
case Blocks.get_block_info(parent_root) do
9298
nil ->
99+
Logger.debug("[PendingBlocks] Add parent to download #{inspect(parent_root)}")
93100
Blocks.add_block_to_download(parent_root)
101+
102+
BlockDownloader.request_blocks_by_root(
103+
[parent_root],
104+
fn result ->
105+
process_downloaded_block(result)
106+
end,
107+
@download_retries
108+
)
109+
110+
Metrics.block_relationship(
111+
parent_root,
112+
block_info.root
113+
)
114+
94115
:download_pending
95116

96117
%BlockInfo{status: :invalid} ->
@@ -118,6 +139,16 @@ defmodule LambdaEthereumConsensus.Beacon.PendingBlocks do
118139
end
119140
end
120141

142+
defp process_downloaded_block({:ok, [block]}) do
143+
Libp2pPort.add_block(block)
144+
end
145+
146+
defp process_downloaded_block({:error, reason}) do
147+
Logger.error("Error downloading block: #{inspect(reason)}")
148+
149+
# We might want to declare a block invalid here.
150+
end
151+
121152
defp process_blobs({:ok, blobs}), do: add_blobs(blobs)
122153

123154
defp process_blobs({:error, reason}) do

lib/lambda_ethereum_consensus/fork_choice/fork_choice.ex

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ defmodule LambdaEthereumConsensus.ForkChoice do
99
alias LambdaEthereumConsensus.Execution.ExecutionChain
1010
alias LambdaEthereumConsensus.ForkChoice.Handlers
1111
alias LambdaEthereumConsensus.ForkChoice.Head
12+
alias LambdaEthereumConsensus.Metrics
1213
alias LambdaEthereumConsensus.P2P.Gossip.OperationsCollector
1314
alias LambdaEthereumConsensus.StateTransition.Misc
1415
alias LambdaEthereumConsensus.Store.BlobDb
@@ -27,14 +28,16 @@ defmodule LambdaEthereumConsensus.ForkChoice do
2728
##########################
2829

2930
@spec init_store(Store.t(), Types.uint64()) :: :ok | :error
30-
def init_store(%Store{head_slot: head_slot} = store, time) do
31+
def init_store(%Store{head_slot: head_slot, head_root: head_root} = store, time) do
3132
Logger.info("[Fork choice] Initialized store.", slot: head_slot)
3233

3334
store = Handlers.on_tick(store, time)
3435

3536
:telemetry.execute([:sync, :store], %{slot: Store.get_current_slot(store)})
3637
:telemetry.execute([:sync, :on_block], %{slot: head_slot})
3738

39+
Metrics.block_status(head_root, head_slot, :transitioned)
40+
3841
persist_store(store)
3942
end
4043

lib/lambda_ethereum_consensus/metrics.ex

Lines changed: 53 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ defmodule LambdaEthereumConsensus.Metrics do
22
@moduledoc """
33
Basic telemetry metric generation to be used across the node.
44
"""
5+
alias LambdaEthereumConsensus.Store.Blocks
6+
require Logger
57

68
def tracer({:add_peer, %{}}) do
79
:telemetry.execute([:network, :pubsub_peers], %{}, %{result: "add"})
@@ -68,13 +70,59 @@ defmodule LambdaEthereumConsensus.Metrics do
6870
end
6971
end
7072

71-
def block_status(root, status) do
72-
hex_root = root |> Base.encode16()
73+
def block_status(root, slot, new_status) do
74+
block_status_execute(root, new_status, slot, 1)
75+
end
7376

74-
:telemetry.execute([:blocks, :status], %{}, %{
75-
mainstat: status,
77+
@doc """
78+
- Sets the old status to '0' to deactivate it and sets the new status to '1' so that we can filter the Grafana table.
79+
- If the old status is ':download', it will be deactivated with a 'nil' slot, since that's how it was activated.
80+
"""
81+
def block_status(root, slot, :download, new_status) do
82+
block_status_execute(root, :download, nil, 0)
83+
block_status_execute(root, new_status, slot, 1)
84+
end
85+
86+
def block_status(root, slot, old_status, new_status) do
87+
block_status_execute(root, old_status, slot, 0)
88+
block_status_execute(root, new_status, slot, 1)
89+
end
90+
91+
defp block_status_execute(root, status, slot, value) do
92+
hex_root = Base.encode16(root)
93+
94+
Logger.debug(
95+
"[Metrics] slot = #{inspect(slot)}, status = #{inspect(status)}, value = #{inspect(value)}"
96+
)
97+
98+
:telemetry.execute([:blocks, :status], %{total: value}, %{
7699
id: hex_root,
77-
title: hex_root
100+
mainstat: status,
101+
color: map_color(status),
102+
title: slot,
103+
detail__root: hex_root
78104
})
79105
end
106+
107+
def block_relationship(nil, _), do: :ok
108+
109+
def block_relationship(parent_root, root) do
110+
# If we try to add an edge to a non-existent node, it will crash.
111+
if Blocks.get_block_info(parent_root) do
112+
hex_parent_root = parent_root |> Base.encode16()
113+
hex_root = root |> Base.encode16()
114+
115+
:telemetry.execute([:blocks, :relationship], %{total: 1}, %{
116+
id: hex_root <> hex_parent_root,
117+
source: hex_parent_root,
118+
target: hex_root
119+
})
120+
end
121+
end
122+
123+
defp map_color(:transitioned), do: "blue"
124+
defp map_color(:pending), do: "green"
125+
defp map_color(:download_blobs), do: "yellow"
126+
defp map_color(:download), do: "orange"
127+
defp map_color(:invalid), do: "red"
80128
end

lib/lambda_ethereum_consensus/store/blocks.ex

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,21 +82,44 @@ defmodule LambdaEthereumConsensus.Store.Blocks do
8282
# list. If it's not in the list, the operation is equivalent to only adding it in the correct
8383
# one.
8484
BlockDb.change_root_status(block_info.root, :download, block_info.status)
85+
86+
{slot, parent_root} =
87+
if block_info.signed_block do
88+
{block_info.signed_block.message.slot, block_info.signed_block.message.parent_root}
89+
else
90+
{nil, nil}
91+
end
92+
93+
Metrics.block_status(
94+
block_info.root,
95+
slot,
96+
:download,
97+
block_info.status
98+
)
99+
100+
Metrics.block_relationship(parent_root, block_info.root)
85101
end
86102

87103
@doc """
88104
Changes the status of a block in the db. Returns the block with the modified status.
89105
"""
90106
@spec change_status(BlockInfo.t(), BlockInfo.block_status()) :: BlockInfo.t()
91107
def change_status(block_info, status) do
92-
Metrics.block_status(block_info.root, status)
93-
94108
new_block_info = BlockInfo.change_status(block_info, status)
95109
store_block_info(new_block_info)
96110

97111
old_status = block_info.status
98112
BlockDb.change_root_status(block_info.root, old_status, status)
99113

114+
Metrics.block_status(
115+
block_info.root,
116+
block_info.signed_block.message.slot,
117+
old_status,
118+
status
119+
)
120+
121+
Metrics.block_relationship(block_info.signed_block.message.parent_root, block_info.root)
122+
100123
new_block_info
101124
end
102125

lib/lambda_ethereum_consensus/telemetry.ex

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,10 @@ defmodule LambdaEthereumConsensus.Telemetry do
148148
last_value("fork_choice.recompute_head.exception.duration",
149149
unit: {:native, :millisecond}
150150
),
151-
counter("blocks.status.count", tags: [:title, :mainstat, :id])
151+
last_value("blocks.status.total", tags: [:id, :mainstat, :color, :title, :detail__root]),
152+
last_value("blocks.relationship.total",
153+
tags: [:id, :source, :target]
154+
)
152155
]
153156
end
154157

metrics/grafana/provisioning/dashboards/home.json

Lines changed: 84 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,89 @@
2828
"links": [],
2929
"liveNow": false,
3030
"panels": [
31+
{
32+
"datasource": {
33+
"uid": "PBFA97CFB590B2093",
34+
"type": "prometheus"
35+
},
36+
"gridPos": {
37+
"h": 8,
38+
"w": 12,
39+
"x": 0,
40+
"y": 0
41+
},
42+
"id": 31,
43+
"options": {
44+
"nodes": {},
45+
"edges": {}
46+
},
47+
"targets": [
48+
{
49+
"datasource": {
50+
"type": "prometheus",
51+
"uid": "PBFA97CFB590B2093"
52+
},
53+
"disableTextWrap": false,
54+
"editorMode": "builder",
55+
"expr": "blocks_status_total",
56+
"format": "table",
57+
"fullMetaSearch": false,
58+
"includeNullMetadata": true,
59+
"instant": true,
60+
"legendFormat": "__auto",
61+
"range": false,
62+
"refId": "A",
63+
"useBackend": false,
64+
"exemplar": false
65+
},
66+
{
67+
"datasource": {
68+
"type": "prometheus",
69+
"uid": "PBFA97CFB590B2093"
70+
},
71+
"disableTextWrap": false,
72+
"editorMode": "builder",
73+
"expr": "blocks_relationship_total",
74+
"format": "table",
75+
"fullMetaSearch": false,
76+
"hide": false,
77+
"includeNullMetadata": true,
78+
"instant": true,
79+
"legendFormat": "__auto",
80+
"range": false,
81+
"refId": "B",
82+
"useBackend": false,
83+
"exemplar": false
84+
}
85+
],
86+
"title": "Blockchain View",
87+
"transformations": [
88+
{
89+
"id": "filterByValue",
90+
"options": {
91+
"filters": [
92+
{
93+
"fieldName": "Value #A",
94+
"config": {
95+
"id": "equal",
96+
"options": {
97+
"value": 0
98+
}
99+
}
100+
}
101+
],
102+
"type": "exclude",
103+
"match": "any"
104+
},
105+
"filter": {
106+
"id": "byRefId",
107+
"options": "A"
108+
},
109+
"topic": "series"
110+
}
111+
],
112+
"type": "nodeGraph"
113+
},
31114
{
32115
"datasource": {
33116
"type": "prometheus",
@@ -2698,4 +2781,4 @@
26982781
"uid": "90EXFQnIk",
26992782
"version": 3,
27002783
"weekStart": ""
2701-
}
2784+
}

0 commit comments

Comments
 (0)