1use crate::*;
21use sp_consensus_sassafras::{vrf::VrfSignature, EphemeralPublic, EpochConfiguration};
22
23use frame_benchmarking::v2::*;
24use frame_support::traits::Hooks;
25use frame_system::RawOrigin;
26
27const LOG_TARGET: &str = "sassafras::benchmark";
28
29const TICKETS_DATA: &[u8] = include_bytes!("data/25_tickets_100_auths.bin");
30
31fn make_dummy_vrf_signature() -> VrfSignature {
32 let buf = [
35 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
36 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
37 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
38 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
39 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xb5, 0x5f, 0x8e, 0xc7, 0x68, 0xf5, 0x05, 0x3f, 0xa9,
40 0x18, 0xca, 0x07, 0x13, 0xc7, 0x4b, 0xa3, 0x9a, 0x97, 0xd3, 0x76, 0x8f, 0x0c, 0xbf, 0x2e,
41 0xd4, 0xf9, 0x3a, 0xae, 0xc1, 0x96, 0x2a, 0x64, 0x80,
42 ];
43 VrfSignature::decode(&mut &buf[..]).unwrap()
44}
45
46#[benchmarks]
47mod benchmarks {
48 use super::*;
49
50 #[benchmark]
54 fn on_initialize() {
55 let block_num = BlockNumberFor::<T>::from(0u32);
56
57 let slot_claim = SlotClaim {
58 authority_idx: 0,
59 slot: Default::default(),
60 vrf_signature: make_dummy_vrf_signature(),
61 ticket_claim: None,
62 };
63 frame_system::Pallet::<T>::deposit_log((&slot_claim).into());
64
65 #[block]
69 {
70 Pallet::<T>::on_initialize(block_num);
73 Pallet::<T>::on_finalize(block_num)
74 }
75 }
76
77 #[benchmark]
92 fn enact_epoch_change(x: Linear<1, 100>, y: Linear<1000, 5000>) {
93 let authorities_count = x as usize;
94 let epoch_length = y as u32;
95 let redundancy_factor = 2;
96
97 let unsorted_tickets_count = epoch_length * redundancy_factor;
98
99 let mut meta = TicketsMetadata { unsorted_tickets_count, tickets_count: [0, 0] };
100 let config = EpochConfiguration { redundancy_factor, attempts_number: 32 };
101
102 let mut raw_data = TICKETS_DATA;
104 let (authorities, _): (Vec<AuthorityId>, Vec<TicketEnvelope>) =
105 Decode::decode(&mut raw_data).expect("Failed to decode tickets buffer");
106 let next_authorities: Vec<_> = authorities[..authorities_count].to_vec();
107 let next_authorities = WeakBoundedVec::force_from(next_authorities, None);
108 NextAuthorities::<T>::set(next_authorities);
109
110 (0..meta.unsorted_tickets_count)
112 .collect::<Vec<_>>()
113 .chunks(SEGMENT_MAX_SIZE as usize)
114 .enumerate()
115 .for_each(|(segment_id, chunk)| {
116 let segment = chunk
117 .iter()
118 .map(|i| {
119 let id_bytes = crate::hashing::blake2_128(&i.to_le_bytes());
120 TicketId::from_le_bytes(id_bytes)
121 })
122 .collect::<Vec<_>>();
123 UnsortedSegments::<T>::insert(
124 segment_id as u32,
125 BoundedVec::truncate_from(segment),
126 );
127 });
128
129 NextEpochConfig::<T>::set(Some(config));
131 PendingEpochConfigChange::<T>::set(Some(config));
132
133 let epoch_tag = EpochIndex::<T>::get() & 1;
135 meta.tickets_count[epoch_tag as usize] = epoch_length;
136 (0..epoch_length).for_each(|i| {
137 let id_bytes = crate::hashing::blake2_128(&i.to_le_bytes());
138 let id = TicketId::from_le_bytes(id_bytes);
139 TicketsIds::<T>::insert((epoch_tag as u8, i), id);
140 let body = TicketBody {
141 attempt_idx: i,
142 erased_public: EphemeralPublic::from([i as u8; 32]),
143 revealed_public: EphemeralPublic::from([i as u8; 32]),
144 };
145 TicketsData::<T>::set(id, Some(body));
146 });
147
148 TicketsMeta::<T>::set(meta);
149
150 #[block]
151 {
152 Pallet::<T>::should_end_epoch(BlockNumberFor::<T>::from(3u32));
153 let next_authorities = Pallet::<T>::next_authorities();
154 Pallet::<T>::enact_epoch_change(Default::default(), next_authorities);
156 }
157 }
158
159 #[benchmark]
160 fn submit_tickets(x: Linear<1, 25>) {
161 let tickets_count = x as usize;
162
163 let mut raw_data = TICKETS_DATA;
164 let (authorities, tickets): (Vec<AuthorityId>, Vec<TicketEnvelope>) =
165 Decode::decode(&mut raw_data).expect("Failed to decode tickets buffer");
166
167 log::debug!(target: LOG_TARGET, "PreBuiltTickets: {} tickets, {} authorities", tickets.len(), authorities.len());
168
169 NextRandomness::<T>::set([0; 32]);
172
173 Pallet::<T>::update_ring_verifier(&authorities);
174
175 let next_config = EpochConfiguration { attempts_number: 1, redundancy_factor: u32::MAX };
177 NextEpochConfig::<T>::set(Some(next_config));
178
179 let authorities = WeakBoundedVec::force_from(authorities, None);
181 NextAuthorities::<T>::set(authorities);
182
183 let tickets = tickets[..tickets_count].to_vec();
184 let tickets = BoundedVec::truncate_from(tickets);
185
186 log::debug!(target: LOG_TARGET, "Submitting {} tickets", tickets_count);
187
188 #[extrinsic_call]
189 submit_tickets(RawOrigin::None, tickets);
190 }
191
192 #[benchmark]
193 fn plan_config_change() {
194 let config = EpochConfiguration { redundancy_factor: 1, attempts_number: 10 };
195
196 #[extrinsic_call]
197 plan_config_change(RawOrigin::Root, config);
198 }
199
200 #[benchmark]
202 fn update_ring_verifier(x: Linear<1, 100>) {
203 let authorities_count = x as usize;
204
205 let mut raw_data = TICKETS_DATA;
206 let (authorities, _): (Vec<AuthorityId>, Vec<TicketEnvelope>) =
207 Decode::decode(&mut raw_data).expect("Failed to decode tickets buffer");
208 let authorities: Vec<_> = authorities[..authorities_count].to_vec();
209
210 #[block]
211 {
212 Pallet::<T>::update_ring_verifier(&authorities);
213 }
214 }
215
216 #[benchmark]
221 fn load_ring_context() {
222 #[block]
223 {
224 let _ring_ctx = RingContext::<T>::get().unwrap();
225 }
226 }
227
228 #[benchmark]
230 fn sort_segments(x: Linear<1, 100>) {
231 let segments_count = x as u32;
232 let tickets_count = segments_count * SEGMENT_MAX_SIZE;
233
234 let tickets: Vec<_> = (0..tickets_count)
236 .map(|i| {
237 let body = TicketBody {
238 attempt_idx: i,
239 erased_public: EphemeralPublic::from([i as u8; 32]),
240 revealed_public: EphemeralPublic::from([i as u8; 32]),
241 };
242 let id_bytes = crate::hashing::blake2_128(&i.to_le_bytes());
243 let id = TicketId::from_le_bytes(id_bytes);
244 (id, body)
245 })
246 .collect();
247
248 for (chunk_id, chunk) in tickets.chunks(SEGMENT_MAX_SIZE as usize).enumerate() {
249 let segment: Vec<TicketId> = chunk
250 .iter()
251 .map(|(id, body)| {
252 TicketsData::<T>::set(id, Some(body.clone()));
253 *id
254 })
255 .collect();
256 let segment = BoundedVec::truncate_from(segment);
257 UnsortedSegments::<T>::insert(chunk_id as u32, segment);
258 }
259
260 let mut meta = TicketsMeta::<T>::get();
262 meta.unsorted_tickets_count = tickets_count;
263 TicketsMeta::<T>::set(meta);
264
265 log::debug!(target: LOG_TARGET, "Before sort: {:?}", meta);
266 #[block]
267 {
268 Pallet::<T>::sort_segments(u32::MAX, 0, &mut meta);
269 }
270 log::debug!(target: LOG_TARGET, "After sort: {:?}", meta);
271 }
272}