Skip to content

Commit e5dcecb

Browse files
authored
[fix] improvements to proposal handling (#690)
* [fix] improvements to proposal handling * fix harness * fix clippy
1 parent e2bc897 commit e5dcecb

File tree

9 files changed

+200
-86
lines changed

9 files changed

+200
-86
lines changed

dkg-gadget/src/constants.rs

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
// Constants for dkg-gadget
2+
3+
// ================= Common ======================== //
4+
pub const DKG_KEYGEN_PROTOCOL_NAME: &str = "/webb-tools/dkg/keygen/1";
5+
6+
pub const DKG_SIGNING_PROTOCOL_NAME: &str = "/webb-tools/dkg/signing/1";
7+
8+
// ================= Worker ========================== //
9+
pub mod worker {
10+
pub const ENGINE_ID: sp_runtime::ConsensusEngineId = *b"WDKG";
11+
12+
pub const STORAGE_SET_RETRY_NUM: usize = 5;
13+
14+
pub const MAX_SUBMISSION_DELAY: u32 = 3;
15+
16+
pub const MAX_KEYGEN_RETRIES: usize = 5;
17+
18+
/// How many blocks to keep the proposal hash in out local cache.
19+
pub const PROPOSAL_HASH_LIFETIME: u32 = 10;
20+
}
21+
22+
// ============= Signing Manager ======================= //
23+
24+
pub mod signing_manager {
25+
// the maximum number of tasks that the work manager tries to assign
26+
pub const MAX_RUNNING_TASKS: usize = 1;
27+
28+
// the maximum number of tasks that can be enqueued,
29+
// enqueued here implies not actively running but listening for messages
30+
pub const MAX_ENQUEUED_TASKS: usize = 20;
31+
32+
// How often to poll the jobs to check completion status
33+
pub const JOB_POLL_INTERVAL_IN_MILLISECONDS: u64 = 500;
34+
35+
// Number of signing sets to generate for every proposal
36+
pub const MAX_POTENTIAL_SIGNING_SETS_PER_PROPOSAL: u8 = 2;
37+
}
38+
39+
// ============= Networking ======================= //
40+
41+
pub mod network {
42+
/// Maximum number of known messages hashes to keep for a peer.
43+
pub const MAX_KNOWN_MESSAGES: usize = 4096;
44+
45+
/// Maximum allowed size for a DKG Signed Message notification.
46+
pub const MAX_MESSAGE_SIZE: u64 = 16 * 1024 * 1024;
47+
48+
/// Maximum number of duplicate messages that a single peer can send us.
49+
///
50+
/// This is to prevent a malicious peer from spamming us with messages.
51+
pub const MAX_DUPLICATED_MESSAGES_PER_PEER: usize = 8;
52+
}
53+
54+
// ============= Keygen Manager ======================= //
55+
56+
pub mod keygen_manager {
57+
/// only 1 task at a time may run for keygen
58+
pub const MAX_RUNNING_TASKS: usize = 1;
59+
/// There should never be any job enqueueing for keygen
60+
pub const MAX_ENQUEUED_TASKS: usize = 0;
61+
}

dkg-gadget/src/gossip_engine/network.rs

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
//! engine, and it is verified then it will be added to the Engine's internal stream of DKG
4141
//! messages, later the DKG Gadget will read this stream and process the DKG message.
4242
43+
pub use crate::constants::network::*;
4344
use crate::{debug_logger::DebugLogger, metrics::Metrics, worker::HasLatestHeader, DKGKeystore};
4445
use codec::{Decode, Encode};
4546
use dkg_primitives::types::{DKGError, SignedDKGMessage};
@@ -152,17 +153,6 @@ impl NetworkGossipEngineBuilder {
152153
}
153154
}
154155

155-
/// Maximum number of known messages hashes to keep for a peer.
156-
const MAX_KNOWN_MESSAGES: usize = 4096;
157-
158-
/// Maximum allowed size for a DKG Signed Message notification.
159-
const MAX_MESSAGE_SIZE: u64 = 16 * 1024 * 1024;
160-
161-
/// Maximum number of duplicate messages that a single peer can send us.
162-
///
163-
/// This is to prevent a malicious peer from spamming us with messages.
164-
const MAX_DUPLICATED_MESSAGES_PER_PEER: usize = 8;
165-
166156
#[allow(unused)]
167157
mod rep {
168158
use sc_peerset::ReputationChange as Rep;

dkg-gadget/src/keygen_manager/mod.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
use crate::{
44
async_protocols::{remote::AsyncProtocolRemote, KeygenPartyId, KeygenRound},
5+
constants::keygen_manager::*,
56
dkg_modules::KeygenProtocolSetupParameters,
67
gossip_engine::GossipEngineIface,
78
signing_manager::work_manager::{JobMetadata, PollMethod, WorkManager},
@@ -68,11 +69,6 @@ pub enum KeygenState {
6869
Failed { session_id: u64 },
6970
}
7071

71-
/// only 1 task at a time may run for keygen
72-
const MAX_RUNNING_TASKS: usize = 1;
73-
/// There should never be any job enqueueing for keygen
74-
const MAX_ENQUEUED_TASKS: usize = 0;
75-
7672
impl<B, BE, C, GE> KeygenManager<B, BE, C, GE>
7773
where
7874
B: Block,

dkg-gadget/src/lib.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,17 +43,16 @@ pub mod worker;
4343

4444
pub mod async_protocols;
4545
pub use dkg_logging::debug_logger;
46+
pub mod constants;
4647
pub mod dkg_modules;
4748
pub mod gossip_messages;
4849
pub mod storage;
4950

51+
pub use constants::{DKG_KEYGEN_PROTOCOL_NAME, DKG_SIGNING_PROTOCOL_NAME};
5052
pub use debug_logger::RoundsEventType;
5153
use gossip_engine::NetworkGossipEngineBuilder;
5254
pub use keystore::DKGKeystore;
5355

54-
pub const DKG_KEYGEN_PROTOCOL_NAME: &str = "/webb-tools/dkg/keygen/1";
55-
pub const DKG_SIGNING_PROTOCOL_NAME: &str = "/webb-tools/dkg/signing/1";
56-
5756
/// Returns the configuration value to put in
5857
/// [`sc_network::config::NetworkConfiguration::extra_sets`].
5958
pub fn dkg_peers_set_config(

dkg-gadget/src/signing_manager/mod.rs

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use dkg_primitives::{
88
use self::work_manager::WorkManager;
99
use crate::{
1010
async_protocols::KeygenPartyId,
11+
constants::signing_manager::*,
1112
dkg_modules::SigningProtocolSetupParameters,
1213
gossip_engine::GossipEngineIface,
1314
metric_inc,
@@ -21,7 +22,6 @@ use dkg_runtime_primitives::crypto::Public;
2122
use sp_api::HeaderT;
2223
use std::sync::atomic::{AtomicBool, Ordering};
2324
use webb_proposals::TypedChainId;
24-
2525
/// For balancing the amount of work done by each node
2626
pub mod work_manager;
2727

@@ -51,13 +51,6 @@ impl<B: Block, BE, C, GE> Clone for SigningManager<B, BE, C, GE> {
5151
}
5252
}
5353

54-
// the maximum number of tasks that the work manager tries to assign
55-
const MAX_RUNNING_TASKS: usize = 4;
56-
const MAX_ENQUEUED_TASKS: usize = 20;
57-
// How often to poll the jobs to check completion status
58-
const JOB_POLL_INTERVAL_IN_MILLISECONDS: u64 = 500;
59-
pub const MAX_POTENTIAL_SIGNING_SETS_PER_PROPOSAL: u8 = 2;
60-
6154
impl<B, BE, C, GE> SigningManager<B, BE, C, GE>
6255
where
6356
B: Block,

dkg-gadget/src/worker.rs

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ use dkg_runtime_primitives::{
5353
GENESIS_AUTHORITY_SET_ID,
5454
};
5555

56+
pub use crate::constants::worker::*;
5657
use crate::{
5758
async_protocols::{remote::AsyncProtocolRemote, AsyncProtocolParameters},
5859
dkg_modules::DKGModules,
@@ -70,17 +71,6 @@ use crate::{
7071
Client,
7172
};
7273

73-
pub const ENGINE_ID: sp_runtime::ConsensusEngineId = *b"WDKG";
74-
75-
pub const STORAGE_SET_RETRY_NUM: usize = 5;
76-
77-
pub const MAX_SUBMISSION_DELAY: u32 = 3;
78-
79-
pub const MAX_KEYGEN_RETRIES: usize = 5;
80-
81-
/// How many blocks to keep the proposal hash in out local cache.
82-
pub const PROPOSAL_HASH_LIFETIME: u32 = 10;
83-
8474
pub type Shared<T> = Arc<RwLock<T>>;
8575

8676
pub struct WorkerParams<B, BE, C, GE>

dkg-test-orchestrator/src/main.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
9393
);
9494

9595
let max_signing_sets_per_proposal =
96-
dkg_gadget::signing_manager::MAX_POTENTIAL_SIGNING_SETS_PER_PROPOSAL;
96+
dkg_gadget::constants::signing_manager::MAX_POTENTIAL_SIGNING_SETS_PER_PROPOSAL;
9797

9898
// first, spawn the orchestrator/mock-blockchain
9999
let orchestrator_task = MockBlockchain::new(

pallets/dkg-proposal-handler/src/functions.rs

Lines changed: 95 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use super::*;
22
use dkg_runtime_primitives::handlers::decode_proposals::ProposalIdentifier;
3-
use sp_runtime::traits::{CheckedAdd, One};
3+
use sp_runtime::traits::{CheckedAdd, CheckedSub, One};
44

55
impl<T: Config> Pallet<T> {
66
// *** API methods ***
@@ -272,4 +272,98 @@ impl<T: Config> Pallet<T> {
272272
pub fn signed_proposals_len() -> usize {
273273
SignedProposals::<T>::iter_keys().count()
274274
}
275+
276+
pub fn on_idle_create_proposal_batches(mut remaining_weight: Weight) -> Weight {
277+
// fetch all unsigned proposals
278+
let unsigned_proposals: Vec<_> = UnsignedProposals::<T>::iter().collect();
279+
let unsigned_proposals_len = unsigned_proposals.len() as u64;
280+
remaining_weight =
281+
remaining_weight.saturating_sub(T::DbWeight::get().reads(unsigned_proposals_len));
282+
283+
for (typed_chain_id, unsigned_proposals) in unsigned_proposals {
284+
remaining_weight =
285+
remaining_weight.saturating_sub(T::DbWeight::get().reads_writes(1, 3));
286+
287+
if remaining_weight.is_zero() {
288+
break
289+
}
290+
291+
let batch_id_res = Self::generate_next_batch_id();
292+
293+
if batch_id_res.is_err() {
294+
log::debug!(
295+
target: "runtime::dkg_proposal_handler",
296+
"on_idle: Cannot generate next batch ID: {:?}",
297+
batch_id_res,
298+
);
299+
return remaining_weight
300+
}
301+
302+
let batch_id = batch_id_res.expect("checked above");
303+
304+
// create new proposal batch
305+
let proposal_batch = StoredUnsignedProposalBatchOf::<T> {
306+
batch_id,
307+
proposals: unsigned_proposals,
308+
timestamp: <frame_system::Pallet<T>>::block_number(),
309+
};
310+
// push the batch to unsigned proposal queue
311+
UnsignedProposalQueue::<T>::insert(typed_chain_id, batch_id, proposal_batch);
312+
313+
// remove the batch from the unsigned proposal list
314+
UnsignedProposals::<T>::remove(typed_chain_id);
315+
}
316+
317+
remaining_weight
318+
}
319+
320+
pub fn on_idle_remove_expired_batches(
321+
now: T::BlockNumber,
322+
mut remaining_weight: Weight,
323+
) -> Weight {
324+
use dkg_runtime_primitives::DKGPayloadKey::RefreshProposal;
325+
326+
// early return if we dont have enough weight to perform a read
327+
if remaining_weight.is_zero() {
328+
return remaining_weight
329+
}
330+
331+
// fetch all unsigned proposals
332+
let unsigned_proposals: Vec<_> = UnsignedProposalQueue::<T>::iter().collect();
333+
let unsigned_proposals_len = unsigned_proposals.len() as u64;
334+
remaining_weight =
335+
remaining_weight.saturating_sub(T::DbWeight::get().reads(unsigned_proposals_len));
336+
337+
// filter out proposals to delete
338+
let unsigned_proposal_past_expiry = unsigned_proposals.into_iter().filter(
339+
|(_, _, StoredUnsignedProposalBatchOf::<T> { proposals, timestamp, .. })| {
340+
let key = proposals.first().expect("cannot be empty").key;
341+
342+
// Skip expiration for keygen related proposals
343+
if let RefreshProposal(_) = key {
344+
return false
345+
}
346+
347+
let time_passed = now.checked_sub(timestamp).unwrap_or_default();
348+
time_passed > T::UnsignedProposalExpiry::get()
349+
},
350+
);
351+
352+
// remove unsigned proposal until we run out of weight
353+
for expired_proposal in unsigned_proposal_past_expiry {
354+
remaining_weight =
355+
remaining_weight.saturating_sub(T::DbWeight::get().writes(One::one()));
356+
357+
if remaining_weight.is_zero() {
358+
break
359+
}
360+
Self::deposit_event(Event::<T>::ProposalBatchExpired {
361+
target_chain: expired_proposal.0,
362+
batch_id: expired_proposal.1,
363+
});
364+
UnsignedProposalQueue::<T>::remove(expired_proposal.0, expired_proposal.1);
365+
}
366+
367+
remaining_weight
368+
}
275369
}

0 commit comments

Comments
 (0)