Skip to content

Commit de5dd90

Browse files
authored
Merge pull request #4006 from ProvableHQ/fix/sha-length
[Fix] Use array for handshake commit hashes
2 parents 3344448 + 545738e commit de5dd90

File tree

5 files changed

+72
-65
lines changed

5 files changed

+72
-65
lines changed

node/bft/events/src/challenge_request.rs

Lines changed: 23 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -15,27 +15,23 @@
1515

1616
use super::*;
1717

18-
use snarkos_node_network::built_info;
18+
use snarkos_node_network::get_repo_commit_hash;
1919

2020
#[derive(Clone, Debug, PartialEq, Eq)]
2121
pub struct ChallengeRequest<N: Network> {
2222
pub version: u32,
2323
pub listener_port: u16,
2424
pub address: Address<N>,
2525
pub nonce: u64,
26-
pub snarkos_sha: String,
26+
pub snarkos_sha: Option<[u8; 40]>,
2727
}
2828

2929
impl<N: Network> ChallengeRequest<N> {
30-
/// Creates a new `ChallengeRequest` event.
30+
/// Constant for an unknown commit hash.
31+
const UNKNOWN_COMMIT_HASH: [u8; 40] = [b'?'; 40];
32+
3133
pub fn new(listener_port: u16, address: Address<N>, nonce: u64) -> Self {
32-
Self {
33-
version: Event::<N>::VERSION,
34-
listener_port,
35-
address,
36-
nonce,
37-
snarkos_sha: built_info::GIT_COMMIT_HASH.unwrap_or_default().into(),
38-
}
34+
Self { version: Event::<N>::VERSION, listener_port, address, nonce, snarkos_sha: get_repo_commit_hash() }
3935
}
4036
}
4137

@@ -48,35 +44,38 @@ impl<N: Network> EventTrait for ChallengeRequest<N> {
4844
}
4945

5046
impl<N: Network> ToBytes for ChallengeRequest<N> {
51-
fn write_le<W: Write>(&self, mut writer: W) -> IoResult<()> {
47+
fn write_le<W: Write>(&self, mut writer: W) -> io::Result<()> {
5248
self.version.write_le(&mut writer)?;
5349
self.listener_port.write_le(&mut writer)?;
5450
self.address.write_le(&mut writer)?;
5551
self.nonce.write_le(&mut writer)?;
56-
self.snarkos_sha.as_bytes().write_le(&mut writer)?;
52+
// Serialize `None` as a constant.
53+
self.snarkos_sha.unwrap_or(Self::UNKNOWN_COMMIT_HASH).write_le(&mut writer)?;
5754

5855
Ok(())
5956
}
6057
}
6158

6259
impl<N: Network> FromBytes for ChallengeRequest<N> {
63-
fn read_le<R: Read>(mut reader: R) -> IoResult<Self> {
60+
fn read_le<R: Read>(mut reader: R) -> io::Result<Self> {
6461
let version = u32::read_le(&mut reader)?;
6562
let listener_port = u16::read_le(&mut reader)?;
6663
let address = Address::<N>::read_le(&mut reader)?;
6764
let nonce = u64::read_le(&mut reader)?;
68-
let snarkos_sha = str::from_utf8(&<[u8; 40]>::read_le(&mut reader).unwrap_or([b'?'; 40])[..])
69-
.map(|str| if str.starts_with('?') { "unknown" } else { str })
70-
.map_err(|_| error("Invalid snarkOS SHA"))?
71-
.to_owned();
65+
let snarkos_sha = {
66+
let bytes =
67+
<[u8; 40]>::read_le(&mut reader).map_err(|err| io_error(format!("Invalid snarkOS SHA - {err}")))?;
68+
if bytes == Self::UNKNOWN_COMMIT_HASH { None } else { Some(bytes) }
69+
};
7270

7371
Ok(Self { version, listener_port, address, nonce, snarkos_sha })
7472
}
7573
}
7674

7775
#[cfg(test)]
7876
pub mod prop_tests {
79-
use crate::ChallengeRequest;
77+
use super::*;
78+
8079
use snarkvm::{
8180
console::prelude::{FromBytes, ToBytes},
8281
prelude::{Address, TestRng, Uniform},
@@ -97,12 +96,11 @@ pub mod prop_tests {
9796

9897
pub fn any_challenge_request() -> BoxedStrategy<ChallengeRequest<CurrentNetwork>> {
9998
(any_valid_address(), any::<u64>(), any::<u32>(), any::<u16>(), collection::vec(0u8..=127, 40))
100-
.prop_map(|(address, nonce, version, listener_port, sha)| ChallengeRequest {
101-
address,
102-
nonce,
103-
version,
104-
listener_port,
105-
snarkos_sha: sha.into_iter().map(|b| b as char).collect(),
99+
.prop_map(|(address, nonce, version, listener_port, sha)| {
100+
let sha: [u8; 40] = sha.try_into().unwrap();
101+
let snarkos_sha =
102+
if sha == ChallengeRequest::<CurrentNetwork>::UNKNOWN_COMMIT_HASH { None } else { Some(sha) };
103+
ChallengeRequest { address, nonce, version, listener_port, snarkos_sha }
106104
})
107105
.boxed()
108106
}
@@ -112,12 +110,8 @@ pub mod prop_tests {
112110
let mut buf = BytesMut::default().writer();
113111
ChallengeRequest::write_le(&original, &mut buf).unwrap();
114112

115-
let mut deserialized: ChallengeRequest<CurrentNetwork> =
113+
let deserialized: ChallengeRequest<CurrentNetwork> =
116114
ChallengeRequest::read_le(buf.into_inner().reader()).unwrap();
117-
// Upon deserialization, unsupplied SHA is registered as "unknown".
118-
if deserialized.snarkos_sha == "unknown" {
119-
deserialized.snarkos_sha = original.snarkos_sha.clone();
120-
}
121115
assert_eq!(original, deserialized);
122116
}
123117
}

node/bft/events/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ pub use worker_ping::WorkerPing;
6868

6969
use snarkos_node_sync_locators::BlockLocators;
7070
use snarkvm::{
71-
console::prelude::{FromBytes, Network, Read, ToBytes, Write, error},
71+
console::prelude::{FromBytes, Network, Read, ToBytes, Write, error, io_error},
7272
ledger::{
7373
block::Block,
7474
narwhal::{BatchCertificate, BatchHeader, Data, Transmission, TransmissionID},

node/bft/tests/gateway_e2e.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ async fn handshake_responder_side_invalid_challenge_request() {
110110
let listener_port = test_peer.listening_addr().port();
111111
let address = accounts.get(1).unwrap().address();
112112
let nonce = rng.r#gen();
113-
let snarkos_sha = String::new();
113+
let snarkos_sha = None;
114114
// Set the wrong version so the challenge request is invalid.
115115
let challenge_request = ChallengeRequest { version: 0, listener_port, address, nonce, snarkos_sha };
116116

@@ -150,7 +150,7 @@ async fn handshake_responder_side_invalid_challenge_response() {
150150
let listener_port = test_peer.listening_addr().port();
151151
let address = accounts.get(1).unwrap().address();
152152
let our_nonce = rng.r#gen();
153-
let snarkos_sha = String::new();
153+
let snarkos_sha = None;
154154
let version = Event::<CurrentNetwork>::VERSION;
155155
let challenge_request = ChallengeRequest { version, listener_port, address, nonce: our_nonce, snarkos_sha };
156156

node/network/src/lib.rs

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -79,17 +79,31 @@ pub fn bootstrap_peers<N: Network>(is_dev: bool) -> Vec<SocketAddr> {
7979
}
8080
}
8181

82+
/// Get our SHA from the build information (or None if it is not set or does not 40 bytes long).
83+
pub fn get_repo_commit_hash() -> Option<[u8; 40]> {
84+
built_info::GIT_COMMIT_HASH.and_then(|sha| sha.as_bytes().try_into().ok())
85+
}
86+
8287
/// Logs the peer's snarkOS repo SHA and how it compares to ours.
83-
pub fn log_repo_sha_comparison(peer_addr: SocketAddr, peer_sha: &str, ctx: &str) {
84-
let our_sha = built_info::GIT_COMMIT_HASH.unwrap_or_default();
85-
let sha_cmp = if peer_sha == "unknown" {
86-
" with an unknown repo SHA".to_owned()
87-
} else if peer_sha == our_sha {
88-
format!("@{peer_sha} (same as us)")
89-
} else if our_sha.is_empty() {
90-
format!("@{peer_sha} (potentially different than us)")
91-
} else {
92-
format!("@{peer_sha} (different than us)")
88+
pub fn log_repo_sha_comparison(peer_addr: SocketAddr, peer_sha: &Option<[u8; 40]>, ctx: &str) {
89+
let our_sha = get_repo_commit_hash();
90+
91+
// Generate a string representation for the peers hash.
92+
let peer_sha_str: Option<&str> = peer_sha.as_ref().and_then(|h| str::from_utf8(h).ok());
93+
94+
let sha_cmp = match (&our_sha, peer_sha, peer_sha_str) {
95+
// They sent no hash, or an invalid string.
96+
(_, _, None) | (_, None, _) => " with an unknown repo SHA".to_owned(),
97+
// Our hash cannot be retrieved.
98+
(None, _, Some(theirs_str)) => format!("@{theirs_str} (potentially different than us)"),
99+
// Both hashes are valid. Compare.
100+
(Some(ours), Some(theirs), Some(theirs_str)) => {
101+
if ours == theirs {
102+
format!("@{theirs_str} (same as us)")
103+
} else {
104+
format!("@{theirs_str} (different than us)")
105+
}
106+
}
93107
};
94108

95109
debug!("{ctx} Peer '{peer_addr}' uses snarkOS{sha_cmp}");

node/router/messages/src/challenge_request.rs

Lines changed: 22 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@
1515

1616
use super::*;
1717

18-
use snarkos_node_network::{NodeType, built_info};
19-
use snarkvm::prelude::{FromBytes, ToBytes};
18+
use snarkos_node_network::{NodeType, get_repo_commit_hash};
19+
use snarkvm::prelude::{FromBytes, ToBytes, io_error};
2020

2121
use std::borrow::Cow;
2222

@@ -27,7 +27,7 @@ pub struct ChallengeRequest<N: Network> {
2727
pub node_type: NodeType,
2828
pub address: Address<N>,
2929
pub nonce: u64,
30-
pub snarkos_sha: String,
30+
pub snarkos_sha: Option<[u8; 40]>,
3131
}
3232

3333
impl<N: Network> MessageTrait for ChallengeRequest<N> {
@@ -45,7 +45,7 @@ impl<N: Network> ToBytes for ChallengeRequest<N> {
4545
self.node_type.write_le(&mut writer)?;
4646
self.address.write_le(&mut writer)?;
4747
self.nonce.write_le(&mut writer)?;
48-
self.snarkos_sha.as_bytes().write_le(&mut writer)?;
48+
self.snarkos_sha.unwrap_or(Self::UNKNOWN_COMMIT_HASH).write_le(&mut writer)?;
4949

5050
Ok(())
5151
}
@@ -58,32 +58,37 @@ impl<N: Network> FromBytes for ChallengeRequest<N> {
5858
let node_type = NodeType::read_le(&mut reader)?;
5959
let address = Address::<N>::read_le(&mut reader)?;
6060
let nonce = u64::read_le(&mut reader)?;
61-
let snarkos_sha = str::from_utf8(&<[u8; 40]>::read_le(&mut reader).unwrap_or([b'?'; 40])[..])
62-
.map(|str| if str.starts_with('?') { "unknown" } else { str })
63-
.map_err(|_| error("Invalid snarkOS SHA"))?
64-
.to_owned();
61+
62+
let snarkos_sha = {
63+
let bytes =
64+
<[u8; 40]>::read_le(&mut reader).map_err(|err| io_error(format!("Invalid snarkOS SHA - {err}")))?;
65+
if bytes == Self::UNKNOWN_COMMIT_HASH { None } else { Some(bytes) }
66+
};
6567

6668
Ok(Self { version, listener_port, node_type, address, nonce, snarkos_sha })
6769
}
6870
}
6971

7072
impl<N: Network> ChallengeRequest<N> {
73+
/// Constant for an unknown commit hash.
74+
const UNKNOWN_COMMIT_HASH: [u8; 40] = [b'?'; 40];
75+
7176
pub fn new(listener_port: u16, node_type: NodeType, address: Address<N>, nonce: u64) -> Self {
7277
Self {
7378
version: Message::<N>::latest_message_version(),
7479
listener_port,
7580
node_type,
7681
address,
7782
nonce,
78-
snarkos_sha: built_info::GIT_COMMIT_HASH.unwrap_or_default().into(),
83+
snarkos_sha: get_repo_commit_hash(),
7984
}
8085
}
8186
}
8287

8388
#[cfg(test)]
8489
pub mod prop_tests {
85-
use crate::ChallengeRequest;
86-
use snarkos_node_network::NodeType;
90+
use super::*;
91+
8792
use snarkvm::{
8893
console::prelude::{FromBytes, ToBytes},
8994
prelude::{Address, TestRng, Uniform},
@@ -115,13 +120,11 @@ pub mod prop_tests {
115120

116121
pub fn any_challenge_request() -> BoxedStrategy<ChallengeRequest<CurrentNetwork>> {
117122
(any_valid_address(), any::<u64>(), any::<u32>(), any::<u16>(), any_node_type(), collection::vec(0u8..=127, 40))
118-
.prop_map(|(address, nonce, version, listener_port, node_type, sha)| ChallengeRequest {
119-
address,
120-
nonce,
121-
version,
122-
listener_port,
123-
node_type,
124-
snarkos_sha: sha.into_iter().map(|b| b as char).collect(),
123+
.prop_map(|(address, nonce, version, listener_port, node_type, sha)| {
124+
let sha: [u8; 40] = sha.try_into().unwrap();
125+
let snarkos_sha =
126+
if sha == ChallengeRequest::<CurrentNetwork>::UNKNOWN_COMMIT_HASH { None } else { Some(sha) };
127+
ChallengeRequest { address, nonce, version, listener_port, node_type, snarkos_sha }
125128
})
126129
.boxed()
127130
}
@@ -131,12 +134,8 @@ pub mod prop_tests {
131134
let mut buf = BytesMut::default().writer();
132135
ChallengeRequest::write_le(&original, &mut buf).unwrap();
133136

134-
let mut deserialized: ChallengeRequest<CurrentNetwork> =
137+
let deserialized: ChallengeRequest<CurrentNetwork> =
135138
ChallengeRequest::read_le(buf.into_inner().reader()).unwrap();
136-
// Upon deserialization, unsupplied SHA is registered as "unknown".
137-
if deserialized.snarkos_sha == "unknown" {
138-
deserialized.snarkos_sha = original.snarkos_sha.clone();
139-
}
140139
assert_eq!(original, deserialized);
141140
}
142141
}

0 commit comments

Comments
 (0)