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