Skip to content

Commit 08a62a2

Browse files
committed
CRC: add unit tests and tighten regex restriction and update change log with full path
Signed-off-by: Jacinta Ferrant <[email protected]>
1 parent e236019 commit 08a62a2

File tree

4 files changed

+113
-5
lines changed

4 files changed

+113
-5
lines changed

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ and this project adheres to the versioning scheme outlined in the [README.md](RE
1616
- `get-stacks-block-info?` added
1717
- `get-tenure-info?` added
1818
- `get-block-info?` removed
19-
- Added `/v3/signer/` endpoint
19+
- Added `/v3/signer/{signer_pubkey}/{reward_cycle}` endpoint
2020

2121
## [2.5.0.0.7]
2222

stackslib/src/net/api/getsigner.rs

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,17 @@ use crate::util_lib::db::Error as DBError;
4545

4646
#[derive(Clone, Default)]
4747
pub struct GetSignerRequestHandler {
48-
signer_pubkey: Option<Secp256k1PublicKey>,
49-
reward_cycle: Option<u64>,
48+
pub signer_pubkey: Option<Secp256k1PublicKey>,
49+
pub reward_cycle: Option<u64>,
50+
}
51+
52+
impl GetSignerRequestHandler {
53+
pub fn new() -> Self {
54+
Self {
55+
signer_pubkey: None,
56+
reward_cycle: None,
57+
}
58+
}
5059
}
5160

5261
#[derive(Debug, Serialize, Deserialize)]
@@ -61,8 +70,10 @@ impl HttpRequest for GetSignerRequestHandler {
6170
}
6271

6372
fn path_regex(&self) -> Regex {
64-
Regex::new(r#"^/v3/signer/(?P<signer_pubkey>[0-9a-f]{66})/(?P<cycle_num>[0-9]{1,10})$"#)
65-
.unwrap()
73+
Regex::new(
74+
r#"^/v3/signer/(?P<signer_pubkey>0[23][0-9a-f]{64})/(?P<cycle_num>[0-9]{1,10})$"#,
75+
)
76+
.unwrap()
6677
}
6778

6879
fn metrics_identifier(&self) -> &str {
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
// Copyright (C) 2024 Stacks Open Internet Foundation
2+
//
3+
// This program is free software: you can redistribute it and/or modify
4+
// it under the terms of the GNU General Public License as published by
5+
// the Free Software Foundation, either version 3 of the License, or
6+
// (at your option) any later version.
7+
//
8+
// This program is distributed in the hope that it will be useful,
9+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
10+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+
// GNU General Public License for more details.
12+
//
13+
// You should have received a copy of the GNU General Public License
14+
// along with this program. If not, see <http://www.gnu.org/licenses/>.
15+
16+
use std::collections::BTreeMap;
17+
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
18+
19+
use clarity::types::chainstate::{StacksBlockId, StacksPrivateKey, StacksPublicKey};
20+
use rand::{thread_rng, RngCore};
21+
use stacks_common::types::chainstate::{BurnchainHeaderHash, ConsensusHash};
22+
use stacks_common::types::net::PeerHost;
23+
24+
use crate::net::api::getsigner::{self, GetSignerRequestHandler};
25+
use crate::net::api::tests::{test_rpc, TestRPC};
26+
use crate::net::connection::ConnectionOptions;
27+
use crate::net::http::{Error as HttpError, HttpRequestPreamble, HttpVersion};
28+
use crate::net::httpcore::{
29+
RPCRequestHandler, StacksHttp, StacksHttpPreamble, StacksHttpRequest, TipRequest,
30+
};
31+
use crate::net::test::TestEventObserver;
32+
use crate::net::{Error as NetError, ProtocolFamily};
33+
34+
fn make_preamble(query: &str) -> HttpRequestPreamble {
35+
HttpRequestPreamble {
36+
version: HttpVersion::Http11,
37+
verb: "GET".into(),
38+
path_and_query_str: format!("/v3/signer{query}"),
39+
host: PeerHost::DNS("localhost".into(), 0),
40+
content_type: None,
41+
content_length: Some(0),
42+
keep_alive: false,
43+
headers: BTreeMap::new(),
44+
}
45+
}
46+
47+
#[test]
48+
fn test_try_parse_request() {
49+
let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 33333);
50+
let http = StacksHttp::new(addr.clone(), &ConnectionOptions::default());
51+
let private_key = StacksPrivateKey::new();
52+
let signer_pubkey = StacksPublicKey::from_private(&private_key);
53+
let signer_pubkey_hex = signer_pubkey.to_hex();
54+
let cycle_num = thread_rng().next_u32() as u64;
55+
56+
let mut handler = getsigner::GetSignerRequestHandler::new();
57+
let mut bad_content_length_preamble =
58+
make_preamble(&format!("/{signer_pubkey_hex}/{cycle_num}"));
59+
bad_content_length_preamble.content_length = Some(1);
60+
let tests = vec![
61+
(
62+
make_preamble(&format!("/{signer_pubkey_hex}/{cycle_num}")),
63+
Ok((Some(signer_pubkey), Some(cycle_num))),
64+
),
65+
(
66+
make_preamble(&format!("/foo/{cycle_num}")),
67+
Err(NetError::NotFoundError),
68+
),
69+
(
70+
make_preamble(&format!("/{signer_pubkey_hex}/bar")),
71+
Err(NetError::NotFoundError),
72+
),
73+
(
74+
bad_content_length_preamble,
75+
Err(
76+
HttpError::DecodeError("Invalid Http request: expected 0-length body".into())
77+
.into(),
78+
),
79+
),
80+
];
81+
82+
for (inp, expected_result) in tests.into_iter() {
83+
handler.restart();
84+
let parsed_request = http.handle_try_parse_request(&mut handler, &inp, &[]);
85+
match expected_result {
86+
Ok((key, cycle)) => {
87+
assert!(parsed_request.is_ok());
88+
assert_eq!(handler.signer_pubkey, key);
89+
assert_eq!(handler.reward_cycle, cycle);
90+
}
91+
Err(e) => {
92+
assert_eq!(e, parsed_request.unwrap_err());
93+
}
94+
}
95+
}
96+
}

stackslib/src/net/api/tests/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ mod getmicroblocks_indexed;
7373
mod getmicroblocks_unconfirmed;
7474
mod getneighbors;
7575
mod getpoxinfo;
76+
mod getsigner;
7677
mod getsortition;
7778
mod getstackerdbchunk;
7879
mod getstackerdbmetadata;

0 commit comments

Comments
 (0)