Skip to content

Commit 9d4cc3a

Browse files
authored
Merge pull request #5962 from jferrant/feat/signer-state-conflict-resolution-strategies
Feat/signer state conflict resolution strategies
2 parents 50e304a + aab7784 commit 9d4cc3a

File tree

10 files changed

+1251
-44
lines changed

10 files changed

+1251
-44
lines changed

libsigner/src/events.rs

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -192,8 +192,14 @@ pub enum SignerEvent<T: SignerEventTrait> {
192192
/// The `Vec<T>` will contain any signer messages made by the miner.
193193
MinerMessages(Vec<T>),
194194
/// The signer messages for other signers and miners to observe
195-
/// The u32 is the signer set to which the message belongs (either 0 or 1)
196-
SignerMessages(u32, Vec<T>),
195+
SignerMessages {
196+
/// The signer set to which the message belongs (either 0 or 1)
197+
signer_set: u32,
198+
/// Each message of type `T` is paired with the `StacksPublicKey` of the slot from which it was retreived
199+
messages: Vec<(StacksPublicKey, T)>,
200+
/// the time at which this event was received by the signer's event processor
201+
received_time: SystemTime,
202+
},
197203
/// A new block proposal validation response from the node
198204
BlockValidationResponse(BlockValidateResponse),
199205
/// Status endpoint request
@@ -518,6 +524,7 @@ impl<T: SignerEventTrait> TryFrom<StackerDBChunksEvent> for SignerEvent<T> {
518524
type Error = EventError;
519525

520526
fn try_from(event: StackerDBChunksEvent) -> Result<Self, Self::Error> {
527+
let received_time = SystemTime::now();
521528
let signer_event = if event.contract_id.name.as_str() == MINERS_NAME
522529
&& event.contract_id.is_boot()
523530
{
@@ -536,12 +543,21 @@ impl<T: SignerEventTrait> TryFrom<StackerDBChunksEvent> for SignerEvent<T> {
536543
return Err(EventError::UnrecognizedStackerDBContract(event.contract_id));
537544
};
538545
// signer-XXX-YYY boot contract
539-
let signer_messages: Vec<T> = event
546+
let messages: Vec<(StacksPublicKey, T)> = event
540547
.modified_slots
541548
.iter()
542-
.filter_map(|chunk| read_next::<T, _>(&mut &chunk.data[..]).ok())
549+
.filter_map(|chunk| {
550+
Some((
551+
chunk.recover_pk().ok()?,
552+
read_next::<T, _>(&mut &chunk.data[..]).ok()?,
553+
))
554+
})
543555
.collect();
544-
SignerEvent::SignerMessages(signer_set, signer_messages)
556+
SignerEvent::SignerMessages {
557+
signer_set,
558+
messages,
559+
received_time,
560+
}
545561
} else {
546562
return Err(EventError::UnrecognizedStackerDBContract(event.contract_id));
547563
};

libsigner/src/tests/mod.rs

Lines changed: 39 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,15 @@ use std::fmt::Debug;
2020
use std::io::{Read, Write};
2121
use std::net::{SocketAddr, TcpStream, ToSocketAddrs};
2222
use std::sync::mpsc::{channel, Receiver, Sender};
23-
use std::time::Duration;
23+
use std::time::{Duration, SystemTime};
2424
use std::{mem, thread};
2525

2626
use blockstack_lib::chainstate::nakamoto::signer_set::NakamotoSigners;
2727
use blockstack_lib::chainstate::nakamoto::{NakamotoBlock, NakamotoBlockHeader};
2828
use blockstack_lib::chainstate::stacks::boot::SIGNERS_NAME;
2929
use blockstack_lib::chainstate::stacks::events::StackerDBChunksEvent;
3030
use blockstack_lib::util_lib::boot::boot_code_id;
31-
use clarity::types::chainstate::{ConsensusHash, StacksBlockId, TrieHash};
31+
use clarity::types::chainstate::{ConsensusHash, StacksBlockId, StacksPublicKey, TrieHash};
3232
use clarity::util::hash::Sha512Trunc256Sum;
3333
use clarity::util::secp256k1::MessageSignature;
3434
use clarity::vm::types::QualifiedContractIdentifier;
@@ -142,6 +142,13 @@ fn test_simple_signer() {
142142
chunks.push(chunk_event);
143143
}
144144

145+
chunks.sort_by(|ev1, ev2| {
146+
ev1.modified_slots[0]
147+
.slot_id
148+
.partial_cmp(&ev2.modified_slots[0].slot_id)
149+
.unwrap()
150+
});
151+
145152
let thread_chunks = chunks.clone();
146153

147154
// simulate a node that's trying to push data
@@ -177,23 +184,44 @@ fn test_simple_signer() {
177184
sleep_ms(5000);
178185
let accepted_events = running_signer.stop().unwrap();
179186

180-
chunks.sort_by(|ev1, ev2| {
181-
ev1.modified_slots[0]
182-
.slot_id
183-
.partial_cmp(&ev2.modified_slots[0].slot_id)
184-
.unwrap()
185-
});
186-
187187
let sent_events: Vec<SignerEvent<SignerMessage>> = chunks
188188
.iter()
189189
.map(|chunk| {
190190
let msg = chunk.modified_slots[0].data.clone();
191+
let pubkey = chunk.modified_slots[0]
192+
.recover_pk()
193+
.expect("Faield to recover public key of slot");
191194
let signer_message = read_next::<SignerMessage, _>(&mut &msg[..]).unwrap();
192-
SignerEvent::SignerMessages(0, vec![signer_message])
195+
SignerEvent::SignerMessages {
196+
signer_set: 0,
197+
messages: vec![(pubkey, signer_message)],
198+
received_time: SystemTime::now(),
199+
}
193200
})
194201
.collect();
195202

196-
assert_eq!(sent_events, accepted_events);
203+
for (sent_event, accepted_event) in sent_events.iter().zip(accepted_events.iter()) {
204+
let SignerEvent::SignerMessages {
205+
signer_set,
206+
messages,
207+
received_time,
208+
} = sent_event
209+
else {
210+
panic!("BUG: should not have sent anything but a signer message");
211+
};
212+
let SignerEvent::SignerMessages {
213+
signer_set: accepted_signer_set,
214+
messages: accepted_messages,
215+
received_time: accepted_time,
216+
} = accepted_event
217+
else {
218+
panic!("BUG: should not have accepted anything but a signer message");
219+
};
220+
221+
assert_eq!(signer_set, accepted_signer_set);
222+
assert_eq!(messages, accepted_messages);
223+
assert_ne!(received_time, accepted_time);
224+
}
197225
mock_stacks_node.join().unwrap();
198226
}
199227

libsigner/src/v0/messages.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
//! and the `SignerMessage` enum.
2525
2626
use std::fmt::{Debug, Display};
27+
use std::hash::{Hash, Hasher};
2728
use std::io::{Read, Write};
2829
use std::marker::PhantomData;
2930
use std::net::{SocketAddr, TcpListener, TcpStream};
@@ -573,7 +574,7 @@ pub enum StateMachineUpdateContent {
573574
}
574575

575576
/// Message for update the Signer State infos
576-
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
577+
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, Eq, Hash)]
577578
pub enum StateMachineUpdateMinerState {
578579
/// There is an active miner
579580
ActiveMiner {

0 commit comments

Comments
 (0)