Skip to main content

bobcat_features/
lib.rs

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        // We need the first slot of the word to be the length:
22        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}