• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

stacks-network / stacks-core / 26250451051-1

21 May 2026 08:11PM UTC coverage: 85.585% (-0.1%) from 85.712%
26250451051-1

Pull #7215

github

ec9d4c
web-flow
Merge 9487bf852 into af1280aac
Pull Request #7215: Chore: fix flake in non_blocking_minority_configured_to_favour_...

188844 of 220651 relevant lines covered (85.58%)

18975267.44 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

91.8
/stackslib/src/net/api/getconstantval.rs
1
// Copyright (C) 2013-2020 Blockstack PBC, a public benefit corporation
2
// Copyright (C) 2020-2023 Stacks Open Internet Foundation
3
//
4
// This program is free software: you can redistribute it and/or modify
5
// it under the terms of the GNU General Public License as published by
6
// the Free Software Foundation, either version 3 of the License, or
7
// (at your option) any later version.
8
//
9
// This program is distributed in the hope that it will be useful,
10
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
// GNU General Public License for more details.
13
//
14
// You should have received a copy of the GNU General Public License
15
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
16

17
use clarity::vm::ast::parser::v1::CLARITY_NAME_REGEX;
18
use clarity::vm::clarity::ClarityConnection;
19
use clarity::vm::representations::{CONTRACT_NAME_REGEX_STRING, STANDARD_PRINCIPAL_REGEX_STRING};
20
use clarity::vm::types::QualifiedContractIdentifier;
21
use clarity::vm::{ClarityName, ContractName};
22
use regex::{Captures, Regex};
23
use stacks_common::types::chainstate::StacksAddress;
24
use stacks_common::types::net::PeerHost;
25

26
use crate::net::http::{
27
    parse_json, Error, HttpNotFound, HttpRequest, HttpRequestContents, HttpRequestPreamble,
28
    HttpResponse, HttpResponseContents, HttpResponsePayload, HttpResponsePreamble,
29
};
30
use crate::net::httpcore::{
31
    request, HttpRequestContentsExtensions as _, RPCRequestHandler, StacksHttpRequest,
32
    StacksHttpResponse,
33
};
34
use crate::net::{Error as NetError, StacksNodeState, TipRequest};
35

36
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
37
pub struct ConstantValResponse {
38
    pub data: String,
39
}
40

41
#[derive(Clone)]
42
pub struct RPCGetConstantValRequestHandler {
43
    pub constname: Option<ClarityName>,
44
    pub contract_identifier: Option<QualifiedContractIdentifier>,
45
}
46

47
impl RPCGetConstantValRequestHandler {
48
    pub fn new() -> Self {
1,101,019✔
49
        Self {
1,101,019✔
50
            constname: None,
1,101,019✔
51
            contract_identifier: None,
1,101,019✔
52
        }
1,101,019✔
53
    }
1,101,019✔
54
}
55

56
/// Decode the HTTP request
57
impl HttpRequest for RPCGetConstantValRequestHandler {
58
    fn verb(&self) -> &'static str {
1,101,018✔
59
        "GET"
1,101,018✔
60
    }
1,101,018✔
61

62
    fn path_regex(&self) -> Regex {
2,202,037✔
63
        Regex::new(&format!(
2,202,037✔
64
            "^/v2/constant_val/(?P<address>{})/(?P<contract>{})/(?P<constname>{})$",
2,202,037✔
65
            *STANDARD_PRINCIPAL_REGEX_STRING, *CONTRACT_NAME_REGEX_STRING, *CLARITY_NAME_REGEX
2,202,037✔
66
        ))
2,202,037✔
67
        .unwrap()
2,202,037✔
68
    }
2,202,037✔
69

70
    fn metrics_identifier(&self) -> &str {
22✔
71
        "/v2/constant_val/:principal/:contract_name/:const_name"
22✔
72
    }
22✔
73

74
    /// Try to decode this request.
75
    /// There's nothing to load here, so just make sure the request is well-formed.
76
    fn try_parse_request(
23✔
77
        &mut self,
23✔
78
        preamble: &HttpRequestPreamble,
23✔
79
        captures: &Captures,
23✔
80
        query: Option<&str>,
23✔
81
        _body: &[u8],
23✔
82
    ) -> Result<HttpRequestContents, Error> {
23✔
83
        if preamble.get_content_length() != 0 {
23✔
84
            return Err(Error::DecodeError(
×
85
                "Invalid Http request: expected 0-length body".to_string(),
×
86
            ));
×
87
        }
23✔
88

89
        let contract_identifier = request::get_contract_address(captures, "address", "contract")?;
23✔
90
        let constname = request::get_clarity_name(captures, "constname")?;
23✔
91

92
        self.contract_identifier = Some(contract_identifier);
23✔
93
        self.constname = Some(constname);
23✔
94

95
        let contents = HttpRequestContents::new().query_string(query);
23✔
96
        Ok(contents)
23✔
97
    }
23✔
98
}
99

100
/// Handle the HTTP request
101
impl RPCRequestHandler for RPCGetConstantValRequestHandler {
102
    /// Reset internal state
103
    fn restart(&mut self) {
23✔
104
        self.contract_identifier = None;
23✔
105
        self.constname = None;
23✔
106
    }
23✔
107

108
    /// Make the response
109
    fn try_handle_request(
22✔
110
        &mut self,
22✔
111
        preamble: HttpRequestPreamble,
22✔
112
        contents: HttpRequestContents,
22✔
113
        node: &mut StacksNodeState,
22✔
114
    ) -> Result<(HttpResponsePreamble, HttpResponseContents), NetError> {
22✔
115
        let contract_identifier = self.contract_identifier.take().ok_or(NetError::SendError(
22✔
116
            "`contract_identifier` not set".to_string(),
22✔
117
        ))?;
22✔
118
        let constant_name = self
22✔
119
            .constname
22✔
120
            .take()
22✔
121
            .ok_or(NetError::SendError("`constname` not set".to_string()))?;
22✔
122
        let tip = match node.load_stacks_chain_tip(&preamble, &contents) {
22✔
123
            Ok(tip) => tip,
22✔
124
            Err(error_resp) => {
×
125
                return error_resp.try_into_contents().map_err(NetError::from);
×
126
            }
127
        };
128

129
        let data_resp =
22✔
130
            node.with_node_state(|_network, sortdb, chainstate, _mempool, _rpc_args| {
22✔
131
                chainstate.maybe_read_only_clarity_tx(
22✔
132
                    &sortdb.index_handle_at_block(chainstate, &tip)?,
22✔
133
                    &tip,
22✔
134
                    |clarity_tx| {
22✔
135
                        clarity_tx.with_clarity_db_readonly(|clarity_db| {
22✔
136
                            let contract = clarity_db.get_contract(&contract_identifier).ok()?;
22✔
137

138
                            let cst = contract
21✔
139
                                .lookup_variable(constant_name.as_str())?
21✔
140
                                .serialize_to_hex()
20✔
141
                                .ok()?;
20✔
142

143
                            let data = format!("0x{cst}");
20✔
144
                            Some(ConstantValResponse { data })
20✔
145
                        })
22✔
146
                    },
22✔
147
                )
148
            });
22✔
149

150
        let data_resp = match data_resp {
22✔
151
            Ok(Some(Some(data))) => data,
20✔
152
            Ok(Some(None)) => {
153
                return StacksHttpResponse::new_error(
2✔
154
                    &preamble,
2✔
155
                    &HttpNotFound::new("Constant not found".to_string()),
2✔
156
                )
157
                .try_into_contents()
2✔
158
                .map_err(NetError::from);
2✔
159
            }
160
            Ok(None) | Err(_) => {
161
                return StacksHttpResponse::new_error(
×
162
                    &preamble,
×
163
                    &HttpNotFound::new("Chain tip not found".to_string()),
×
164
                )
165
                .try_into_contents()
×
166
                .map_err(NetError::from);
×
167
            }
168
        };
169

170
        let preamble = HttpResponsePreamble::ok_json(&preamble);
20✔
171
        let body = HttpResponseContents::try_from_json(&data_resp)?;
20✔
172
        Ok((preamble, body))
20✔
173
    }
22✔
174
}
175

176
/// Decode the HTTP response
177
impl HttpResponse for RPCGetConstantValRequestHandler {
178
    fn try_parse_response(
2✔
179
        &self,
2✔
180
        preamble: &HttpResponsePreamble,
2✔
181
        body: &[u8],
2✔
182
    ) -> Result<HttpResponsePayload, Error> {
2✔
183
        let constant_val: ConstantValResponse = parse_json(preamble, body)?;
2✔
184
        Ok(HttpResponsePayload::try_from_json(constant_val)?)
2✔
185
    }
2✔
186
}
187

188
impl StacksHttpRequest {
189
    /// Make a new request for a constant val
190
    pub fn new_getconstantval(
5✔
191
        host: PeerHost,
5✔
192
        contract_addr: StacksAddress,
5✔
193
        contract_name: ContractName,
5✔
194
        constant_name: ClarityName,
5✔
195
        tip_req: TipRequest,
5✔
196
    ) -> StacksHttpRequest {
5✔
197
        StacksHttpRequest::new_for_peer(
5✔
198
            host,
5✔
199
            "GET".into(),
5✔
200
            format!(
5✔
201
                "/v2/constant_val/{}/{}/{}",
202
                &contract_addr, &contract_name, &constant_name
5✔
203
            ),
204
            HttpRequestContents::new().for_tip(tip_req),
5✔
205
        )
206
        .expect("FATAL: failed to construct request from infallible data")
5✔
207
    }
5✔
208
}
209

210
impl StacksHttpResponse {
211
    pub fn decode_constant_val_response(self) -> Result<ConstantValResponse, NetError> {
2✔
212
        let contents = self.get_http_payload_ok()?;
2✔
213
        let contents_json: serde_json::Value = contents.try_into()?;
2✔
214
        let resp: ConstantValResponse = serde_json::from_value(contents_json)
2✔
215
            .map_err(|_e| NetError::DeserializeError("Failed to load from JSON".to_string()))?;
2✔
216
        Ok(resp)
2✔
217
    }
2✔
218
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc