14
14
// You should have received a copy of the GNU General Public License
15
15
// along with this program. If not, see <http://www.gnu.org/licenses/>.
16
16
17
- use std:: fmt;
18
- use std:: str:: FromStr ;
19
-
20
17
use regex:: { Captures , Regex } ;
21
18
use stacks_common:: types:: net:: PeerHost ;
22
- use stacks_common:: types:: StacksEpochId ;
23
19
24
- use crate :: net:: db:: PeerDB ;
25
20
use crate :: net:: http:: {
26
21
parse_json, Error , HttpRequest , HttpRequestContents , HttpRequestPreamble , HttpResponse ,
27
22
HttpResponseContents , HttpResponsePayload , HttpResponsePreamble , HttpServerError ,
28
23
} ;
29
24
use crate :: net:: httpcore:: { RPCRequestHandler , StacksHttpRequest , StacksHttpResponse } ;
30
- use crate :: net:: {
31
- infer_initial_burnchain_block_download, Error as NetError , NeighborAddress , StacksNodeState ,
32
- } ;
25
+ use crate :: net:: { Error as NetError , StacksNodeState } ;
33
26
34
27
/// The response for the GET /v3/health endpoint
35
28
/// This endpoint returns the difference in height between the node and its most advanced neighbor
@@ -42,57 +35,19 @@ pub struct RPCGetHealthResponse {
42
35
pub difference_from_max_peer : u64 ,
43
36
/// the max height of the node's most advanced neighbor
44
37
pub max_stacks_height_of_neighbors : u64 ,
38
+ /// the address of the node's most advanced neighbor
39
+ pub max_stacks_neighbor_address : Option < String > ,
45
40
/// the height of this node
46
41
pub node_stacks_tip_height : u64 ,
47
42
}
48
43
49
- const NEIGHBORS_SCOPE_PARAM_NAME : & str = "neighbors" ;
50
-
51
- #[ derive( Clone , Debug , PartialEq ) ]
52
- pub enum NeighborsScope {
53
- Initial ,
54
- All ,
55
- }
56
-
57
- impl FromStr for NeighborsScope {
58
- type Err = crate :: net:: http:: Error ;
59
-
60
- fn from_str ( s : & str ) -> Result < Self , Self :: Err > {
61
- match s {
62
- "initial" => Ok ( NeighborsScope :: Initial ) ,
63
- "all" => Ok ( NeighborsScope :: All ) ,
64
- _ => Err ( crate :: net:: http:: Error :: Http (
65
- 400 ,
66
- format ! (
67
- "Invalid `neighbors` query parameter: `{}`, allowed values are `initial` or `all`" ,
68
- s
69
- ) ,
70
- ) ) ,
71
- }
72
- }
73
- }
74
-
75
- impl fmt:: Display for NeighborsScope {
76
- fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
77
- let s = match self {
78
- NeighborsScope :: Initial => "initial" ,
79
- NeighborsScope :: All => "all" ,
80
- } ;
81
- write ! ( f, "{s}" )
82
- }
83
- }
84
-
85
44
#[ derive( Clone ) ]
86
45
/// Empty request handler for the GET /v3/health endpoint
87
- pub struct RPCGetHealthRequestHandler {
88
- neighbors_scope : Option < NeighborsScope > ,
89
- }
46
+ pub struct RPCGetHealthRequestHandler { }
90
47
91
48
impl RPCGetHealthRequestHandler {
92
49
pub fn new ( ) -> Self {
93
- Self {
94
- neighbors_scope : None ,
95
- }
50
+ Self { }
96
51
}
97
52
}
98
53
@@ -125,12 +80,7 @@ impl HttpRequest for RPCGetHealthRequestHandler {
125
80
) ) ;
126
81
}
127
82
128
- let req_contents = HttpRequestContents :: new ( ) . query_string ( query) ;
129
- if let Some ( scope) = req_contents. get_query_arg ( NEIGHBORS_SCOPE_PARAM_NAME ) {
130
- self . neighbors_scope = Some ( scope. parse ( ) ?) ;
131
- }
132
-
133
- Ok ( req_contents)
83
+ Ok ( HttpRequestContents :: new ( ) . query_string ( query) )
134
84
}
135
85
}
136
86
@@ -145,9 +95,7 @@ fn create_error_response(
145
95
146
96
impl RPCRequestHandler for RPCGetHealthRequestHandler {
147
97
/// Reset internal state
148
- fn restart ( & mut self ) {
149
- self . neighbors_scope = None ;
150
- }
98
+ fn restart ( & mut self ) { }
151
99
152
100
/// Make the response
153
101
fn try_handle_request (
@@ -156,97 +104,30 @@ impl RPCRequestHandler for RPCGetHealthRequestHandler {
156
104
_contents : HttpRequestContents ,
157
105
node : & mut StacksNodeState ,
158
106
) -> Result < ( HttpResponsePreamble , HttpResponseContents ) , NetError > {
159
- let neighbors_scope = self
160
- . neighbors_scope
161
- . take ( )
162
- . unwrap_or ( NeighborsScope :: Initial ) ;
163
- let use_all_neighbors = neighbors_scope == NeighborsScope :: All ;
164
-
165
- node. with_node_state ( |network, _sortdb, _chainstate, _mempool, _rpc_args| {
166
- let current_epoch = network. get_current_epoch ( ) ;
167
-
168
- let neighbors_arg = if use_all_neighbors {
169
- None
170
- } else {
171
- let initial_neighbors = PeerDB :: get_valid_initial_neighbors (
172
- network. peerdb . conn ( ) ,
173
- network. local_peer . network_id ,
174
- current_epoch. network_epoch ,
175
- network. peer_version ,
176
- network. chain_view . burn_block_height ,
107
+ let ( ( max_stacks_neighbor_address, max_stacks_height_of_neighbors) , node_stacks_tip_height) =
108
+ node. with_node_state ( |network, _sortdb, _chainstate, _mempool, _rpc_args| {
109
+ (
110
+ network
111
+ . highest_stacks_neighbor
112
+ . map ( |( addr, height) | ( Some ( addr. to_string ( ) ) , height) )
113
+ . unwrap_or ( ( None , 0 ) ) ,
114
+ network. stacks_tip . height ,
177
115
)
178
- . map_err ( NetError :: from) ?;
179
-
180
- if initial_neighbors. is_empty ( ) {
181
- return create_error_response (
182
- & preamble,
183
- "No viable bootstrap peers found, unable to determine health" ,
184
- ) ;
185
- }
186
- Some ( initial_neighbors)
187
- } ;
188
-
189
- let peer_max_stacks_height_opt = {
190
- if current_epoch. epoch_id < StacksEpochId :: Epoch30 {
191
- // When the node enters Epoch 3.0, ibd is not accurate. In nakamoto it's always set to false.
192
- // See the implementation of `RunLoop::start` in `stacks-node/src/run_loop/nakamoto.rs`,
193
- // specifically the section and comment where `let ibd = false`, for details.
194
- let ibd = infer_initial_burnchain_block_download (
195
- & network. burnchain ,
196
- network. burnchain_tip . block_height ,
197
- network. chain_view . burn_block_height ,
198
- ) ;
199
-
200
- // get max block height amongst bootstrap nodes
201
- match network. inv_state . as_ref ( ) {
202
- Some ( inv_state) => {
203
- inv_state. get_max_stacks_height_of_neighbors ( neighbors_arg. as_deref ( ) , ibd)
204
- }
205
- None => {
206
- return create_error_response (
207
- & preamble,
208
- "Peer inventory state (Epoch 2.x) not found, unable to determine health." ,
209
- ) ;
210
- }
211
- }
212
- } else {
213
- let neighbors_arg: Option < Vec < NeighborAddress > > = neighbors_arg. as_ref ( ) . map ( |v| v. iter ( ) . map ( NeighborAddress :: from_neighbor) . collect ( ) ) ;
214
- match network. block_downloader_nakamoto . as_ref ( ) {
215
- Some ( block_downloader_nakamoto) => {
216
- block_downloader_nakamoto. get_max_stacks_height_of_neighbors ( neighbors_arg. as_deref ( ) )
217
- }
218
- None => {
219
- return create_error_response (
220
- & preamble,
221
- "Nakamoto block downloader not found (Epoch 3.0+), unable to determine health." ,
222
- ) ;
223
- }
224
- }
225
- }
226
- } ;
227
-
228
- match peer_max_stacks_height_opt {
229
- Some ( max_stacks_height_of_neighbors) => {
230
- // There could be a edge case where our node is ahead of all peers.
231
- let node_stacks_tip_height = network. stacks_tip . height ;
232
- let difference_from_max_peer =
233
- max_stacks_height_of_neighbors. saturating_sub ( node_stacks_tip_height) ;
234
-
235
- let preamble = HttpResponsePreamble :: ok_json ( & preamble) ;
236
- let data = RPCGetHealthResponse {
237
- difference_from_max_peer,
238
- max_stacks_height_of_neighbors,
239
- node_stacks_tip_height,
240
- } ;
241
- let body = HttpResponseContents :: try_from_json ( & data) ?;
242
- Ok ( ( preamble, body) )
243
- }
244
- None => create_error_response (
245
- & preamble,
246
- "Couldn't obtain stats on any bootstrap peers, unable to determine health." ,
247
- ) ,
248
- }
249
- } )
116
+ } ) ;
117
+
118
+ // There could be a edge case where our node is ahead of all peers.
119
+ let difference_from_max_peer =
120
+ max_stacks_height_of_neighbors. saturating_sub ( node_stacks_tip_height) ;
121
+
122
+ let preamble = HttpResponsePreamble :: ok_json ( & preamble) ;
123
+ let data = RPCGetHealthResponse {
124
+ difference_from_max_peer,
125
+ max_stacks_height_of_neighbors,
126
+ max_stacks_neighbor_address,
127
+ node_stacks_tip_height,
128
+ } ;
129
+ let body = HttpResponseContents :: try_from_json ( & data) ?;
130
+ Ok ( ( preamble, body) )
250
131
}
251
132
}
252
133
@@ -263,15 +144,12 @@ impl HttpResponse for RPCGetHealthRequestHandler {
263
144
}
264
145
265
146
impl StacksHttpRequest {
266
- pub fn new_gethealth ( host : PeerHost , neighbors_scope : NeighborsScope ) -> StacksHttpRequest {
147
+ pub fn new_gethealth ( host : PeerHost ) -> StacksHttpRequest {
267
148
StacksHttpRequest :: new_for_peer (
268
149
host,
269
150
"GET" . into ( ) ,
270
151
"/v3/health" . into ( ) ,
271
- HttpRequestContents :: new ( ) . query_arg (
272
- NEIGHBORS_SCOPE_PARAM_NAME . into ( ) ,
273
- neighbors_scope. to_string ( ) ,
274
- ) ,
152
+ HttpRequestContents :: new ( ) ,
275
153
)
276
154
. expect ( "FATAL: failed to construct request from infallible data" )
277
155
}
0 commit comments