Skip to content

Commit c4a2c44

Browse files
authored
Merge branch 'develop' into chore/tenure-extend-changelog
2 parents 00b5f65 + 3b25d99 commit c4a2c44

File tree

8 files changed

+255
-92
lines changed

8 files changed

+255
-92
lines changed

stackslib/src/net/connection.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
// You should have received a copy of the GNU General Public License
1515
// along with this program. If not, see <http://www.gnu.org/licenses/>.
1616

17-
use std::collections::VecDeque;
17+
use std::collections::{HashMap, VecDeque};
1818
use std::io::{Read, Write};
1919
use std::ops::{Deref, DerefMut};
2020
use std::sync::mpsc::{
@@ -24,7 +24,7 @@ use std::time::Duration;
2424
use std::{io, net};
2525

2626
use clarity::vm::costs::ExecutionCost;
27-
use clarity::vm::types::BOUND_VALUE_SERIALIZATION_HEX;
27+
use clarity::vm::types::{QualifiedContractIdentifier, BOUND_VALUE_SERIALIZATION_HEX};
2828
use stacks_common::codec::{StacksMessageCodec, MAX_MESSAGE_LEN};
2929
use stacks_common::types::net::PeerAddress;
3030
use stacks_common::util::hash::to_hex;
@@ -44,7 +44,8 @@ use crate::net::neighbors::{
4444
WALK_SEED_PROBABILITY, WALK_STATE_TIMEOUT,
4545
};
4646
use crate::net::{
47-
Error as net_error, MessageSequence, Preamble, ProtocolFamily, RelayData, StacksHttp, StacksP2P,
47+
Error as net_error, MessageSequence, NeighborAddress, Preamble, ProtocolFamily, RelayData,
48+
StacksHttp, StacksP2P,
4849
};
4950

5051
/// Receiver notification handle.
@@ -433,6 +434,8 @@ pub struct ConnectionOptions {
433434
pub nakamoto_unconfirmed_downloader_interval_ms: u128,
434435
/// The authorization token to enable privileged RPC endpoints
435436
pub auth_token: Option<String>,
437+
/// StackerDB replicas to talk to for a particular smart contract
438+
pub stackerdb_hint_replicas: HashMap<QualifiedContractIdentifier, Vec<NeighborAddress>>,
436439

437440
// fault injection
438441
/// Disable neighbor walk and discovery
@@ -565,6 +568,7 @@ impl std::default::Default for ConnectionOptions {
565568
nakamoto_inv_sync_burst_interval_ms: 1_000, // wait 1 second after a sortition before running inventory sync
566569
nakamoto_unconfirmed_downloader_interval_ms: 5_000, // run unconfirmed downloader once every 5 seconds
567570
auth_token: None,
571+
stackerdb_hint_replicas: HashMap::new(),
568572

569573
// no faults on by default
570574
disable_neighbor_walk: false,

stackslib/src/net/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3141,7 +3141,7 @@ pub mod test {
31413141
&mut stacks_node.chainstate,
31423142
&sortdb,
31433143
old_stackerdb_configs,
3144-
config.connection_opts.num_neighbors,
3144+
&config.connection_opts,
31453145
)
31463146
.expect("Failed to refresh stackerdb configs");
31473147

stackslib/src/net/p2p.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -841,6 +841,9 @@ impl PeerNetwork {
841841
) -> usize {
842842
let mut count = 0;
843843
for (_, convo) in self.peers.iter() {
844+
if !convo.is_authenticated() {
845+
continue;
846+
}
844847
if !convo.is_outbound() {
845848
continue;
846849
}
@@ -4158,7 +4161,7 @@ impl PeerNetwork {
41584161
chainstate,
41594162
sortdb,
41604163
stacker_db_configs,
4161-
self.connection_opts.num_neighbors,
4164+
&self.connection_opts,
41624165
)?;
41634166
Ok(())
41644167
}

stackslib/src/net/stackerdb/config.rs

Lines changed: 99 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,94 @@ impl StackerDBConfig {
285285
Ok(ret)
286286
}
287287

288+
/// Evaluate contract-given hint-replicas
289+
fn eval_hint_replicas(
290+
contract_id: &QualifiedContractIdentifier,
291+
hint_replicas_list: Vec<ClarityValue>,
292+
) -> Result<Vec<NeighborAddress>, NetError> {
293+
let mut hint_replicas = vec![];
294+
for hint_replica_value in hint_replicas_list.into_iter() {
295+
let hint_replica_data = hint_replica_value.expect_tuple()?;
296+
297+
let addr_byte_list = hint_replica_data
298+
.get("addr")
299+
.expect("FATAL: missing 'addr'")
300+
.clone()
301+
.expect_list()?;
302+
let port = hint_replica_data
303+
.get("port")
304+
.expect("FATAL: missing 'port'")
305+
.clone()
306+
.expect_u128()?;
307+
let pubkey_hash_bytes = hint_replica_data
308+
.get("public-key-hash")
309+
.expect("FATAL: missing 'public-key-hash")
310+
.clone()
311+
.expect_buff_padded(20, 0)?;
312+
313+
let mut addr_bytes = vec![];
314+
for byte_val in addr_byte_list.into_iter() {
315+
let byte = byte_val.expect_u128()?;
316+
if byte > (u8::MAX as u128) {
317+
let reason = format!(
318+
"Contract {} stipulates an addr byte above u8::MAX",
319+
contract_id
320+
);
321+
warn!("{}", &reason);
322+
return Err(NetError::InvalidStackerDBContract(
323+
contract_id.clone(),
324+
reason,
325+
));
326+
}
327+
addr_bytes.push(byte as u8);
328+
}
329+
if addr_bytes.len() != 16 {
330+
let reason = format!(
331+
"Contract {} did not stipulate a full 16-octet IP address",
332+
contract_id
333+
);
334+
warn!("{}", &reason);
335+
return Err(NetError::InvalidStackerDBContract(
336+
contract_id.clone(),
337+
reason,
338+
));
339+
}
340+
341+
if port < 1024 || port > u128::from(u16::MAX - 1) {
342+
let reason = format!(
343+
"Contract {} stipulates a port lower than 1024 or above u16::MAX - 1",
344+
contract_id
345+
);
346+
warn!("{}", &reason);
347+
return Err(NetError::InvalidStackerDBContract(
348+
contract_id.clone(),
349+
reason,
350+
));
351+
}
352+
// NOTE: port is now known to be in range [1024, 65535]
353+
354+
let mut pubkey_hash_slice = [0u8; 20];
355+
pubkey_hash_slice.copy_from_slice(&pubkey_hash_bytes[0..20]);
356+
357+
let peer_addr = PeerAddress::from_slice(&addr_bytes).expect("FATAL: not 16 bytes");
358+
if peer_addr.is_in_private_range() {
359+
debug!(
360+
"Ignoring private IP address '{}' in hint-replicas",
361+
&peer_addr.to_socketaddr(port as u16)
362+
);
363+
continue;
364+
}
365+
366+
let naddr = NeighborAddress {
367+
addrbytes: peer_addr,
368+
port: port as u16,
369+
public_key_hash: Hash160(pubkey_hash_slice),
370+
};
371+
hint_replicas.push(naddr);
372+
}
373+
Ok(hint_replicas)
374+
}
375+
288376
/// Evaluate the contract to get its config
289377
fn eval_config(
290378
chainstate: &mut StacksChainState,
@@ -293,6 +381,7 @@ impl StackerDBConfig {
293381
tip: &StacksBlockId,
294382
signers: Vec<(StacksAddress, u32)>,
295383
local_max_neighbors: u64,
384+
local_hint_replicas: Option<Vec<NeighborAddress>>,
296385
) -> Result<StackerDBConfig, NetError> {
297386
let value =
298387
chainstate.eval_read_only(burn_dbconn, tip, contract_id, "(stackerdb-get-config)")?;
@@ -394,91 +483,17 @@ impl StackerDBConfig {
394483
max_neighbors = u128::from(local_max_neighbors);
395484
}
396485

397-
let hint_replicas_list = config_tuple
398-
.get("hint-replicas")
399-
.expect("FATAL: missing 'hint-replicas'")
400-
.clone()
401-
.expect_list()?;
402-
let mut hint_replicas = vec![];
403-
for hint_replica_value in hint_replicas_list.into_iter() {
404-
let hint_replica_data = hint_replica_value.expect_tuple()?;
405-
406-
let addr_byte_list = hint_replica_data
407-
.get("addr")
408-
.expect("FATAL: missing 'addr'")
486+
let hint_replicas = if let Some(replicas) = local_hint_replicas {
487+
replicas.clone()
488+
} else {
489+
let hint_replicas_list = config_tuple
490+
.get("hint-replicas")
491+
.expect("FATAL: missing 'hint-replicas'")
409492
.clone()
410493
.expect_list()?;
411-
let port = hint_replica_data
412-
.get("port")
413-
.expect("FATAL: missing 'port'")
414-
.clone()
415-
.expect_u128()?;
416-
let pubkey_hash_bytes = hint_replica_data
417-
.get("public-key-hash")
418-
.expect("FATAL: missing 'public-key-hash")
419-
.clone()
420-
.expect_buff_padded(20, 0)?;
421494

422-
let mut addr_bytes = vec![];
423-
for byte_val in addr_byte_list.into_iter() {
424-
let byte = byte_val.expect_u128()?;
425-
if byte > (u8::MAX as u128) {
426-
let reason = format!(
427-
"Contract {} stipulates an addr byte above u8::MAX",
428-
contract_id
429-
);
430-
warn!("{}", &reason);
431-
return Err(NetError::InvalidStackerDBContract(
432-
contract_id.clone(),
433-
reason,
434-
));
435-
}
436-
addr_bytes.push(byte as u8);
437-
}
438-
if addr_bytes.len() != 16 {
439-
let reason = format!(
440-
"Contract {} did not stipulate a full 16-octet IP address",
441-
contract_id
442-
);
443-
warn!("{}", &reason);
444-
return Err(NetError::InvalidStackerDBContract(
445-
contract_id.clone(),
446-
reason,
447-
));
448-
}
449-
450-
if port < 1024 || port > u128::from(u16::MAX - 1) {
451-
let reason = format!(
452-
"Contract {} stipulates a port lower than 1024 or above u16::MAX - 1",
453-
contract_id
454-
);
455-
warn!("{}", &reason);
456-
return Err(NetError::InvalidStackerDBContract(
457-
contract_id.clone(),
458-
reason,
459-
));
460-
}
461-
// NOTE: port is now known to be in range [1024, 65535]
462-
463-
let mut pubkey_hash_slice = [0u8; 20];
464-
pubkey_hash_slice.copy_from_slice(&pubkey_hash_bytes[0..20]);
465-
466-
let peer_addr = PeerAddress::from_slice(&addr_bytes).expect("FATAL: not 16 bytes");
467-
if peer_addr.is_in_private_range() {
468-
debug!(
469-
"Ignoring private IP address '{}' in hint-replicas",
470-
&peer_addr.to_socketaddr(port as u16)
471-
);
472-
continue;
473-
}
474-
475-
let naddr = NeighborAddress {
476-
addrbytes: peer_addr,
477-
port: port as u16,
478-
public_key_hash: Hash160(pubkey_hash_slice),
479-
};
480-
hint_replicas.push(naddr);
481-
}
495+
Self::eval_hint_replicas(contract_id, hint_replicas_list)?
496+
};
482497

483498
Ok(StackerDBConfig {
484499
chunk_size: chunk_size as u64,
@@ -497,6 +512,7 @@ impl StackerDBConfig {
497512
sortition_db: &SortitionDB,
498513
contract_id: &QualifiedContractIdentifier,
499514
max_neighbors: u64,
515+
local_hint_replicas: Option<Vec<NeighborAddress>>,
500516
) -> Result<StackerDBConfig, NetError> {
501517
let chain_tip =
502518
NakamotoChainState::get_canonical_block_header(chainstate.db(), sortition_db)?
@@ -578,6 +594,7 @@ impl StackerDBConfig {
578594
&chain_tip_hash,
579595
signers,
580596
max_neighbors,
597+
local_hint_replicas,
581598
)?;
582599
Ok(config)
583600
}

stackslib/src/net/stackerdb/mod.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ use crate::chainstate::burn::db::sortdb::SortitionDB;
133133
use crate::chainstate::nakamoto::NakamotoChainState;
134134
use crate::chainstate::stacks::boot::MINERS_NAME;
135135
use crate::chainstate::stacks::db::StacksChainState;
136+
use crate::net::connection::ConnectionOptions;
136137
use crate::net::neighbors::NeighborComms;
137138
use crate::net::p2p::PeerNetwork;
138139
use crate::net::{
@@ -285,8 +286,9 @@ impl StackerDBs {
285286
chainstate: &mut StacksChainState,
286287
sortdb: &SortitionDB,
287288
stacker_db_configs: HashMap<QualifiedContractIdentifier, StackerDBConfig>,
288-
num_neighbors: u64,
289+
connection_opts: &ConnectionOptions,
289290
) -> Result<HashMap<QualifiedContractIdentifier, StackerDBConfig>, net_error> {
291+
let num_neighbors = connection_opts.num_neighbors;
290292
let existing_contract_ids = self.get_stackerdb_contract_ids()?;
291293
let mut new_stackerdb_configs = HashMap::new();
292294
let tip = SortitionDB::get_canonical_burn_chain_tip(sortdb.conn())?;
@@ -314,6 +316,10 @@ impl StackerDBs {
314316
&sortdb,
315317
&stackerdb_contract_id,
316318
num_neighbors,
319+
connection_opts
320+
.stackerdb_hint_replicas
321+
.get(&stackerdb_contract_id)
322+
.cloned(),
317323
)
318324
.unwrap_or_else(|e| {
319325
if matches!(e, net_error::NoSuchStackerDB(_)) && stackerdb_contract_id.is_boot()

0 commit comments

Comments
 (0)