diff --git a/.github/workflows/bitcoin-tests.yml b/.github/workflows/bitcoin-tests.yml
index 19669aebd8..ff686ed831 100644
--- a/.github/workflows/bitcoin-tests.yml
+++ b/.github/workflows/bitcoin-tests.yml
@@ -139,6 +139,7 @@ jobs:
- tests::neon_integrations::bad_microblock_pubkey
- tests::epoch_24::fix_to_pox_contract
- tests::epoch_24::verify_auto_unlock_behavior
+ - tests::signer::test_stackerdb_dkg
- tests::stackerdb::test_stackerdb_load_store
- tests::stackerdb::test_stackerdb_event_observer
steps:
diff --git a/Cargo.lock b/Cargo.lock
index 4096da6da0..6f0d0c6217 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -450,28 +450,6 @@ dependencies = [
"serde",
]
-[[package]]
-name = "bindgen"
-version = "0.64.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c4243e6031260db77ede97ad86c27e501d646a27ab57b59a574f725d98ab1fb4"
-dependencies = [
- "bitflags 1.3.2",
- "cexpr",
- "clang-sys",
- "lazy_static",
- "lazycell",
- "log",
- "peeking_take_while",
- "proc-macro2",
- "quote",
- "regex",
- "rustc-hash",
- "shlex",
- "syn 1.0.109",
- "which",
-]
-
[[package]]
name = "bitflags"
version = "1.3.2"
@@ -606,15 +584,6 @@ version = "1.0.79"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f"
-[[package]]
-name = "cexpr"
-version = "0.6.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766"
-dependencies = [
- "nom",
-]
-
[[package]]
name = "cfg-if"
version = "0.1.10"
@@ -667,17 +636,6 @@ dependencies = [
"inout",
]
-[[package]]
-name = "clang-sys"
-version = "1.6.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c688fc74432808e3eb684cae8830a86be1d66a2bd58e1f248ed0960a590baf6f"
-dependencies = [
- "glob",
- "libc",
- "libloading",
-]
-
[[package]]
name = "clap"
version = "2.34.0"
@@ -1459,12 +1417,6 @@ version = "0.27.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ad0a93d233ebf96623465aad4046a8d3aa4da22d4f4beba5388838c8a434bbb4"
-[[package]]
-name = "glob"
-version = "0.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
-
[[package]]
name = "gloo-timers"
version = "0.2.6"
@@ -1925,12 +1877,6 @@ version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
-[[package]]
-name = "lazycell"
-version = "1.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
-
[[package]]
name = "libc"
version = "0.2.140"
@@ -1957,16 +1903,6 @@ dependencies = [
"rle-decode-fast",
]
-[[package]]
-name = "libloading"
-version = "0.7.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f"
-dependencies = [
- "cfg-if 1.0.0",
- "winapi 0.3.9",
-]
-
[[package]]
name = "libsigner"
version = "0.0.1"
@@ -2086,12 +2022,6 @@ dependencies = [
"unicase",
]
-[[package]]
-name = "minimal-lexical"
-version = "0.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
-
[[package]]
name = "miniz_oxide"
version = "0.6.2"
@@ -2204,16 +2134,6 @@ dependencies = [
"memoffset 0.6.5",
]
-[[package]]
-name = "nom"
-version = "7.1.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
-dependencies = [
- "memchr",
- "minimal-lexical",
-]
-
[[package]]
name = "nu-ansi-term"
version = "0.46.0"
@@ -2348,10 +2268,7 @@ checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39"
[[package]]
name = "p256k1"
version = "5.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "22e81c2cb5a1936d3f26278f9d698932239d03ddf0d5818392d91cd5f98ffc79"
dependencies = [
- "bindgen",
"bitvec",
"bs58 0.4.0",
"cc",
@@ -2400,12 +2317,6 @@ version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "427c3892f9e783d91cc128285287e70a59e206ca452770ece88a76f7a3eddd72"
-[[package]]
-name = "peeking_take_while"
-version = "0.1.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099"
-
[[package]]
name = "percent-encoding"
version = "2.2.0"
@@ -2968,12 +2879,6 @@ version = "0.1.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342"
-[[package]]
-name = "rustc-hash"
-version = "1.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
-
[[package]]
name = "rustc-hex"
version = "2.1.0"
@@ -3378,12 +3283,6 @@ dependencies = [
"lazy_static",
]
-[[package]]
-name = "shlex"
-version = "1.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3"
-
[[package]]
name = "simple-mutex"
version = "1.1.5"
@@ -4453,17 +4352,6 @@ version = "0.25.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14247bb57be4f377dfb94c72830b8ce8fc6beac03cf4bf7b9732eadd414123fc"
-[[package]]
-name = "which"
-version = "4.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2441c784c52b289a054b7201fc93253e288f094e2f4be9058343127c4226a269"
-dependencies = [
- "either",
- "libc",
- "once_cell",
-]
-
[[package]]
name = "winapi"
version = "0.2.8"
@@ -4686,8 +4574,6 @@ dependencies = [
[[package]]
name = "wsts"
version = "4.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4a0c0ec44cbd35be82490c8c566ad4971f7b41ffe8508f1c9938140df7fe18b2"
dependencies = [
"aes-gcm 0.10.2",
"bs58 0.5.0",
diff --git a/Cargo.toml b/Cargo.toml
index 7a87639a02..2a04b86a6a 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -24,3 +24,4 @@ opt-level = 3
[profile.release]
debug = true
+
diff --git a/stacks-common/src/types/mod.rs b/stacks-common/src/types/mod.rs
index 0d4e0c9fa9..8d84666f2d 100644
--- a/stacks-common/src/types/mod.rs
+++ b/stacks-common/src/types/mod.rs
@@ -14,6 +14,7 @@ use crate::util::hash::Hash160;
use crate::util::secp256k1::{MessageSignature, Secp256k1PublicKey};
pub mod chainstate;
+pub mod net;
/// A container for public keys (compressed secp256k1 public keys)
pub struct StacksPublicKeyBuffer(pub [u8; 33]);
diff --git a/stacks-common/src/types/net.rs b/stacks-common/src/types/net.rs
new file mode 100644
index 0000000000..45b6fb43ef
--- /dev/null
+++ b/stacks-common/src/types/net.rs
@@ -0,0 +1,382 @@
+// Copyright (C) 2013-2020 Blockstack PBC, a public benefit corporation
+// Copyright (C) 2020-2023 Stacks Open Internet Foundation
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+
+use std::fmt;
+use std::hash::{Hash, Hasher};
+use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
+use std::str::FromStr;
+
+use serde::de::{Deserialize, Error as de_Error};
+use serde::ser::Serialize;
+
+use crate::util::hash::to_bin;
+
+#[derive(Debug)]
+pub enum Error {
+ DecodeError(String),
+}
+
+impl fmt::Display for Error {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match self {
+ Error::DecodeError(msg) => write!(f, "{}", &msg),
+ }
+ }
+}
+
+impl std::error::Error for Error {
+ fn cause(&self) -> Option<&dyn std::error::Error> {
+ match self {
+ Error::DecodeError(_) => None,
+ }
+ }
+}
+
+/// A container for an IPv4 or IPv6 address.
+/// Rules:
+/// -- If this is an IPv6 address, the octets are in network byte order
+/// -- If this is an IPv4 address, the octets must encode an IPv6-to-IPv4-mapped address
+pub struct PeerAddress(pub [u8; 16]);
+impl_array_newtype!(PeerAddress, u8, 16);
+impl_array_hexstring_fmt!(PeerAddress);
+impl_byte_array_newtype!(PeerAddress, u8, 16);
+impl_byte_array_message_codec!(PeerAddress, 16);
+
+impl Serialize for PeerAddress {
+ fn serialize(&self, s: S) -> Result {
+ let inst = format!("{}", self.to_socketaddr(0).ip());
+ s.serialize_str(inst.as_str())
+ }
+}
+
+impl<'de> Deserialize<'de> for PeerAddress {
+ fn deserialize>(d: D) -> Result {
+ let inst = String::deserialize(d)?;
+ let ip = inst.parse::().map_err(de_Error::custom)?;
+
+ Ok(PeerAddress::from_ip(&ip))
+ }
+}
+
+impl PeerAddress {
+ pub fn from_slice(bytes: &[u8]) -> Option {
+ if bytes.len() != 16 {
+ return None;
+ }
+
+ let mut bytes16 = [0u8; 16];
+ bytes16.copy_from_slice(&bytes[0..16]);
+ Some(PeerAddress(bytes16))
+ }
+
+ /// Is this an IPv4 address?
+ pub fn is_ipv4(&self) -> bool {
+ self.ipv4_octets().is_some()
+ }
+
+ /// Get the octet representation of this peer address as an IPv4 address.
+ /// The last 4 bytes of the list contain the IPv4 address.
+ /// This method returns None if the bytes don't encode a valid IPv4-mapped address (i.e. ::ffff:0:0/96)
+ pub fn ipv4_octets(&self) -> Option<[u8; 4]> {
+ if self.0[0..12]
+ != [
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
+ ]
+ {
+ return None;
+ }
+ let mut ret = [0u8; 4];
+ ret.copy_from_slice(&self.0[12..16]);
+ Some(ret)
+ }
+
+ /// Return the bit representation of this peer address as an IPv4 address, in network byte
+ /// order. Return None if this is not an IPv4 address.
+ pub fn ipv4_bits(&self) -> Option {
+ let octets_opt = self.ipv4_octets();
+ if octets_opt.is_none() {
+ return None;
+ }
+
+ let octets = octets_opt.unwrap();
+ Some(
+ ((octets[0] as u32) << 24)
+ | ((octets[1] as u32) << 16)
+ | ((octets[2] as u32) << 8)
+ | (octets[3] as u32),
+ )
+ }
+
+ /// Convert to SocketAddr
+ pub fn to_socketaddr(&self, port: u16) -> SocketAddr {
+ if self.is_ipv4() {
+ SocketAddr::new(
+ IpAddr::V4(Ipv4Addr::new(
+ self.0[12], self.0[13], self.0[14], self.0[15],
+ )),
+ port,
+ )
+ } else {
+ let addr_words: [u16; 8] = [
+ ((self.0[0] as u16) << 8) | (self.0[1] as u16),
+ ((self.0[2] as u16) << 8) | (self.0[3] as u16),
+ ((self.0[4] as u16) << 8) | (self.0[5] as u16),
+ ((self.0[6] as u16) << 8) | (self.0[7] as u16),
+ ((self.0[8] as u16) << 8) | (self.0[9] as u16),
+ ((self.0[10] as u16) << 8) | (self.0[11] as u16),
+ ((self.0[12] as u16) << 8) | (self.0[13] as u16),
+ ((self.0[14] as u16) << 8) | (self.0[15] as u16),
+ ];
+
+ SocketAddr::new(
+ IpAddr::V6(Ipv6Addr::new(
+ addr_words[0],
+ addr_words[1],
+ addr_words[2],
+ addr_words[3],
+ addr_words[4],
+ addr_words[5],
+ addr_words[6],
+ addr_words[7],
+ )),
+ port,
+ )
+ }
+ }
+
+ /// Convert from socket address
+ pub fn from_socketaddr(addr: &SocketAddr) -> PeerAddress {
+ PeerAddress::from_ip(&addr.ip())
+ }
+
+ /// Convert from IP address
+ pub fn from_ip(addr: &IpAddr) -> PeerAddress {
+ match addr {
+ IpAddr::V4(ref addr) => {
+ let octets = addr.octets();
+ PeerAddress([
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
+ octets[0], octets[1], octets[2], octets[3],
+ ])
+ }
+ IpAddr::V6(ref addr) => {
+ let words = addr.segments();
+ PeerAddress([
+ (words[0] >> 8) as u8,
+ (words[0] & 0xff) as u8,
+ (words[1] >> 8) as u8,
+ (words[1] & 0xff) as u8,
+ (words[2] >> 8) as u8,
+ (words[2] & 0xff) as u8,
+ (words[3] >> 8) as u8,
+ (words[3] & 0xff) as u8,
+ (words[4] >> 8) as u8,
+ (words[4] & 0xff) as u8,
+ (words[5] >> 8) as u8,
+ (words[5] & 0xff) as u8,
+ (words[6] >> 8) as u8,
+ (words[6] & 0xff) as u8,
+ (words[7] >> 8) as u8,
+ (words[7] & 0xff) as u8,
+ ])
+ }
+ }
+ }
+
+ /// Convert from ipv4 octets
+ pub fn from_ipv4(o1: u8, o2: u8, o3: u8, o4: u8) -> PeerAddress {
+ PeerAddress([
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, o1, o2, o3, o4,
+ ])
+ }
+
+ /// Is this the any-network address? i.e. 0.0.0.0 (v4) or :: (v6)?
+ pub fn is_anynet(&self) -> bool {
+ self.0 == [0x00; 16] || self == &PeerAddress::from_ipv4(0, 0, 0, 0)
+ }
+
+ /// Is this a private IP address?
+ pub fn is_in_private_range(&self) -> bool {
+ if self.is_ipv4() {
+ // 10.0.0.0/8, 172.16.0.0/12, or 192.168.0.0/16
+ self.0[12] == 10
+ || (self.0[12] == 172 && self.0[13] >= 16 && self.0[13] <= 31)
+ || (self.0[12] == 192 && self.0[13] == 168)
+ } else {
+ self.0[0] >= 0xfc
+ }
+ }
+
+ pub fn to_bin(&self) -> String {
+ to_bin(&self.0)
+ }
+}
+
+/// Peer address variants for the Host: header
+#[derive(Clone, PartialEq)]
+pub enum PeerHost {
+ DNS(String, u16),
+ IP(PeerAddress, u16),
+}
+
+impl fmt::Display for PeerHost {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match *self {
+ PeerHost::DNS(ref s, ref p) => write!(f, "{}:{}", s, p),
+ PeerHost::IP(ref a, ref p) => write!(f, "{}", a.to_socketaddr(*p)),
+ }
+ }
+}
+
+impl fmt::Debug for PeerHost {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match *self {
+ PeerHost::DNS(ref s, ref p) => write!(f, "PeerHost::DNS({},{})", s, p),
+ PeerHost::IP(ref a, ref p) => write!(f, "PeerHost::IP({:?},{})", a, p),
+ }
+ }
+}
+
+impl Hash for PeerHost {
+ fn hash(&self, state: &mut H) {
+ match *self {
+ PeerHost::DNS(ref name, ref port) => {
+ "DNS".hash(state);
+ name.hash(state);
+ port.hash(state);
+ }
+ PeerHost::IP(ref addrbytes, ref port) => {
+ "IP".hash(state);
+ addrbytes.hash(state);
+ port.hash(state);
+ }
+ }
+ }
+}
+
+impl FromStr for PeerHost {
+ type Err = Error;
+
+ fn from_str(header: &str) -> Result {
+ // we're looser than the RFC allows for DNS names -- anything that doesn't parse to an IP
+ // address will be parsed to a DNS name.
+ // try as IP:port
+ match header.parse::() {
+ Ok(socketaddr) => Ok(PeerHost::IP(
+ PeerAddress::from_socketaddr(&socketaddr),
+ socketaddr.port(),
+ )),
+ Err(_) => {
+ // maybe missing :port
+ let hostport = format!("{}:80", header);
+ match hostport.parse::() {
+ Ok(socketaddr) => Ok(PeerHost::IP(
+ PeerAddress::from_socketaddr(&socketaddr),
+ socketaddr.port(),
+ )),
+ Err(_) => {
+ // try as DNS-name:port
+ let host;
+ let port;
+ let parts: Vec<&str> = header.split(":").collect();
+ if parts.len() == 0 {
+ return Err(Error::DecodeError(
+ "Failed to parse PeerHost: no parts".to_string(),
+ ));
+ } else if parts.len() == 1 {
+ // no port
+ host = Some(parts[0].to_string());
+ port = Some(80);
+ } else {
+ let np = parts.len();
+ if parts[np - 1].chars().all(char::is_numeric) {
+ // ends in :port
+ let host_str = parts[0..np - 1].join(":");
+ if host_str.len() == 0 {
+ return Err(Error::DecodeError("Empty host".to_string()));
+ }
+ host = Some(host_str);
+
+ let port_res = parts[np - 1].parse::();
+ port = match port_res {
+ Ok(p) => Some(p),
+ Err(_) => {
+ return Err(Error::DecodeError(
+ "Failed to parse PeerHost: invalid port".to_string(),
+ ));
+ }
+ };
+ } else {
+ // only host
+ host = Some(header.to_string());
+ port = Some(80);
+ }
+ }
+
+ match (host, port) {
+ (Some(h), Some(p)) => Ok(PeerHost::DNS(h, p)),
+ (_, _) => Err(Error::DecodeError(
+ "Failed to parse PeerHost: failed to extract host and/or port"
+ .to_string(),
+ )), // I don't think this is reachable
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+impl PeerHost {
+ pub fn hostname(&self) -> String {
+ match *self {
+ PeerHost::DNS(ref s, _) => s.clone(),
+ PeerHost::IP(ref a, ref p) => format!("{}", a.to_socketaddr(*p).ip()),
+ }
+ }
+
+ pub fn port(&self) -> u16 {
+ match *self {
+ PeerHost::DNS(_, ref p) => *p,
+ PeerHost::IP(_, ref p) => *p,
+ }
+ }
+
+ pub fn from_host_port(host: String, port: u16) -> PeerHost {
+ // try as IP, and fall back to DNS
+ match host.parse::() {
+ Ok(addr) => PeerHost::IP(PeerAddress::from_ip(&addr), port),
+ Err(_) => PeerHost::DNS(host, port),
+ }
+ }
+
+ pub fn from_socketaddr(socketaddr: &SocketAddr) -> PeerHost {
+ PeerHost::IP(PeerAddress::from_socketaddr(socketaddr), socketaddr.port())
+ }
+
+ pub fn to_host_port(&self) -> (String, u16) {
+ match *self {
+ PeerHost::DNS(ref s, ref p) => (s.clone(), *p),
+ PeerHost::IP(ref i, ref p) => (format!("{}", i.to_socketaddr(0).ip()), *p),
+ }
+ }
+}
+
+impl From for PeerHost {
+ fn from(addr: SocketAddr) -> PeerHost {
+ PeerHost::from_socketaddr(&addr)
+ }
+}
diff --git a/stacks-common/src/util/chunked_encoding.rs b/stacks-common/src/util/chunked_encoding.rs
index 17afb25f05..bb1b869eee 100644
--- a/stacks-common/src/util/chunked_encoding.rs
+++ b/stacks-common/src/util/chunked_encoding.rs
@@ -20,6 +20,8 @@ use std::{error, fmt, io};
use crate::codec::MAX_MESSAGE_LEN;
use crate::deps_common::httparse;
+/// NOTE: it is imperative that the given Read and Write impls here _never_ fail with EWOULDBLOCK.
+
#[derive(Debug)]
pub enum ChunkedError {
DeserializeError(String),
@@ -336,6 +338,10 @@ impl HttpChunkedTransferWriterState {
corked: false,
}
}
+
+ pub fn get_chunk_size(&self) -> usize {
+ self.chunk_size
+ }
}
pub struct HttpChunkedTransferWriter<'a, 'state, W: Write> {
diff --git a/stacks-common/src/util/mod.rs b/stacks-common/src/util/mod.rs
index 5a8d68368a..97cbc4104f 100644
--- a/stacks-common/src/util/mod.rs
+++ b/stacks-common/src/util/mod.rs
@@ -63,8 +63,8 @@ pub enum HexError {
impl fmt::Display for HexError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
- HexError::BadLength(n) => write!(f, "bad length {} for sha256d hex string", n),
- HexError::BadCharacter(c) => write!(f, "bad character {} in sha256d hex string", c),
+ HexError::BadLength(n) => write!(f, "bad length {} for hex string", n),
+ HexError::BadCharacter(c) => write!(f, "bad character {} for hex string", c),
}
}
}
@@ -75,8 +75,8 @@ impl error::Error for HexError {
}
fn description(&self) -> &str {
match *self {
- HexError::BadLength(_) => "sha256d hex string non-64 length",
- HexError::BadCharacter(_) => "sha256d bad hex character",
+ HexError::BadLength(_) => "hex string non-64 length",
+ HexError::BadCharacter(_) => "bad hex character",
}
}
}
diff --git a/stacks-common/src/util/pipe.rs b/stacks-common/src/util/pipe.rs
index c07ad4dbe1..d850826fd4 100644
--- a/stacks-common/src/util/pipe.rs
+++ b/stacks-common/src/util/pipe.rs
@@ -220,6 +220,11 @@ impl PipeWrite {
Ok(buf.len())
}
+ /// How many bytes are pending?
+ pub fn pending(&self) -> usize {
+ self.buf.as_ref().map(|b| b.len()).unwrap_or(0)
+ }
+
/// Try and flush all data to the reader.
/// Return True if we succeeded; False if not.
pub fn try_flush(&mut self) -> io::Result {
diff --git a/stacks-signer/src/cli.rs b/stacks-signer/src/cli.rs
index c21c3d78cc..ab0e6649a3 100644
--- a/stacks-signer/src/cli.rs
+++ b/stacks-signer/src/cli.rs
@@ -2,10 +2,12 @@ use std::io::{self, Read};
use std::net::SocketAddr;
use std::path::PathBuf;
-use crate::config::Network;
use clap::Parser;
use clarity::vm::types::QualifiedContractIdentifier;
-use stacks_common::{address::b58, types::chainstate::StacksPrivateKey};
+use stacks_common::address::b58;
+use stacks_common::types::chainstate::StacksPrivateKey;
+
+use crate::config::Network;
extern crate alloc;
diff --git a/stacks-signer/src/config.rs b/stacks-signer/src/config.rs
index f198cf4044..d634dd0cdd 100644
--- a/stacks-signer/src/config.rs
+++ b/stacks-signer/src/config.rs
@@ -14,27 +14,23 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see .
+use std::convert::TryFrom;
+use std::fs;
+use std::net::{SocketAddr, ToSocketAddrs};
+use std::path::PathBuf;
+use std::time::Duration;
+
use blockstack_lib::chainstate::stacks::TransactionVersion;
use clarity::vm::types::QualifiedContractIdentifier;
use hashbrown::HashMap;
use p256k1::ecdsa;
use p256k1::scalar::Scalar;
use serde::Deserialize;
-use stacks_common::{
- address::{
- AddressHashMode, C32_ADDRESS_VERSION_MAINNET_SINGLESIG,
- C32_ADDRESS_VERSION_TESTNET_SINGLESIG,
- },
- consts::{CHAIN_ID_MAINNET, CHAIN_ID_TESTNET},
- types::chainstate::{StacksAddress, StacksPrivateKey, StacksPublicKey},
-};
-use std::{
- convert::TryFrom,
- fs,
- net::{SocketAddr, ToSocketAddrs},
- path::PathBuf,
- time::Duration,
+use stacks_common::address::{
+ AddressHashMode, C32_ADDRESS_VERSION_MAINNET_SINGLESIG, C32_ADDRESS_VERSION_TESTNET_SINGLESIG,
};
+use stacks_common::consts::{CHAIN_ID_MAINNET, CHAIN_ID_TESTNET};
+use stacks_common::types::chainstate::{StacksAddress, StacksPrivateKey, StacksPublicKey};
use wsts::state_machine::PublicKeys;
/// List of key_ids for each signer_id
diff --git a/stacks-signer/src/stacks_client.rs b/stacks-signer/src/stacks_client.rs
index 700858cfb4..0621df4b09 100644
--- a/stacks-signer/src/stacks_client.rs
+++ b/stacks-signer/src/stacks_client.rs
@@ -1,33 +1,25 @@
use std::time::Duration;
use bincode::Error as BincodeError;
-use blockstack_lib::{
- burnchains::Txid,
- chainstate::stacks::{
- StacksTransaction, StacksTransactionSigner, TransactionAnchorMode, TransactionAuth,
- TransactionContractCall, TransactionPayload, TransactionPostConditionMode,
- TransactionSpendingCondition, TransactionVersion,
- },
-};
-use clarity::vm::{
- types::{serialization::SerializationError, QualifiedContractIdentifier, SequenceData},
- Value as ClarityValue, {ClarityName, ContractName},
+use blockstack_lib::burnchains::Txid;
+use blockstack_lib::chainstate::stacks::{
+ StacksTransaction, StacksTransactionSigner, TransactionAnchorMode, TransactionAuth,
+ TransactionContractCall, TransactionPayload, TransactionPostConditionMode,
+ TransactionSpendingCondition, TransactionVersion,
};
+use clarity::vm::types::serialization::SerializationError;
+use clarity::vm::types::{QualifiedContractIdentifier, SequenceData};
+use clarity::vm::{ClarityName, ContractName, Value as ClarityValue};
use hashbrown::HashMap;
use libsigner::{RPCError, SignerSession, StackerDBSession};
use libstackerdb::{Error as StackerDBError, StackerDBChunkAckData, StackerDBChunkData};
use serde_json::json;
use slog::{slog_debug, slog_warn};
-use stacks_common::{
- codec::StacksMessageCodec,
- debug,
- types::chainstate::{StacksAddress, StacksPrivateKey, StacksPublicKey},
- warn,
-};
-use wsts::{
- net::{Message, Packet},
- Point, Scalar,
-};
+use stacks_common::codec::StacksMessageCodec;
+use stacks_common::types::chainstate::{StacksAddress, StacksPrivateKey, StacksPublicKey};
+use stacks_common::{debug, warn};
+use wsts::net::{Message, Packet};
+use wsts::{Point, Scalar};
use crate::config::Config;
@@ -466,11 +458,9 @@ fn slot_id(id: u32, message: &Message) -> u32 {
#[cfg(test)]
mod tests {
- use std::{
- io::{BufWriter, Read, Write},
- net::{SocketAddr, TcpListener},
- thread::spawn,
- };
+ use std::io::{BufWriter, Read, Write};
+ use std::net::{SocketAddr, TcpListener};
+ use std::thread::spawn;
use super::*;
diff --git a/stackslib/src/chainstate/burn/db/sortdb.rs b/stackslib/src/chainstate/burn/db/sortdb.rs
index 999d145828..4c63a28968 100644
--- a/stackslib/src/chainstate/burn/db/sortdb.rs
+++ b/stackslib/src/chainstate/burn/db/sortdb.rs
@@ -5569,6 +5569,7 @@ impl<'a> SortitionHandleTx<'a> {
let winner = hash_tied
.first()
.expect("FATAL: zero-length list of tied block IDs");
+
let winner_index = *mapping
.get(&winner)
.expect("FATAL: winning block ID not mapped");
diff --git a/stackslib/src/chainstate/stacks/db/blocks.rs b/stackslib/src/chainstate/stacks/db/blocks.rs
index e362cbbd85..25dcdc9f33 100644
--- a/stackslib/src/chainstate/stacks/db/blocks.rs
+++ b/stackslib/src/chainstate/stacks/db/blocks.rs
@@ -23,7 +23,6 @@ use std::{cmp, fmt, fs, io};
pub use clarity::vm::analysis::errors::{CheckError, CheckErrors};
use clarity::vm::analysis::run_analysis;
-use clarity::vm::ast::ASTRules;
use clarity::vm::clarity::TransactionConnection;
use clarity::vm::contexts::AssetMap;
use clarity::vm::contracts::Contract;
@@ -68,8 +67,7 @@ use crate::core::*;
use crate::cost_estimates::EstimatorError;
use crate::monitoring::{set_last_block_transaction_count, set_last_execution_cost_observed};
use crate::net::relay::Relayer;
-use crate::net::stream::{BlockStreamData, HeaderStreamData, MicroblockStreamData, Streamer};
-use crate::net::{BlocksInvData, Error as net_error, ExtendedStacksHeader};
+use crate::net::{BlocksInvData, Error as net_error};
use crate::util_lib::boot::boot_code_id;
use crate::util_lib::db::{
query_count, query_int, query_row, query_row_columns, query_row_panic, query_rows,
@@ -1158,6 +1156,15 @@ impl StacksChainState {
) -> Result