Skip to content

fix: /v3/health use canonical stacks height header #6347

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 15 commits into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion docs/rpc/components/examples/node-health.example.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"difference_from_max_peer": 0,
"node_stacks_tip_height": 12345,
"max_stacks_height_of_neighbors": 12345,
"node_stacks_tip_height": 12345
"max_stacks_neighbor_address": "127.0.0.1:8080"
}
3 changes: 3 additions & 0 deletions docs/rpc/components/schemas/get-health.schema.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,7 @@ properties:
type: integer
minimum: 0
description: The current Stacks tip height of this node
max_stacks_neighbor_address:
type: [string, "null"]
description: The address of the most advanced peer
description: Health information about the node's synchronization status
18 changes: 1 addition & 17 deletions docs/rpc/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1295,24 +1295,11 @@ paths:
- `difference_from_max_peer`: The difference in Stacks height between this node and its most advanced peer.
- `max_stacks_height_of_neighbors`: The maximum Stacks height observed among the node"s connected peers.
- `node_stacks_tip_height`: The current Stacks tip height of this node.
- `max_stacks_neighbor_address`: The address of the most advanced peer. Null if no peer data is available.
tags:
- Info
security: []
operationId: getNodeHealth
parameters:
- in: query
name: neighbors
description: |
Specifies the set of peers to use for health checks.
- `initial` (default): Use only the initial bootstrap peers.
- `all`: Use all connected peers.
required: false
schema:
type: string
enum:
- initial
- all
default: initial
responses:
"200":
description: Success
Expand All @@ -1323,11 +1310,8 @@ paths:
example:
$ref: "./components/examples/node-health.example.json"
"400":
description: Bad request, such as an invalid `neighbors` query parameter.
$ref: "#/components/responses/BadRequest"
"500":
description: |
Failed to query for health (e.g., no data or no valid peers to query from).
$ref: "#/components/responses/InternalServerError"

/v2/attachments/{hash}:
Expand Down
18 changes: 16 additions & 2 deletions stacks-node/src/tests/nakamoto_integrations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ use crate::operations::BurnchainOpSigner;
use crate::run_loop::boot_nakamoto;
use crate::tests::neon_integrations::{
call_read_only, get_account, get_account_result, get_chain_info_opt, get_chain_info_result,
get_neighbors, get_pox_info, get_sortition_info, next_block_and_wait,
get_neighbors, get_node_health, get_pox_info, get_sortition_info, next_block_and_wait,
run_until_burnchain_height, submit_tx, submit_tx_fallible, test_observer, wait_for_runloop,
};
use crate::tests::signer::SignerTest;
Expand Down Expand Up @@ -2413,10 +2413,11 @@ fn mine_multiple_per_tenure_integration() {
/// It starts in Epoch 2.0, mines with `neon_node` to Epoch 3.0, and then switches
/// to Nakamoto operation (activating pox-4 by submitting a stack-stx tx). The BootLoop
/// struct handles the epoch-2/3 tear-down and spin-up.
/// This test makes three assertions:
/// This test makes four assertions:
/// * 15 tenures are mined after 3.0 starts
/// * Each tenure has 6 blocks (the coinbase block and 5 interim blocks)
/// * Both nodes see the same chainstate at the end of the test
/// * Both nodes have the same `PeerNetwork::highest_stacks_height_of_neighbors`
fn multiple_miners() {
if env::var("BITCOIND_TEST") != Ok("1".into()) {
return;
Expand Down Expand Up @@ -2641,6 +2642,19 @@ fn multiple_miners() {
info!("Peer height information"; "peer_1" => peer_1_height, "peer_2" => peer_2_height);
assert_eq!(peer_1_height, peer_2_height);

// check that the `ConversationHttp::chat` was called and updated
// `PeerNetwork::highest_stacks_height_of_neighbors`
wait_for(20, || {
let health_node_1 = get_node_health(&naka_conf);
let health_node_2 = get_node_health(&conf_node_2);
info!("Peer health information"; "peer_1" => ?health_node_1, "peer_2" => ?health_node_2);
Ok(
health_node_1.max_stacks_height_of_neighbors == peer_2_height
&& health_node_2.max_stacks_height_of_neighbors == peer_1_height,
)
})
.unwrap();

assert!(tip.anchored_header.as_stacks_nakamoto().is_some());
assert_eq!(
tip.stacks_block_height,
Expand Down
13 changes: 13 additions & 0 deletions stacks-node/src/tests/neon_integrations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ use stacks::core::{
};
use stacks::net::api::getaccount::AccountEntryResponse;
use stacks::net::api::getcontractsrc::ContractSrcResponse;
use stacks::net::api::gethealth::RPCGetHealthResponse;
use stacks::net::api::getinfo::RPCPeerInfoData;
use stacks::net::api::getpoxinfo::RPCPoxInfoData;
use stacks::net::api::getsortition::SortitionInfo;
Expand Down Expand Up @@ -1010,6 +1011,18 @@ pub fn get_block(http_origin: &str, block_id: &StacksBlockId) -> Option<StacksBl
}
}

pub fn get_node_health(conf: &Config) -> RPCGetHealthResponse {
let http_origin = format!("http://{}", &conf.node.rpc_bind);
let client = reqwest::blocking::Client::new();
let path = format!("{http_origin}/v3/health");
client
.get(&path)
.send()
.unwrap()
.json::<RPCGetHealthResponse>()
.unwrap()
}

pub fn get_chain_info_result(conf: &Config) -> Result<RPCPeerInfoData, reqwest::Error> {
let http_origin = format!("http://{}", &conf.node.rpc_bind);
let client = reqwest::blocking::Client::new();
Expand Down
10 changes: 5 additions & 5 deletions stackslib/src/chainstate/stacks/db/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -661,9 +661,9 @@ const CHAINSTATE_INITIAL_SCHEMA: &[&str] = &[
tx_merkle_root TEXT NOT NULL,
state_index_root TEXT NOT NULL,
microblock_pubkey_hash TEXT NOT NULL,

block_hash TEXT NOT NULL, -- NOTE: this is *not* unique, since two burn chain forks can commit to the same Stacks block.
index_block_hash TEXT UNIQUE NOT NULL, -- NOTE: this is the hash of the block hash and consensus hash of the burn block that selected it,
index_block_hash TEXT UNIQUE NOT NULL, -- NOTE: this is the hash of the block hash and consensus hash of the burn block that selected it,
-- and is guaranteed to be globally unique (across all Stacks forks and across all PoX forks).
-- index_block_hash is the block hash fed into the MARF index.

Expand Down Expand Up @@ -698,7 +698,7 @@ const CHAINSTATE_INITIAL_SCHEMA: &[&str] = &[
burnchain_commit_burn INT NOT NULL,
burnchain_sortition_burn INT NOT NULL,
miner INT NOT NULL,

-- internal use
stacks_block_height INTEGER NOT NULL,
index_block_hash TEXT NOT NULL, -- NOTE: can't enforce UNIQUE here, because there will be multiple entries per block
Expand Down Expand Up @@ -799,7 +799,7 @@ const CHAINSTATE_SCHEMA_3: &[&str] = &[
-- * one that records the coinbase, anchored tx fee, and confirmed streamed tx fees, and
-- * one that records only the produced streamed tx fees.
-- The latter is determined once this block's stream gets subsequently confirmed.
-- You query this table by passing both the parent and the child block hashes, since both the
-- You query this table by passing both the parent and the child block hashes, since both the
-- parent and child blocks determine the full reward for the parent block.
CREATE TABLE matured_rewards(
address TEXT NOT NULL, -- address of the miner who produced the block
Expand All @@ -810,7 +810,7 @@ const CHAINSTATE_SCHEMA_3: &[&str] = &[
tx_fees_streamed_confirmed TEXT NOT NULL,
tx_fees_streamed_produced TEXT NOT NULL,

-- fork identifier
-- fork identifier
child_index_block_hash TEXT NOT NULL,
parent_index_block_hash TEXT NOT NULL,

Expand Down
7 changes: 3 additions & 4 deletions stackslib/src/net/api/callreadonly.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ use crate::net::http::{
HttpResponsePreamble,
};
use crate::net::httpcore::{
request, HttpPreambleExtensions, HttpRequestContentsExtensions, RPCRequestHandler,
StacksHttpRequest, StacksHttpResponse,
request, HttpRequestContentsExtensions as _, RPCRequestHandler, StacksHttpRequest,
StacksHttpResponse,
};
use crate::net::{Error as NetError, StacksNodeState, TipRequest};

Expand Down Expand Up @@ -307,8 +307,7 @@ impl RPCRequestHandler for RPCCallReadOnlyRequestHandler {
}
};

let mut preamble = HttpResponsePreamble::ok_json(&preamble);
preamble.set_canonical_stacks_tip_height(Some(node.canonical_stacks_tip_height()));
let preamble = HttpResponsePreamble::ok_json(&preamble);
let body = HttpResponseContents::try_from_json(&data_resp)?;
Ok((preamble, body))
}
Expand Down
7 changes: 3 additions & 4 deletions stackslib/src/net/api/fastcallreadonly.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ use crate::net::http::{
HttpResponsePayload, HttpResponsePreamble,
};
use crate::net::httpcore::{
request, HttpPreambleExtensions, HttpRequestContentsExtensions, RPCRequestHandler,
StacksHttpRequest, StacksHttpResponse,
request, HttpRequestContentsExtensions as _, RPCRequestHandler, StacksHttpRequest,
StacksHttpResponse,
};
use crate::net::{Error as NetError, StacksNodeState, TipRequest};

Expand Down Expand Up @@ -312,8 +312,7 @@ impl RPCRequestHandler for RPCFastCallReadOnlyRequestHandler {
}
};

let mut preamble = HttpResponsePreamble::ok_json(&preamble);
preamble.set_canonical_stacks_tip_height(Some(node.canonical_stacks_tip_height()));
let preamble = HttpResponsePreamble::ok_json(&preamble);
let body = HttpResponseContents::try_from_json(&data_resp)?;
Ok((preamble, body))
}
Expand Down
1 change: 0 additions & 1 deletion stackslib/src/net/api/get_tenures_fork_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,6 @@ impl RPCRequestHandler for GetTenuresForkInfo {
None,
HttpContentType::JSON,
);

Ok((
resp_preamble,
HttpResponseContents::try_from_json(&tenures)?,
Expand Down
6 changes: 2 additions & 4 deletions stackslib/src/net/api/getaccount.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,7 @@ use crate::net::http::{
HttpResponse, HttpResponseContents, HttpResponsePayload, HttpResponsePreamble,
};
use crate::net::httpcore::{
HttpPreambleExtensions, HttpRequestContentsExtensions, RPCRequestHandler, StacksHttpRequest,
StacksHttpResponse,
HttpRequestContentsExtensions as _, RPCRequestHandler, StacksHttpRequest, StacksHttpResponse,
};
use crate::net::{Error as NetError, StacksNodeState, TipRequest};

Expand Down Expand Up @@ -219,8 +218,7 @@ impl RPCRequestHandler for RPCGetAccountRequestHandler {
.map_err(NetError::from);
};

let mut preamble = HttpResponsePreamble::ok_json(&preamble);
preamble.set_canonical_stacks_tip_height(Some(node.canonical_stacks_tip_height()));
let preamble = HttpResponsePreamble::ok_json(&preamble);
let body = HttpResponseContents::try_from_json(&account)?;
Ok((preamble, body))
}
Expand Down
7 changes: 2 additions & 5 deletions stackslib/src/net/api/getattachment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,7 @@ use crate::net::http::{
parse_json, Error, HttpNotFound, HttpRequest, HttpRequestContents, HttpRequestPreamble,
HttpResponse, HttpResponseContents, HttpResponsePayload, HttpResponsePreamble,
};
use crate::net::httpcore::{
HttpPreambleExtensions, RPCRequestHandler, StacksHttpRequest, StacksHttpResponse,
};
use crate::net::httpcore::{RPCRequestHandler, StacksHttpRequest, StacksHttpResponse};
use crate::net::{Error as NetError, StacksNodeState};

#[derive(Clone)]
Expand Down Expand Up @@ -126,8 +124,7 @@ impl RPCRequestHandler for RPCGetAttachmentRequestHandler {
}
};

let mut preamble = HttpResponsePreamble::ok_json(&preamble);
preamble.set_canonical_stacks_tip_height(Some(node.canonical_stacks_tip_height()));
let preamble = HttpResponsePreamble::ok_json(&preamble);
let body = HttpResponseContents::try_from_json(&attachment)?;
Ok((preamble, body))
}
Expand Down
7 changes: 2 additions & 5 deletions stackslib/src/net/api/getattachmentsinv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,7 @@ use crate::net::http::{
HttpRequestPreamble, HttpResponse, HttpResponseContents, HttpResponsePayload,
HttpResponsePreamble,
};
use crate::net::httpcore::{
HttpPreambleExtensions, RPCRequestHandler, StacksHttpRequest, StacksHttpResponse,
};
use crate::net::httpcore::{RPCRequestHandler, StacksHttpRequest, StacksHttpResponse};
use crate::net::{Error as NetError, StacksNodeState};

#[derive(Clone)]
Expand Down Expand Up @@ -214,8 +212,7 @@ impl RPCRequestHandler for RPCGetAttachmentsInvRequestHandler {
pages,
};

let mut preamble = HttpResponsePreamble::ok_json(&preamble);
preamble.set_canonical_stacks_tip_height(Some(node.canonical_stacks_tip_height()));
let preamble = HttpResponsePreamble::ok_json(&preamble);
let body = HttpResponseContents::try_from_json(&content)?;
Ok((preamble, body))
}
Expand Down
1 change: 0 additions & 1 deletion stackslib/src/net/api/getblock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,6 @@ impl RPCRequestHandler for RPCBlocksRequestHandler {
None,
HttpContentType::Bytes,
);

Ok((
resp_preamble,
HttpResponseContents::from_stream(Box::new(stream)),
Expand Down
1 change: 0 additions & 1 deletion stackslib/src/net/api/getblock_v3.rs
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,6 @@ impl RPCRequestHandler for RPCNakamotoBlockRequestHandler {
None,
HttpContentType::Bytes,
);

Ok((
resp_preamble,
HttpResponseContents::from_stream(Box::new(stream)),
Expand Down
3 changes: 1 addition & 2 deletions stackslib/src/net/api/getblockbyheight.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ use crate::net::http::{
HttpResponsePreamble, HttpServerError,
};
use crate::net::httpcore::{
HttpRequestContentsExtensions, RPCRequestHandler, StacksHttpRequest, StacksHttpResponse,
HttpRequestContentsExtensions as _, RPCRequestHandler, StacksHttpRequest, StacksHttpResponse,
};
use crate::net::{Error as NetError, StacksNodeState, TipRequest};

Expand Down Expand Up @@ -179,7 +179,6 @@ impl RPCRequestHandler for RPCNakamotoBlockByHeightRequestHandler {
None,
HttpContentType::Bytes,
);

Ok((
resp_preamble,
HttpResponseContents::from_stream(Box::new(stream)),
Expand Down
6 changes: 2 additions & 4 deletions stackslib/src/net/api/getclaritymarfvalue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,7 @@ use crate::net::http::{
HttpResponse, HttpResponseContents, HttpResponsePayload, HttpResponsePreamble,
};
use crate::net::httpcore::{
HttpPreambleExtensions, HttpRequestContentsExtensions, RPCRequestHandler, StacksHttpRequest,
StacksHttpResponse,
HttpRequestContentsExtensions as _, RPCRequestHandler, StacksHttpRequest, StacksHttpResponse,
};
use crate::net::{Error as NetError, StacksNodeState, TipRequest};

Expand Down Expand Up @@ -168,8 +167,7 @@ impl RPCRequestHandler for RPCGetClarityMarfRequestHandler {
}
};

let mut preamble = HttpResponsePreamble::ok_json(&preamble);
preamble.set_canonical_stacks_tip_height(Some(node.canonical_stacks_tip_height()));
let preamble = HttpResponsePreamble::ok_json(&preamble);
let body = HttpResponseContents::try_from_json(&data_resp)?;
Ok((preamble, body))
}
Expand Down
7 changes: 3 additions & 4 deletions stackslib/src/net/api/getclaritymetadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ use crate::net::http::{
HttpResponse, HttpResponseContents, HttpResponsePayload, HttpResponsePreamble,
};
use crate::net::httpcore::{
request, HttpPreambleExtensions, HttpRequestContentsExtensions, RPCRequestHandler,
StacksHttpRequest, StacksHttpResponse,
request, HttpRequestContentsExtensions as _, RPCRequestHandler, StacksHttpRequest,
StacksHttpResponse,
};
use crate::net::{Error as NetError, StacksNodeState, TipRequest};

Expand Down Expand Up @@ -221,8 +221,7 @@ impl RPCRequestHandler for RPCGetClarityMetadataRequestHandler {
}
};

let mut preamble = HttpResponsePreamble::ok_json(&preamble);
preamble.set_canonical_stacks_tip_height(Some(node.canonical_stacks_tip_height()));
let preamble = HttpResponsePreamble::ok_json(&preamble);
let body = HttpResponseContents::try_from_json(&data_resp)?;
Ok((preamble, body))
}
Expand Down
7 changes: 3 additions & 4 deletions stackslib/src/net/api/getconstantval.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ use crate::net::http::{
HttpResponse, HttpResponseContents, HttpResponsePayload, HttpResponsePreamble,
};
use crate::net::httpcore::{
request, HttpPreambleExtensions, HttpRequestContentsExtensions, RPCRequestHandler,
StacksHttpRequest, StacksHttpResponse,
request, HttpRequestContentsExtensions as _, RPCRequestHandler, StacksHttpRequest,
StacksHttpResponse,
};
use crate::net::{Error as NetError, StacksNodeState, TipRequest};

Expand Down Expand Up @@ -168,8 +168,7 @@ impl RPCRequestHandler for RPCGetConstantValRequestHandler {
}
};

let mut preamble = HttpResponsePreamble::ok_json(&preamble);
preamble.set_canonical_stacks_tip_height(Some(node.canonical_stacks_tip_height()));
let preamble = HttpResponsePreamble::ok_json(&preamble);
let body = HttpResponseContents::try_from_json(&data_resp)?;
Ok((preamble, body))
}
Expand Down
7 changes: 3 additions & 4 deletions stackslib/src/net/api/getcontractabi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ use crate::net::http::{
HttpResponse, HttpResponseContents, HttpResponsePayload, HttpResponsePreamble,
};
use crate::net::httpcore::{
request, HttpPreambleExtensions, HttpRequestContentsExtensions, RPCRequestHandler,
StacksHttpRequest, StacksHttpResponse,
request, HttpRequestContentsExtensions as _, RPCRequestHandler, StacksHttpRequest,
StacksHttpResponse,
};
use crate::net::{Error as NetError, StacksNodeState, TipRequest};

Expand Down Expand Up @@ -148,8 +148,7 @@ impl RPCRequestHandler for RPCGetContractAbiRequestHandler {
}
};

let mut preamble = HttpResponsePreamble::ok_json(&preamble);
preamble.set_canonical_stacks_tip_height(Some(node.canonical_stacks_tip_height()));
let preamble = HttpResponsePreamble::ok_json(&preamble);
let body = HttpResponseContents::try_from_json(&data_resp)?;
Ok((preamble, body))
}
Expand Down
Loading
Loading