@@ -7,14 +7,14 @@ defmodule LambdaEthereumConsensus.Beacon.PendingBlocks do
7
7
require Logger
8
8
9
9
alias LambdaEthereumConsensus.ForkChoice
10
- alias LambdaEthereumConsensus.P2P.BlockDownloader
11
-
12
10
alias LambdaEthereumConsensus.Metrics
13
11
alias LambdaEthereumConsensus.P2P.BlobDownloader
12
+ alias LambdaEthereumConsensus.P2P.BlockDownloader
14
13
alias LambdaEthereumConsensus.Store.BlobDb
15
14
alias LambdaEthereumConsensus.Store.Blocks
16
15
alias Types.BlockInfo
17
16
alias Types.SignedBeaconBlock
17
+ alias Types.Store
18
18
19
19
@ type block_status :: :pending | :invalid | :download | :download_blobs | :unknown
20
20
@ type block_info ::
@@ -36,8 +36,8 @@ defmodule LambdaEthereumConsensus.Beacon.PendingBlocks do
36
36
37
37
If blobs are missing, they will be requested.
38
38
"""
39
- @ spec add_block ( SignedBeaconBlock . t ( ) ) :: :ok
40
- def add_block ( signed_block ) do
39
+ @ spec add_block ( Store . t ( ) , SignedBeaconBlock . t ( ) ) :: Store . t ( )
40
+ def add_block ( store , signed_block ) do
41
41
block_info = BlockInfo . from_block ( signed_block )
42
42
loaded_block = Blocks . get_block_info ( block_info . root )
43
43
@@ -47,14 +47,18 @@ defmodule LambdaEthereumConsensus.Beacon.PendingBlocks do
47
47
48
48
if Enum . empty? ( missing_blobs ) do
49
49
Blocks . new_block_info ( block_info )
50
- process_block_and_check_children ( block_info )
50
+ process_block_and_check_children ( store , block_info )
51
51
else
52
- BlobDownloader . request_blobs_by_root ( missing_blobs , & process_blobs / 1 , @ download_retries )
52
+ BlobDownloader . request_blobs_by_root ( missing_blobs , & process_blobs / 2 , @ download_retries )
53
53
54
54
block_info
55
55
|> BlockInfo . change_status ( :download_blobs )
56
56
|> Blocks . new_block_info ( )
57
+
58
+ store
57
59
end
60
+ else
61
+ store
58
62
end
59
63
end
60
64
@@ -63,17 +67,22 @@ defmodule LambdaEthereumConsensus.Beacon.PendingBlocks do
63
67
module after receiving a new block, but there are some other cases like at node startup, as there
64
68
may be pending blocks from prior executions.
65
69
"""
66
- def process_blocks ( ) do
70
+ def process_blocks ( store ) do
67
71
case Blocks . get_blocks_with_status ( :pending ) do
68
72
{ :ok , blocks } ->
69
73
blocks
70
74
|> Enum . sort_by ( fn % BlockInfo { } = block_info -> block_info . signed_block . message . slot end )
71
- |> Enum . each ( & process_block / 1 )
75
+ |> Enum . reduce ( store , fn block_info , store ->
76
+ { store , _state } = process_block ( store , block_info )
77
+ store
78
+ end )
72
79
73
80
{ :error , reason } ->
74
81
Logger . error (
75
82
"[Pending Blocks] Failed to get pending blocks to process. Reason: #{ reason } "
76
83
)
84
+
85
+ store
77
86
end
78
87
end
79
88
@@ -85,13 +94,14 @@ defmodule LambdaEthereumConsensus.Beacon.PendingBlocks do
85
94
# is called to check if there's any children that can now be processed. This function
86
95
# is only to be called when a new block is saved as pending, not when processing blocks
87
96
# in batch, to avoid unneeded recursion.
88
- defp process_block_and_check_children ( block_info ) do
89
- if process_block ( block_info ) in [ :transitioned , :invalid ] do
90
- process_blocks ( )
97
+ defp process_block_and_check_children ( store , block_info ) do
98
+ case process_block ( store , block_info ) do
99
+ { store , result } when result in [ :transitioned , :invalid ] -> process_blocks ( store )
100
+ { store , _other } -> store
91
101
end
92
102
end
93
103
94
- defp process_block ( block_info ) do
104
+ defp process_block ( store , block_info ) do
95
105
if block_info . status != :pending do
96
106
Logger . error ( "Called process block for a block that's not ready: #{ block_info } " )
97
107
end
@@ -105,9 +115,7 @@ defmodule LambdaEthereumConsensus.Beacon.PendingBlocks do
105
115
106
116
BlockDownloader . request_blocks_by_root (
107
117
[ parent_root ] ,
108
- fn result ->
109
- process_downloaded_block ( result )
110
- end ,
118
+ & process_downloaded_block / 2 ,
111
119
@ download_retries
112
120
)
113
121
@@ -116,65 +124,67 @@ defmodule LambdaEthereumConsensus.Beacon.PendingBlocks do
116
124
block_info . root
117
125
)
118
126
119
- :download_pending
127
+ { store , :download_pending }
120
128
121
129
% BlockInfo { status: :invalid } ->
122
130
Blocks . change_status ( block_info , :invalid )
123
- :invalid
131
+ { store , :invalid }
124
132
125
133
% BlockInfo { status: :transitioned } ->
126
- case ForkChoice . on_block ( block_info ) do
127
- :ok ->
134
+ case ForkChoice . on_block ( store , block_info ) do
135
+ { :ok , store } ->
128
136
Blocks . change_status ( block_info , :transitioned )
129
- :transitioned
137
+ { store , :transitioned }
130
138
131
- { :error , reason } ->
139
+ { :error , reason , store } ->
132
140
Logger . error ( "[PendingBlocks] Saving block as invalid #{ reason } " ,
133
141
slot: block_info . signed_block . message . slot ,
134
142
root: block_info . root
135
143
)
136
144
137
145
Blocks . change_status ( block_info , :invalid )
138
- :invalid
146
+ { store , :invalid }
139
147
end
140
148
141
149
_other ->
142
- :ok
150
+ { store , :ok }
143
151
end
144
152
end
145
153
146
- defp process_downloaded_block ( { :ok , [ block ] } ) do
147
- add_block ( block )
154
+ defp process_downloaded_block ( store , { :ok , [ block ] } ) do
155
+ { :ok , add_block ( store , block ) }
148
156
end
149
157
150
- defp process_downloaded_block ( { :error , reason } ) do
151
- Logger . error ( "Error downloading block: #{ inspect ( reason ) } " )
152
-
158
+ defp process_downloaded_block ( store , { :error , reason } ) do
153
159
# We might want to declare a block invalid here.
160
+ Logger . error ( "Error downloading block: #{ inspect ( reason ) } " )
161
+ { :ok , store }
154
162
end
155
163
156
- defp process_blobs ( { :ok , blobs } ) , do: add_blobs ( blobs )
157
-
158
- defp process_blobs ( { :error , reason } ) do
159
- Logger . error ( "Error downloading blobs: #{ inspect ( reason ) } " )
164
+ defp process_blobs ( store , { :ok , blobs } ) , do: { :ok , add_blobs ( store , blobs ) }
160
165
166
+ defp process_blobs ( store , { :error , reason } ) do
161
167
# We might want to declare a block invalid here.
168
+ Logger . error ( "Error downloading blobs: #{ inspect ( reason ) } " )
169
+ { :ok , store }
162
170
end
163
171
172
+ def add_blob ( store , blob ) , do: add_blobs ( store , [ blob ] )
173
+
164
174
# To be used when a series of blobs are downloaded. Stores each blob.
165
175
# If there are blocks that can be processed, does so immediately.
166
- defp add_blobs ( blobs ) do
176
+ defp add_blobs ( store , blobs ) do
167
177
blobs
168
178
|> Enum . map ( & BlobDb . store_blob / 1 )
169
179
|> Enum . uniq ( )
170
- |> Enum . each ( fn root ->
171
- with % BlockInfo { } = block_info <- Blocks . get_block_info ( root ) do
172
- # TODO: add a new missing blobs call if some blobs are still missing for a block.
173
- if Enum . empty? ( missing_blobs ( block_info ) ) do
174
- block_info
175
- |> Blocks . change_status ( :pending )
176
- |> process_block_and_check_children ( )
177
- end
180
+ |> Enum . reduce ( store , fn root , store ->
181
+ with % BlockInfo { } = block_info <- Blocks . get_block_info ( root ) ,
182
+ [ ] <- missing_blobs ( block_info ) do
183
+ block_info
184
+ |> Blocks . change_status ( :pending )
185
+ |> then ( & process_block_and_check_children ( store , & 1 ) )
186
+ else
187
+ _ -> store
178
188
end
179
189
end )
180
190
end
0 commit comments