Skip to content

Commit bf30fa6

Browse files
committed
Deserialize only the necessary info from peer info to be more resilient to peer info updates in the signer
Signed-off-by: Jacinta Ferrant <[email protected]>
1 parent 5085bda commit bf30fa6

File tree

5 files changed

+131
-70
lines changed

5 files changed

+131
-70
lines changed

libsigner/src/v0/messages.rs

Lines changed: 105 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -239,57 +239,41 @@ pub trait StacksMessageCodecExtensions: Sized {
239239
fn inner_consensus_deserialize<R: Read>(fd: &mut R) -> Result<Self, CodecError>;
240240
}
241241

242-
/// A snapshot of the signer view of the stacks node to be used for mock signing.
243-
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
244-
pub struct MockSignData {
245-
/// The stacks tip consensus hash at the time of the mock signature
242+
/// The signer relevant peer information from the stacks node
243+
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
244+
pub struct PeerInfo {
245+
/// The burn block height
246+
pub burn_block_height: u64,
247+
/// The consensus hash of the stacks tip
246248
pub stacks_tip_consensus_hash: ConsensusHash,
247-
/// The stacks tip header hash at the time of the mock signature
249+
/// The stacks tip
248250
pub stacks_tip: BlockHeaderHash,
251+
/// The stacks tip height
252+
pub stacks_tip_height: u64,
253+
/// The pox consensus
254+
pub pox_consensus: ConsensusHash,
249255
/// The server version
250256
pub server_version: String,
251-
/// The burn block height that triggered the mock signature
252-
pub burn_block_height: u64,
253-
/// The burn block height of the peer view at the time of the mock signature. Note
254-
/// that this may be different from the burn_block_height if the peer view is stale.
255-
pub peer_burn_block_height: u64,
256-
/// The POX consensus hash at the time of the mock signature
257-
pub pox_consensus: ConsensusHash,
258-
/// The chain id for the mock signature
259-
pub chain_id: u32,
260-
}
261-
262-
impl MockSignData {
263-
fn new(peer_view: RPCPeerInfoData, burn_block_height: u64, chain_id: u32) -> Self {
264-
Self {
265-
stacks_tip_consensus_hash: peer_view.stacks_tip_consensus_hash,
266-
stacks_tip: peer_view.stacks_tip,
267-
server_version: peer_view.server_version,
268-
burn_block_height,
269-
peer_burn_block_height: peer_view.burn_block_height,
270-
pox_consensus: peer_view.pox_consensus,
271-
chain_id,
272-
}
273-
}
274257
}
275258

276-
impl StacksMessageCodec for MockSignData {
259+
impl StacksMessageCodec for PeerInfo {
277260
fn consensus_serialize<W: Write>(&self, fd: &mut W) -> Result<(), CodecError> {
261+
write_next(fd, &self.burn_block_height)?;
278262
write_next(fd, self.stacks_tip_consensus_hash.as_bytes())?;
279263
write_next(fd, &self.stacks_tip)?;
264+
write_next(fd, &self.stacks_tip_height)?;
280265
write_next(fd, &(self.server_version.as_bytes().len() as u8))?;
281266
fd.write_all(self.server_version.as_bytes())
282267
.map_err(CodecError::WriteError)?;
283-
write_next(fd, &self.burn_block_height)?;
284-
write_next(fd, &self.peer_burn_block_height)?;
285268
write_next(fd, &self.pox_consensus)?;
286-
write_next(fd, &self.chain_id)?;
287269
Ok(())
288270
}
289271

290272
fn consensus_deserialize<R: Read>(fd: &mut R) -> Result<Self, CodecError> {
273+
let burn_block_height = read_next::<u64, _>(fd)?;
291274
let stacks_tip_consensus_hash = read_next::<ConsensusHash, _>(fd)?;
292275
let stacks_tip = read_next::<BlockHeaderHash, _>(fd)?;
276+
let stacks_tip_height = read_next::<u64, _>(fd)?;
293277
let len_byte: u8 = read_next(fd)?;
294278
let mut bytes = vec![0u8; len_byte as usize];
295279
fd.read_exact(&mut bytes).map_err(CodecError::ReadError)?;
@@ -299,17 +283,44 @@ impl StacksMessageCodec for MockSignData {
299283
"Failed to parse server version name: could not contruct from utf8".to_string(),
300284
)
301285
})?;
302-
let burn_block_height = read_next::<u64, _>(fd)?;
303-
let peer_burn_block_height = read_next::<u64, _>(fd)?;
304286
let pox_consensus = read_next::<ConsensusHash, _>(fd)?;
305-
let chain_id = read_next::<u32, _>(fd)?;
306287
Ok(Self {
288+
burn_block_height,
307289
stacks_tip_consensus_hash,
308290
stacks_tip,
291+
stacks_tip_height,
309292
server_version,
310-
burn_block_height,
311-
peer_burn_block_height,
312293
pox_consensus,
294+
})
295+
}
296+
}
297+
298+
/// A snapshot of the signer view of the stacks node to be used for mock signing.
299+
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
300+
pub struct MockSignData {
301+
/// The view of the stacks node peer information at the time of the mock signature
302+
pub peer_info: PeerInfo,
303+
/// The burn block height of the event that triggered the mock signature
304+
pub event_burn_block_height: u64,
305+
/// The chain id for the mock signature
306+
pub chain_id: u32,
307+
}
308+
309+
impl StacksMessageCodec for MockSignData {
310+
fn consensus_serialize<W: Write>(&self, fd: &mut W) -> Result<(), CodecError> {
311+
self.peer_info.consensus_serialize(fd)?;
312+
write_next(fd, &self.event_burn_block_height)?;
313+
write_next(fd, &self.chain_id)?;
314+
Ok(())
315+
}
316+
317+
fn consensus_deserialize<R: Read>(fd: &mut R) -> Result<Self, CodecError> {
318+
let peer_info = PeerInfo::consensus_deserialize(fd)?;
319+
let event_burn_block_height = read_next::<u64, _>(fd)?;
320+
let chain_id = read_next::<u32, _>(fd)?;
321+
Ok(Self {
322+
peer_info,
323+
event_burn_block_height,
313324
chain_id,
314325
})
315326
}
@@ -326,16 +337,21 @@ pub struct MockSignature {
326337
}
327338

328339
impl MockSignature {
329-
/// Create a new mock sign data struct from the provided peer info, burn block height, chain id, and private key.
340+
/// Create a new mock sign data struct from the provided event burn block height, peer info, chain id, and private key.
341+
/// Note that peer burn block height and event burn block height may not be the same if the peer view is stale.
330342
pub fn new(
331-
peer_view: RPCPeerInfoData,
332-
burn_block_height: u64,
343+
event_burn_block_height: u64,
344+
peer_info: PeerInfo,
333345
chain_id: u32,
334346
stacks_private_key: &StacksPrivateKey,
335347
) -> Self {
336348
let mut sig = Self {
337349
signature: MessageSignature::empty(),
338-
sign_data: MockSignData::new(peer_view, burn_block_height, chain_id),
350+
sign_data: MockSignData {
351+
peer_info,
352+
event_burn_block_height,
353+
chain_id,
354+
},
339355
};
340356
sig.sign(stacks_private_key)
341357
.expect("Failed to sign MockSignature");
@@ -350,25 +366,39 @@ impl MockSignature {
350366
TupleData::from_data(vec![
351367
(
352368
"stacks-tip-consensus-hash".into(),
353-
Value::buff_from(self.sign_data.stacks_tip_consensus_hash.as_bytes().into())
354-
.unwrap(),
369+
Value::buff_from(
370+
self.sign_data
371+
.peer_info
372+
.stacks_tip_consensus_hash
373+
.as_bytes()
374+
.into(),
375+
)
376+
.unwrap(),
355377
),
356378
(
357379
"stacks-tip".into(),
358-
Value::buff_from(self.sign_data.stacks_tip.as_bytes().into()).unwrap(),
380+
Value::buff_from(self.sign_data.peer_info.stacks_tip.as_bytes().into())
381+
.unwrap(),
382+
),
383+
(
384+
"stacks-tip-height".into(),
385+
Value::UInt(self.sign_data.peer_info.stacks_tip_height.into()),
359386
),
360387
(
361388
"server-version".into(),
362-
Value::string_ascii_from_bytes(self.sign_data.server_version.clone().into())
363-
.unwrap(),
389+
Value::string_ascii_from_bytes(
390+
self.sign_data.peer_info.server_version.clone().into(),
391+
)
392+
.unwrap(),
364393
),
365394
(
366-
"burn-block-height".into(),
367-
Value::UInt(self.sign_data.burn_block_height.into()),
395+
"event-burn-block-height".into(),
396+
Value::UInt(self.sign_data.event_burn_block_height.into()),
368397
),
369398
(
370399
"pox-consensus".into(),
371-
Value::buff_from(self.sign_data.pox_consensus.as_bytes().into()).unwrap(),
400+
Value::buff_from(self.sign_data.peer_info.pox_consensus.as_bytes().into())
401+
.unwrap(),
372402
),
373403
])
374404
.expect("Error creating signature hash"),
@@ -822,23 +852,33 @@ mod test {
822852
assert_eq!(signer_message, deserialized_signer_message);
823853
}
824854

825-
fn random_mock_sign_data() -> MockSignData {
855+
fn random_peer_data() -> PeerInfo {
856+
let burn_block_height = thread_rng().next_u64();
826857
let stacks_tip_consensus_byte: u8 = thread_rng().gen();
827858
let stacks_tip_byte: u8 = thread_rng().gen();
859+
let stacks_tip_height = thread_rng().next_u64();
860+
let server_version = "0.0.0".to_string();
828861
let pox_consensus_byte: u8 = thread_rng().gen();
862+
PeerInfo {
863+
burn_block_height,
864+
stacks_tip_consensus_hash: ConsensusHash([stacks_tip_consensus_byte; 20]),
865+
stacks_tip: BlockHeaderHash([stacks_tip_byte; 32]),
866+
stacks_tip_height,
867+
server_version,
868+
pox_consensus: ConsensusHash([pox_consensus_byte; 20]),
869+
}
870+
}
871+
fn random_mock_sign_data() -> MockSignData {
829872
let chain_byte: u8 = thread_rng().gen_range(0..=1);
830873
let chain_id = if chain_byte == 1 {
831874
CHAIN_ID_TESTNET
832875
} else {
833876
CHAIN_ID_MAINNET
834877
};
878+
let peer_info = random_peer_data();
835879
MockSignData {
836-
stacks_tip_consensus_hash: ConsensusHash([stacks_tip_consensus_byte; 20]),
837-
stacks_tip: BlockHeaderHash([stacks_tip_byte; 32]),
838-
server_version: "0.0.0".to_string(),
839-
burn_block_height: thread_rng().next_u64(),
840-
peer_burn_block_height: thread_rng().next_u64(),
841-
pox_consensus: ConsensusHash([pox_consensus_byte; 20]),
880+
peer_info,
881+
event_burn_block_height: thread_rng().next_u64(),
842882
chain_id,
843883
}
844884
}
@@ -871,6 +911,15 @@ mod test {
871911
.expect("Failed to verify MockSignature"));
872912
}
873913

914+
#[test]
915+
fn serde_peer_data() {
916+
let peer_data = random_peer_data();
917+
let serialized_data = peer_data.serialize_to_vec();
918+
let deserialized_data = read_next::<PeerInfo, _>(&mut &serialized_data[..])
919+
.expect("Failed to deserialize PeerInfo");
920+
assert_eq!(peer_data, deserialized_data);
921+
}
922+
874923
#[test]
875924
fn serde_mock_signature() {
876925
let mock_signature = MockSignature {

stacks-signer/src/cli.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,9 @@ extern crate alloc;
4444
const GIT_BRANCH: Option<&'static str> = option_env!("GIT_BRANCH");
4545
const GIT_COMMIT: Option<&'static str> = option_env!("GIT_COMMIT");
4646
#[cfg(debug_assertions)]
47-
const BUILD_TYPE: &'static str = "debug";
47+
const BUILD_TYPE: &str = "debug";
4848
#[cfg(not(debug_assertions))]
49-
const BUILD_TYPE: &'static str = "release";
49+
const BUILD_TYPE: &str = "release";
5050

5151
lazy_static! {
5252
static ref VERSION_STRING: String = {

stacks-signer/src/client/stacks_client.rs

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@ use blockstack_lib::net::api::get_tenures_fork_info::{
3131
TenureForkingInfo, RPC_TENURE_FORKING_INFO_PATH,
3232
};
3333
use blockstack_lib::net::api::getaccount::AccountEntryResponse;
34-
use blockstack_lib::net::api::getinfo::RPCPeerInfoData;
3534
use blockstack_lib::net::api::getpoxinfo::RPCPoxInfoData;
3635
use blockstack_lib::net::api::getsortition::{SortitionInfo, RPC_SORTITION_INFO_PATH};
3736
use blockstack_lib::net::api::getstackers::GetStackersResponse;
@@ -43,6 +42,7 @@ use blockstack_lib::util_lib::boot::{boot_code_addr, boot_code_id};
4342
use clarity::util::hash::to_hex;
4443
use clarity::vm::types::{PrincipalData, QualifiedContractIdentifier};
4544
use clarity::vm::{ClarityName, ContractName, Value as ClarityValue};
45+
use libsigner::v0::messages::PeerInfo;
4646
use reqwest::header::AUTHORIZATION;
4747
use serde_json::json;
4848
use slog::{slog_debug, slog_warn};
@@ -463,7 +463,7 @@ impl StacksClient {
463463
}
464464

465465
/// Get the current peer info data from the stacks node
466-
pub fn get_peer_info(&self) -> Result<RPCPeerInfoData, ClientError> {
466+
pub fn get_peer_info(&self) -> Result<PeerInfo, ClientError> {
467467
debug!("Getting stacks node info...");
468468
let timer =
469469
crate::monitoring::new_rpc_call_timer(&self.core_info_path(), &self.http_origin);
@@ -478,7 +478,7 @@ impl StacksClient {
478478
if !response.status().is_success() {
479479
return Err(ClientError::RequestFailure(response.status()));
480480
}
481-
let peer_info_data = response.json::<RPCPeerInfoData>()?;
481+
let peer_info_data = response.json::<PeerInfo>()?;
482482
Ok(peer_info_data)
483483
}
484484

@@ -1387,7 +1387,18 @@ mod tests {
13871387
let (response, peer_info) = build_get_peer_info_response(None, None);
13881388
let h = spawn(move || mock.client.get_peer_info());
13891389
write_response(mock.server, response.as_bytes());
1390-
assert_eq!(h.join().unwrap().unwrap(), peer_info);
1390+
let reduced_peer_info = h.join().unwrap().unwrap();
1391+
assert_eq!(
1392+
reduced_peer_info.burn_block_height,
1393+
peer_info.burn_block_height
1394+
);
1395+
assert_eq!(reduced_peer_info.pox_consensus, peer_info.pox_consensus);
1396+
assert_eq!(
1397+
reduced_peer_info.stacks_tip_consensus_hash,
1398+
peer_info.stacks_tip_consensus_hash
1399+
);
1400+
assert_eq!(reduced_peer_info.stacks_tip, peer_info.stacks_tip);
1401+
assert_eq!(reduced_peer_info.server_version, peer_info.server_version);
13911402
}
13921403

13931404
#[test]

stacks-signer/src/v0/signer.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -484,7 +484,7 @@ impl Signer {
484484

485485
/// Send a mock signature to stackerdb to prove we are still alive
486486
fn mock_sign(&mut self, burn_block_height: u64, stacks_client: &StacksClient) {
487-
let Ok(peer_view) = stacks_client.get_peer_info() else {
487+
let Ok(peer_info) = stacks_client.get_peer_info() else {
488488
warn!("{self}: Failed to get peer info. Cannot mock sign.");
489489
return;
490490
};
@@ -494,15 +494,15 @@ impl Signer {
494494
CHAIN_ID_TESTNET
495495
};
496496
info!("Mock signing for burn block {burn_block_height:?}";
497-
"stacks_tip_consensus_hash" => ?peer_view.stacks_tip_consensus_hash.clone(),
498-
"stacks_tip" => ?peer_view.stacks_tip.clone(),
499-
"peer_burn_block_height" => peer_view.burn_block_height,
500-
"pox_consensus" => ?peer_view.pox_consensus.clone(),
501-
"server_version" => peer_view.server_version.clone(),
497+
"stacks_tip_consensus_hash" => ?peer_info.stacks_tip_consensus_hash.clone(),
498+
"stacks_tip" => ?peer_info.stacks_tip.clone(),
499+
"peer_burn_block_height" => peer_info.burn_block_height,
500+
"pox_consensus" => ?peer_info.pox_consensus.clone(),
501+
"server_version" => peer_info.server_version.clone(),
502502
"chain_id" => chain_id
503503
);
504504
let mock_signature =
505-
MockSignature::new(peer_view, burn_block_height, chain_id, &self.private_key);
505+
MockSignature::new(burn_block_height, peer_info, chain_id, &self.private_key);
506506
let message = SignerMessage::MockSignature(mock_signature);
507507
if let Err(e) = self
508508
.stackerdb

testnet/stacks-node/src/tests/signer/v0.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1663,7 +1663,8 @@ fn mock_sign_epoch_25() {
16631663
.expect("Failed to get message from stackerdb");
16641664
for message in messages {
16651665
if let SignerMessage::MockSignature(mock_signature) = message {
1666-
if mock_signature.sign_data.burn_block_height == current_burn_block_height {
1666+
if mock_signature.sign_data.event_burn_block_height == current_burn_block_height
1667+
{
16671668
if !mock_signatures.contains(&mock_signature) {
16681669
mock_signatures.push(mock_signature);
16691670
}

0 commit comments

Comments
 (0)