1#![cfg_attr(not(feature = "std"), no_std)]
2
3pub use bobcat_storage::{
4 const_keccak256_two_off_curve, keccak256, storage_load, storage_store,
5 U,
6};
7
8pub use bobcat_entry::block_timestamp;
9
10pub use bobcat_interfaces::superposition::make_fn_features;
11
12pub use bobcat_call::static_call_word;
13
14pub use paste::paste;
15
16#[macro_export]
17macro_rules! BOBCAT_FEATURES {
18 ($($feature_name:ident),* $(,)?) => {
19 pub const _FEATURE_COUNT: u8 = 0 $(+ { let _ = stringify!($feature_name); 1 })*;
20
21 const _: [(); 0] = [(); (_FEATURE_COUNT < 255) as usize - 1];
23
24 $(
25 $crate::paste! {
26 pub const [<FEATURE_ID_ $feature_name:upper>]: $crate::U =
27 $crate::const_keccak256_two_off_curve(
28 b"bobcat.features.",
29 stringify!($feature_name).as_bytes()
30 );
31
32 #[allow(unused)]
33 pub fn [<feature_is_ $feature_name:lower>]() -> bool {
34 $crate::storage_load(&[<FEATURE_ID_ $feature_name:upper>]).is_some()
35 }
36
37 pub fn [<feature_set_ $feature_name:lower>](v: bool) {
38 $crate::storage_store(
39 &[<FEATURE_ID_ $feature_name:upper>],
40 &$crate::U::from(v)
41 )
42 }
43
44 #[allow(unused)]
45 macro_rules! [<FEATURE_IF_ $feature_name:upper>] {
46 ($on_block:block else $off_block:block) => {
47 if [<feature_is_ $feature_name:lower>]() {
48 $on_block
49 } else {
50 $off_block
51 }
52 };
53 }
54 }
55 )*
56
57 #[allow(unused)]
58 pub fn feature_pack() -> $crate::U {
59 let mut r = $crate::U::default();
60 let mut i = 1;
61 $(
62 $crate::paste! {
63 if [<feature_is_ $feature_name:lower>]() {
64 let byte_index = 31 - (i / 8);
65 let bit_position = i % 8;
66 r[byte_index] |= 1 << bit_position;
67 }
68 i += 1;
69 }
70 )*
71 let _ = i;
72 r
73 }
74 };
75}
76
77#[macro_export]
78macro_rules! FEATURE_PICK {
79 ($($feature_name:ident($weight:expr)),* $(,)?) => {
80 {
81 let choice = u16::from($crate::keccak256(&$crate::block_timestamp().to_be_bytes())) % 100;
82 let mut cum = 0u16;
83 let mut found = false;
84 $(
85 if !found {
86 if choice < cum + $weight {
87 $crate::paste! {
88 [<feature_set_ $feature_name:lower>](true);
89 }
90 found = true;
91 } else {
92 cum += $weight;
93 }
94 }
95 )*
96 let _ = cum;
97 let _ = found;
98 }
99 };
100}
101
102#[macro_export]
103macro_rules! FEATURE_MATCH {
104 ($($feature:ident => $expr:expr),+ , * => $default:expr $(,)?) => {
105 $crate::paste! {
106 $(
107 if [<feature_is_ $feature:lower>]() {
108 $expr
109 } else
110 )+
111 {
112 $default
113 }
114 }
115 };
116 ($($feature:ident => $expr:expr),+ , _ => $default:expr $(,)?) => {
117 FEATURE_MATCH! {
118 $($feature => $expr,)+
119 * => $default
120 }
121 };
122 ($($feature:ident => $expr:expr),+ $(,)?) => {
123 FEATURE_MATCH! {
124 $($feature => $expr,)+
125 * => ()
126 }
127 };
128}
129
130#[macro_export]
131macro_rules! FEATURE_COPY {
132 ($address:expr, $($feature_name:ident),* $(,)?) => {
133 {
134 let (rc, r) = $crate::static_call_word(
135 $address,
136 &$crate::make_fn_features(),
137 u64::MAX,
138 0
139 );
140 assert!(rc, "features revert");
141 let remote_count = r[0];
142 const COUNT: u8 = 0 $(+ { let _ = stringify!($feature_name); 1 })*;
143 assert_eq!(
144 remote_count, COUNT,
145 "features {remote_count} != {COUNT}"
146 );
147 let mut i = 1;
148 $(
149 $crate::paste! {
150 let byte_index = 31 - (i / 8);
151 let bit_position = i % 8;
152 $crate::storage_store(
153 &$crate::const_keccak256_two_off_curve(
154 b"bobcat.features.",
155 stringify!($feature_name).as_bytes()
156 ),
157 &$crate::U::from((r[byte_index] & (1 << bit_position)) != 0)
158 );
159 i += 1;
160 }
161 )*
162 let _ = i;
163 }
164 };
165}
166
167#[macro_export]
168macro_rules! FEATURE_COPY_NON_ZEROES {
169 ($address:expr, $($feature_name:ident),* $(,)?) => {
170 {
171 let (rc, r) = $crate::static_call_word(
172 $address,
173 &$crate::make_fn_features(),
174 u64::MAX,
175 0
176 );
177 assert!(rc, "features revert");
178 let remote_count = r[0];
179 const COUNT: u8 = 0 $(+ { let _ = stringify!($feature_name); 1 })*;
180 assert_eq!(
181 remote_count, COUNT,
182 "features {remote_count} != {COUNT}"
183 );
184 let mut i = 1;
185 $(
186 $crate::paste! {
187 let byte_index = 31 - (i / 8);
188 let bit_position = i % 8;
189 let setting = (r[byte_index] & (1 << bit_position)) != 0;
190 if setting {
191 $crate::storage_store(
192 &$crate::const_keccak256_two_off_curve(
193 b"bobcat.features.",
194 stringify!($feature_name).as_bytes()
195 ),
196 &$crate::U::from(setting)
197 );
198 }
199 i += 1;
200 }
201 )*
202 let _ = i;
203 }
204 };
205}
206
207#[macro_export]
208macro_rules! FEATURE_PACK {
209 ($($feature_name:ident),* $(,)?) => {
210 {
211 let mut r = $crate::U::default();
212 #[allow(unused_assignments)]
213 let mut i = 1;
214 const COUNT: u8 = 0 $(+ { let _ = stringify!($feature_name); 1 })*;
215 r[0] = COUNT;
216 $(
217 $crate::paste! {
218 if [<feature_is_ $feature_name:lower>]() {
219 let byte_index = 31 - (i / 8);
220 let bit_position = i % 8;
221 r[byte_index] |= 1 << bit_position;
222 }
223 i += 1;
224 }
225 )*
226 let _ = i;
227 r
228 }
229 };
230}
231
232#[cfg(all(test, feature = "std"))]
233mod test_1 {
234 use bobcat_entry::{host::set_block_timestamp, U};
235
236 use bobcat_host::storage_clear;
237
238 BOBCAT_FEATURES!(test123, swag);
239
240 #[test]
241 fn test_features_1() {
242 assert_eq!(2, _FEATURE_COUNT);
243 feature_set_test123(true);
244 assert!(FEATURE_IF_TEST123!({ true } else { false }));
245 feature_set_test123(false);
246 assert!(!feature_is_test123());
247 let mut test123_count = 0;
248 let mut swag_count = 0;
249 let mut else_count = 0;
250 for i in 0..100_000 {
251 set_block_timestamp(i);
252 FEATURE_PICK!(test123(40), swag(30));
253 FEATURE_MATCH! {
254 test123 => test123_count += 1,
255 swag => swag_count += 1,
256 * => else_count += 1
257 };
258 feature_set_test123(false);
259 feature_set_swag(false);
260 }
261 assert!(40_000 >= test123_count || 39_900 <= test123_count);
262 assert!(30_000 >= swag_count || 29_900 <= swag_count);
263 assert!(50_000 >= else_count || 49_900 <= else_count);
264 feature_set_test123(true);
265 feature_set_swag(true);
266 assert_eq!(U::from(6u32), feature_pack());
267 feature_set_swag(false);
268 assert_eq!(U::from(2u32), feature_pack());
269 storage_clear();
270 }
271}
272
273#[cfg(all(test, feature = "std", feature = "alloy-enabled"))]
274mod test_2 {
275 use std::str::FromStr;
276
277 use bobcat_entry::U;
278
279 use bobcat_host::storage_clear;
280
281 BOBCAT_FEATURES!(
282 F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14, F15, F16, F17, F18, F19, F20,
283 F21, F22, F23, F24, F25, F26, F27, F28, F29, F30, F31, F32, F33, F34, F35, F36, F37, F38,
284 F39, F40, F41, F42, F43, F44, F45, F46, F47, F48, F49, F50, F51, F52, F53, F54, F55, F56,
285 F57, F58, F59, F60, F61, F62, F63, F64, F65, F66, F67, F68, F69, F70, F71, F72, F73, F74,
286 F75, F76, F77, F78, F79, F80, F81, F82, F83, F84, F85, F86, F87, F88, F89, F90, F91, F92,
287 F93, F94, F95, F96, F97, F98, F99, F100, F101, F102, F103, F104, F105, F106, F107, F108,
288 F109, F110, F111, F112, F113, F114, F115, F116, F117, F118, F119, F120, F121, F122, F123,
289 F124, F125, F126, F127, F128, F129, F130, F131, F132, F133, F134, F135, F136, F137, F138,
290 F139, F140, F141, F142, F143, F144, F145, F146, F147, F148, F149, F150, F151, F152, F153,
291 F154, F155, F156, F157, F158, F159, F160, F161, F162, F163, F164, F165, F166, F167, F168,
292 F169, F170, F171, F172, F173, F174, F175, F176, F177, F178, F179, F180, F181, F182, F183,
293 F184, F185, F186, F187, F188, F189, F190, F191, F192, F193, F194, F195, F196, F197, F198,
294 F199, F200, F201, F202, F203, F204, F205, F206, F207, F208, F209, F210, F211, F212, F213,
295 F214, F215, F216, F217, F218, F219, F220, F221, F222, F223, F224, F225, F226, F227, F228,
296 F229, F230, F231, F232, F233, F234, F235, F236, F237, F238, F239, F240, F241, F242, F243,
297 F244, F245, F246, F247, F248, F249, F250, F251, F252, F253, F254,
298 );
299
300 #[test]
301 fn test() {
302 feature_set_f1(true);
303 feature_set_f2(true);
304 feature_set_f3(true);
305 feature_set_f4(true);
306 feature_set_f5(true);
307 feature_set_f6(true);
308 feature_set_f7(true);
309 feature_set_f8(true);
310 feature_set_f9(true);
311 feature_set_f10(true);
312 feature_set_f11(true);
313 feature_set_f12(true);
314 feature_set_f13(true);
315 feature_set_f14(true);
316 feature_set_f15(true);
317 feature_set_f16(true);
318 feature_set_f17(true);
319 feature_set_f18(true);
320 feature_set_f19(true);
321 feature_set_f20(true);
322 feature_set_f21(true);
323 feature_set_f22(true);
324 feature_set_f23(true);
325 feature_set_f24(true);
326 feature_set_f25(true);
327 feature_set_f26(true);
328 feature_set_f27(true);
329 feature_set_f28(true);
330 feature_set_f29(true);
331 feature_set_f30(true);
332 feature_set_f31(true);
333 feature_set_f32(true);
334 feature_set_f33(true);
335 feature_set_f34(true);
336 feature_set_f35(true);
337 feature_set_f36(true);
338 feature_set_f37(true);
339 feature_set_f38(true);
340 feature_set_f39(true);
341 feature_set_f40(true);
342 feature_set_f41(true);
343 feature_set_f42(true);
344 feature_set_f43(true);
345 feature_set_f44(true);
346 feature_set_f45(true);
347 feature_set_f46(true);
348 feature_set_f47(true);
349 feature_set_f48(true);
350 feature_set_f49(true);
351 feature_set_f50(true);
352 feature_set_f51(true);
353 feature_set_f52(true);
354 feature_set_f53(true);
355 feature_set_f54(true);
356 feature_set_f55(true);
357 feature_set_f56(true);
358 feature_set_f57(true);
359 feature_set_f58(true);
360 feature_set_f59(true);
361 feature_set_f60(true);
362 feature_set_f61(true);
363 feature_set_f62(true);
364 feature_set_f63(true);
365 feature_set_f64(true);
366 feature_set_f65(true);
367 feature_set_f66(true);
368 feature_set_f67(true);
369 feature_set_f68(true);
370 feature_set_f69(true);
371 feature_set_f70(true);
372 feature_set_f71(true);
373 feature_set_f72(true);
374 feature_set_f73(true);
375 feature_set_f74(true);
376 feature_set_f75(true);
377 feature_set_f76(true);
378 feature_set_f77(true);
379 feature_set_f78(true);
380 feature_set_f79(true);
381 feature_set_f80(true);
382 feature_set_f81(true);
383 feature_set_f82(true);
384 feature_set_f83(true);
385 feature_set_f84(true);
386 feature_set_f85(true);
387 feature_set_f86(true);
388 feature_set_f87(true);
389 feature_set_f88(true);
390 feature_set_f89(true);
391 feature_set_f90(true);
392 feature_set_f91(true);
393 feature_set_f92(true);
394 feature_set_f93(true);
395 feature_set_f94(true);
396 feature_set_f95(true);
397 feature_set_f96(true);
398 feature_set_f97(true);
399 feature_set_f98(true);
400 feature_set_f99(true);
401 feature_set_f100(true);
402 feature_set_f101(true);
403 feature_set_f102(true);
404 feature_set_f103(true);
405 feature_set_f104(true);
406 feature_set_f105(true);
407 feature_set_f106(true);
408 feature_set_f107(true);
409 feature_set_f108(true);
410 feature_set_f109(true);
411 feature_set_f110(true);
412 feature_set_f111(true);
413 feature_set_f112(true);
414 feature_set_f113(true);
415 feature_set_f114(true);
416 feature_set_f115(true);
417 feature_set_f116(true);
418 feature_set_f117(true);
419 feature_set_f118(true);
420 feature_set_f119(true);
421 feature_set_f120(true);
422 feature_set_f121(true);
423 feature_set_f122(true);
424 feature_set_f123(true);
425 feature_set_f124(true);
426 feature_set_f125(true);
427 feature_set_f126(true);
428 feature_set_f127(true);
429 feature_set_f128(true);
430 feature_set_f129(true);
431 feature_set_f130(true);
432 feature_set_f131(true);
433 feature_set_f132(true);
434 feature_set_f133(true);
435 feature_set_f134(true);
436 feature_set_f135(true);
437 feature_set_f136(true);
438 feature_set_f137(true);
439 feature_set_f138(true);
440 feature_set_f139(true);
441 feature_set_f140(true);
442 feature_set_f141(true);
443 feature_set_f142(true);
444 feature_set_f143(true);
445 feature_set_f144(true);
446 feature_set_f145(true);
447 feature_set_f146(true);
448 feature_set_f147(true);
449 feature_set_f148(true);
450 feature_set_f149(true);
451 feature_set_f150(true);
452 feature_set_f151(true);
453 feature_set_f152(true);
454 feature_set_f153(true);
455 feature_set_f154(true);
456 feature_set_f155(true);
457 feature_set_f156(true);
458 feature_set_f157(true);
459 feature_set_f158(true);
460 feature_set_f159(true);
461 feature_set_f160(true);
462 feature_set_f161(true);
463 feature_set_f162(true);
464 feature_set_f163(true);
465 feature_set_f164(true);
466 feature_set_f165(true);
467 feature_set_f166(true);
468 feature_set_f167(true);
469 feature_set_f168(true);
470 feature_set_f169(true);
471 feature_set_f170(true);
472 feature_set_f171(true);
473 feature_set_f172(true);
474 feature_set_f173(true);
475 feature_set_f174(true);
476 feature_set_f175(true);
477 feature_set_f176(true);
478 feature_set_f177(true);
479 feature_set_f178(true);
480 feature_set_f179(true);
481 feature_set_f180(true);
482 feature_set_f181(true);
483 feature_set_f182(true);
484 feature_set_f183(true);
485 feature_set_f184(true);
486 feature_set_f185(true);
487 feature_set_f186(true);
488 feature_set_f187(true);
489 feature_set_f188(true);
490 feature_set_f189(true);
491 feature_set_f190(true);
492 feature_set_f191(true);
493 feature_set_f192(true);
494 feature_set_f193(true);
495 feature_set_f194(true);
496 feature_set_f195(true);
497 feature_set_f196(true);
498 feature_set_f197(true);
499 feature_set_f198(true);
500 feature_set_f199(true);
501 feature_set_f200(true);
502 feature_set_f201(true);
503 feature_set_f202(true);
504 feature_set_f203(true);
505 feature_set_f204(true);
506 feature_set_f205(true);
507 feature_set_f206(true);
508 feature_set_f207(true);
509 feature_set_f208(true);
510 feature_set_f209(true);
511 feature_set_f210(true);
512 feature_set_f211(true);
513 feature_set_f212(true);
514 feature_set_f213(true);
515 feature_set_f214(true);
516 feature_set_f215(true);
517 feature_set_f216(true);
518 feature_set_f217(true);
519 feature_set_f218(true);
520 feature_set_f219(true);
521 feature_set_f220(true);
522 feature_set_f221(true);
523 feature_set_f222(true);
524 feature_set_f223(true);
525 feature_set_f224(true);
526 feature_set_f225(true);
527 feature_set_f226(true);
528 feature_set_f227(true);
529 feature_set_f228(true);
530 feature_set_f229(true);
531 feature_set_f230(true);
532 feature_set_f231(true);
533 feature_set_f232(true);
534 feature_set_f233(true);
535 feature_set_f234(true);
536 feature_set_f235(true);
537 feature_set_f236(true);
538 feature_set_f237(true);
539 feature_set_f238(true);
540 feature_set_f239(true);
541 feature_set_f240(true);
542 feature_set_f241(true);
543 feature_set_f242(true);
544 feature_set_f243(true);
545 feature_set_f244(true);
546 feature_set_f245(true);
547 feature_set_f246(true);
548 feature_set_f247(true);
549 feature_set_f248(true);
550 feature_set_f249(true);
551 feature_set_f250(true);
552 feature_set_f251(true);
553 feature_set_f252(true);
554 feature_set_f253(true);
555 feature_set_f254(true);
556 assert_eq!(
557 U::from_str(
558 "57896044618658097711785492504343953926634992332820282019728792003956564819966"
559 )
560 .unwrap(),
561 feature_pack()
562 );
563 storage_clear();
564 }
565}