1- use crate :: v2:: trie:: Trie ;
1+ use crate :: v1:: sparse_mpt:: { DeletionError as DeletionErrorV1 , DiffTrie } ;
2+ use crate :: v2:: trie:: { DeletionError as DeletionErrorV2 , Trie } ;
3+
4+ use alloy_primitives:: { hex, keccak256, Bytes , FixedBytes } ;
25use quickcheck:: { quickcheck, Arbitrary , Gen } ;
36use std:: collections:: HashMap ;
47
5- // The maximum key size. keeping it relatively
6- // small increases the chance of multiple
7- // operations being executed against the same
8- // key, which will tease out more bugs.
9- const KEY_SPACE : u8 = 16 ;
10-
118#[ derive( Clone , Debug ) ]
129enum Op {
13- Insert ( Vec < u8 > , Vec < u8 > ) ,
14- Get ( Vec < u8 > ) ,
10+ Insert ( FixedKey , Vec < u8 > ) ,
11+ Delete ( FixedKey ) ,
1512}
1613
14+ // helper trait to extend `choose` with exception handling
1715trait ChooseNonempty {
1816 fn one_of < ' a , T > ( & ' a mut self , entries : & ' a [ T ] ) -> & ' a T ;
1917}
@@ -24,46 +22,120 @@ impl ChooseNonempty for Gen {
2422 }
2523}
2624
27- // Arbitrary lets you create randomized instances
28- // of types that you're interested in testing
29- // properties with. QuickCheck will look for
30- // this trait for things that are the arguments
31- // to properties that it is testing.
25+ #[ derive( Clone , Copy , Debug , PartialEq , Eq , Hash ) ]
26+ struct FixedKey ( FixedBytes < 32 > ) ;
27+
28+ impl FixedKey {
29+ fn as_slice ( & self ) -> & [ u8 ; 32 ] {
30+ & self . 0
31+ }
32+
33+ fn from_string ( s : & str ) -> Self {
34+ Self ( keccak256 ( "a" ) )
35+ }
36+
37+ fn from_bytes ( bytes : [ u8 ; 32 ] ) -> Self {
38+ Self ( FixedBytes :: new ( bytes) )
39+ }
40+
41+ fn into_bytes ( self ) -> Bytes {
42+ Bytes :: from ( self . 0 )
43+ }
44+ }
45+
46+ impl From < Bytes > for FixedKey {
47+ fn from ( bytes : Bytes ) -> FixedKey {
48+ let fbytes = FixedBytes :: from_slice ( bytes. as_ref ( ) ) ;
49+ FixedKey ( fbytes)
50+ }
51+ }
52+
53+ // We chose a small number of keys, to make sure our error cases handle key collisions,
54+ // as well as shared prefixes, properties that would be very unlikely for random keys
55+ impl Arbitrary for FixedKey {
56+ fn arbitrary ( g : & mut Gen ) -> Self {
57+ let keys = [
58+ FixedKey :: from_bytes ( hex ! (
59+ "0000000000000000000000000000000000000000000000000000000000000000"
60+ ) ) ,
61+ FixedKey :: from_bytes ( hex ! (
62+ "0000000000000000000000000000000000000000000000000000000000000001"
63+ ) ) ,
64+ FixedKey :: from_bytes ( hex ! (
65+ "0000000000000000000000000000001000000000000000000000000000000001"
66+ ) ) ,
67+ FixedKey :: from_string ( "0" ) ,
68+ FixedKey :: from_string ( "1" ) ,
69+ FixedKey :: from_string ( "2" ) ,
70+ FixedKey :: from_string ( "3" ) ,
71+ FixedKey :: from_string ( "4" ) ,
72+ FixedKey :: from_string ( "5" ) ,
73+ FixedKey :: from_string ( "6" ) ,
74+ FixedKey :: from_string ( "7" ) ,
75+ ] ;
76+ * g. one_of ( & keys)
77+ }
78+ }
79+
3280impl Arbitrary for Op {
3381 fn arbitrary ( g : & mut Gen ) -> Self {
3482 // pick a random key to perform an operation on
35- let key = g
36- . one_of ( & [ "key00" , "key01" , "odd" , "key010" ] )
37- . as_bytes ( )
38- . to_owned ( ) ;
83+ let key = FixedKey :: arbitrary ( g) ;
3984
4085 if * g. one_of ( & [ true , false ] ) {
4186 Op :: Insert ( key, "value" . into ( ) )
4287 } else {
43- Op :: Get ( key)
88+ Op :: Delete ( key)
89+ }
90+ }
91+ }
92+
93+ quickcheck ! {
94+ fn model_test_v1_map( ops: Vec <Op >) -> bool {
95+ let mut model = HashMap :: new( ) ;
96+ let mut implementation = DiffTrie :: new_empty( ) ;
97+
98+ for op in ops {
99+ match op {
100+ Op :: Insert ( key, value) => {
101+ implementation. insert( key. into_bytes( ) , Bytes :: from( value. clone( ) ) ) . unwrap( ) ;
102+ model. insert( key, value) ;
103+ }
104+ Op :: Delete ( key) => {
105+ match ( implementation. delete( key. into_bytes( ) ) , model. remove( & key) ) {
106+ ( Err ( DeletionErrorV1 :: KeyNotFound ) , None ) => ( ) ,
107+ ( Err ( err) , _) => panic!( "Implementation error {err:?}" ) ,
108+ ( Ok ( _) , Some ( _) ) => ( ) ,
109+ ( Ok ( returned) , None ) => panic!( "Implementation returned {returned:?} on delete" ) ,
110+ }
111+ }
112+ }
44113 }
114+ true
45115 }
46116}
47117
48118quickcheck ! {
49- fn model_test_v2 ( ops: Vec <Op >) -> bool {
119+ fn model_test_v2_map ( ops: Vec <Op >) -> bool {
50120 let mut model = HashMap :: new( ) ;
51121 let mut implementation = Trie :: new_empty( ) ;
52122
53123 for op in ops {
54124 match op {
55125 Op :: Insert ( k, v) => {
56- implementation. insert( k. as_slice( ) , v. as_slice( ) ) ;
126+ implementation. insert( k. as_slice( ) , v. as_slice( ) ) . unwrap ( ) ;
57127 model. insert( k, v) ;
58128 }
59- Op :: Get ( k) => {
60- // if implementation.get(&k) != model.get(&k).map(AsRef::as_ref) {
61- // return false;
62- // }
129+ Op :: Delete ( k) => {
130+ match ( implementation. delete( k. as_slice( ) ) , model. remove( & k) ) {
131+ ( Err ( DeletionErrorV2 :: KeyNotFound ) , None ) => ( ) ,
132+ ( Err ( e) , _) => panic!( "Implementation error {e:?}" ) ,
133+ ( Ok ( _) , Some ( _) ) => ( ) ,
134+ ( Ok ( a) , None ) => panic!( "Implementation returned {a:?} on delete" ) ,
135+ }
63136 }
64137 }
65138 }
66-
67139 true
68140 }
69141}
0 commit comments