@@ -17,6 +17,7 @@ pub enum RpcFilterType {
1717 DataSize ( u64 ) ,
1818 Memcmp ( Memcmp ) ,
1919 TokenAccountState ,
20+ ValueCmp ( ValueCmp ) ,
2021}
2122
2223impl RpcFilterType {
@@ -57,6 +58,7 @@ impl RpcFilterType {
5758 }
5859 }
5960 RpcFilterType :: TokenAccountState => Ok ( ( ) ) ,
61+ RpcFilterType :: ValueCmp ( _) => Ok ( ( ) ) ,
6062 }
6163 }
6264
@@ -69,6 +71,9 @@ impl RpcFilterType {
6971 RpcFilterType :: DataSize ( size) => account. data ( ) . len ( ) as u64 == * size,
7072 RpcFilterType :: Memcmp ( compare) => compare. bytes_match ( account. data ( ) ) ,
7173 RpcFilterType :: TokenAccountState => Account :: valid_account_data ( account. data ( ) ) ,
74+ RpcFilterType :: ValueCmp ( compare) => {
75+ compare. values_match ( account. data ( ) ) . unwrap_or ( false )
76+ }
7277 }
7378 }
7479}
@@ -81,6 +86,8 @@ pub enum RpcFilterError {
8186 Base58DecodeError ( #[ from] bs58:: decode:: Error ) ,
8287 #[ error( "base64 decode error" ) ]
8388 Base64DecodeError ( #[ from] base64:: DecodeError ) ,
89+ #[ error( "invalid ValueCmp filter" ) ]
90+ InvalidValueCmp ,
8491}
8592
8693#[ derive( Debug , Clone , PartialEq , Eq , Hash , Serialize ) ]
@@ -222,6 +229,178 @@ impl Memcmp {
222229 }
223230}
224231
232+ #[ derive( Debug , Clone , PartialEq , Eq , Hash , Serialize , Deserialize ) ]
233+ pub struct ValueCmp {
234+ pub left : Operand ,
235+ comparator : Comparator ,
236+ pub right : Operand ,
237+ }
238+
239+ #[ derive( Debug , Clone , PartialEq , Eq , Hash , Serialize , Deserialize ) ]
240+ pub enum Operand {
241+ Mem {
242+ offset : usize ,
243+ value_type : ValueType ,
244+ } ,
245+ Constant ( String ) ,
246+ }
247+
248+ #[ derive( Debug , Clone , PartialEq , Eq , Hash , Serialize , Deserialize ) ]
249+ pub enum ValueType {
250+ U8 ,
251+ U16 ,
252+ U32 ,
253+ U64 ,
254+ U128 ,
255+ }
256+
257+ enum WrappedValueType {
258+ U8 ( u8 ) ,
259+ U16 ( u16 ) ,
260+ U32 ( u32 ) ,
261+ U64 ( u64 ) ,
262+ U128 ( u128 ) ,
263+ }
264+
265+ impl ValueCmp {
266+ fn parse_mem_into_value_type (
267+ o : & Operand ,
268+ data : & [ u8 ] ,
269+ ) -> Result < WrappedValueType , RpcFilterError > {
270+ match o {
271+ Operand :: Mem { offset, value_type } => match value_type {
272+ ValueType :: U8 => {
273+ if * offset >= data. len ( ) {
274+ return Err ( RpcFilterError :: InvalidValueCmp ) ;
275+ }
276+
277+ Ok ( WrappedValueType :: U8 ( data[ * offset] ) )
278+ }
279+ ValueType :: U16 => {
280+ if * offset + 1 >= data. len ( ) {
281+ return Err ( RpcFilterError :: InvalidValueCmp ) ;
282+ }
283+ Ok ( WrappedValueType :: U16 ( u16:: from_le_bytes (
284+ data[ * offset..* offset + 2 ] . try_into ( ) . unwrap ( ) ,
285+ ) ) )
286+ }
287+ ValueType :: U32 => {
288+ if * offset + 3 >= data. len ( ) {
289+ return Err ( RpcFilterError :: InvalidValueCmp ) ;
290+ }
291+ Ok ( WrappedValueType :: U32 ( u32:: from_le_bytes (
292+ data[ * offset..* offset + 4 ] . try_into ( ) . unwrap ( ) ,
293+ ) ) )
294+ }
295+ ValueType :: U64 => {
296+ if * offset + 7 >= data. len ( ) {
297+ return Err ( RpcFilterError :: InvalidValueCmp ) ;
298+ }
299+ Ok ( WrappedValueType :: U64 ( u64:: from_le_bytes (
300+ data[ * offset..* offset + 8 ] . try_into ( ) . unwrap ( ) ,
301+ ) ) )
302+ }
303+ ValueType :: U128 => {
304+ if * offset + 15 >= data. len ( ) {
305+ return Err ( RpcFilterError :: InvalidValueCmp ) ;
306+ }
307+ Ok ( WrappedValueType :: U128 ( u128:: from_le_bytes (
308+ data[ * offset..* offset + 16 ] . try_into ( ) . unwrap ( ) ,
309+ ) ) )
310+ }
311+ } ,
312+ _ => Err ( RpcFilterError :: InvalidValueCmp ) ,
313+ }
314+ }
315+
316+ pub fn values_match ( & self , data : & [ u8 ] ) -> Result < bool , RpcFilterError > {
317+ match ( & self . left , & self . right ) {
318+ ( left @ Operand :: Mem { .. } , right @ Operand :: Mem { .. } ) => {
319+ let left = Self :: parse_mem_into_value_type ( left, data) ?;
320+ let right = Self :: parse_mem_into_value_type ( right, data) ?;
321+
322+ match ( left, right) {
323+ ( WrappedValueType :: U8 ( left) , WrappedValueType :: U8 ( right) ) => {
324+ Ok ( self . comparator . compare ( left, right) )
325+ }
326+ ( WrappedValueType :: U16 ( left) , WrappedValueType :: U16 ( right) ) => {
327+ Ok ( self . comparator . compare ( left, right) )
328+ }
329+ ( WrappedValueType :: U32 ( left) , WrappedValueType :: U32 ( right) ) => {
330+ Ok ( self . comparator . compare ( left, right) )
331+ }
332+ ( WrappedValueType :: U64 ( left) , WrappedValueType :: U64 ( right) ) => {
333+ Ok ( self . comparator . compare ( left, right) )
334+ }
335+ ( WrappedValueType :: U128 ( left) , WrappedValueType :: U128 ( right) ) => {
336+ Ok ( self . comparator . compare ( left, right) )
337+ }
338+ _ => Err ( RpcFilterError :: InvalidValueCmp ) ,
339+ }
340+ }
341+ ( left @ Operand :: Mem { .. } , Operand :: Constant ( constant) ) => {
342+ match Self :: parse_mem_into_value_type ( left, data) ? {
343+ WrappedValueType :: U8 ( left) => {
344+ let right = constant
345+ . parse :: < u8 > ( )
346+ . map_err ( |_| RpcFilterError :: InvalidValueCmp ) ?;
347+ Ok ( self . comparator . compare ( left, right) )
348+ }
349+ WrappedValueType :: U16 ( left) => {
350+ let right = constant
351+ . parse :: < u16 > ( )
352+ . map_err ( |_| RpcFilterError :: InvalidValueCmp ) ?;
353+ Ok ( self . comparator . compare ( left, right) )
354+ }
355+ WrappedValueType :: U32 ( left) => {
356+ let right = constant
357+ . parse :: < u32 > ( )
358+ . map_err ( |_| RpcFilterError :: InvalidValueCmp ) ?;
359+ Ok ( self . comparator . compare ( left, right) )
360+ }
361+ WrappedValueType :: U64 ( left) => {
362+ let right = constant
363+ . parse :: < u64 > ( )
364+ . map_err ( |_| RpcFilterError :: InvalidValueCmp ) ?;
365+ Ok ( self . comparator . compare ( left, right) )
366+ }
367+ WrappedValueType :: U128 ( left) => {
368+ let right = constant
369+ . parse :: < u128 > ( )
370+ . map_err ( |_| RpcFilterError :: InvalidValueCmp ) ?;
371+ Ok ( self . comparator . compare ( left, right) )
372+ }
373+ }
374+ }
375+ _ => Err ( RpcFilterError :: InvalidValueCmp ) ,
376+ }
377+ }
378+ }
379+
380+ #[ derive( Debug , Clone , PartialEq , Eq , Hash , Serialize , Deserialize ) ]
381+ pub enum Comparator {
382+ Eq = 0 ,
383+ Ne ,
384+ Gt ,
385+ Ge ,
386+ Lt ,
387+ Le ,
388+ }
389+
390+ impl Comparator {
391+ // write a generic function to compare two values
392+ pub fn compare < T : PartialOrd > ( & self , left : T , right : T ) -> bool {
393+ match self {
394+ Comparator :: Eq => left == right,
395+ Comparator :: Ne => left != right,
396+ Comparator :: Gt => left > right,
397+ Comparator :: Ge => left >= right,
398+ Comparator :: Lt => left < right,
399+ Comparator :: Le => left <= right,
400+ }
401+ }
402+ }
403+
225404#[ cfg( test) ]
226405mod tests {
227406 use {
@@ -455,4 +634,56 @@ mod tests {
455634 serde_json:: from_str:: <Value >( BYTES_FILTER_WITH_ENCODING ) . unwrap( )
456635 ) ;
457636 }
637+
638+ #[ test]
639+ fn test_values_match ( ) {
640+ // test all the ValueCmp cases
641+ let data = vec ! [ 1 , 2 , 3 , 4 , 5 ] ;
642+
643+ let filter = ValueCmp {
644+ left : Operand :: Mem {
645+ offset : 1 ,
646+ value_type : ValueType :: U8 ,
647+ } ,
648+ comparator : Comparator :: Eq ,
649+ right : Operand :: Constant ( "2" . to_string ( ) ) ,
650+ } ;
651+
652+ assert ! ( ValueCmp {
653+ left: Operand :: Mem {
654+ offset: 1 ,
655+ value_type: ValueType :: U8
656+ } ,
657+ comparator: Comparator :: Eq ,
658+ right: Operand :: Constant ( "2" . to_string( ) )
659+ }
660+ . values_match( & data)
661+ . unwrap( ) ) ;
662+
663+ assert ! ( ValueCmp {
664+ left: Operand :: Mem {
665+ offset: 1 ,
666+ value_type: ValueType :: U8
667+ } ,
668+ comparator: Comparator :: Lt ,
669+ right: Operand :: Constant ( "3" . to_string( ) )
670+ }
671+ . values_match( & data)
672+ . unwrap( ) ) ;
673+
674+ assert ! ( ValueCmp {
675+ left: Operand :: Mem {
676+ offset: 0 ,
677+ value_type: ValueType :: U32
678+ } ,
679+ comparator: Comparator :: Eq ,
680+ right: Operand :: Constant ( "67305985" . to_string( ) )
681+ }
682+ . values_match( & data)
683+ . unwrap( ) ) ;
684+
685+ // serialize
686+ let s = serde_json:: to_string ( & filter) . unwrap ( ) ;
687+ println ! ( "{}" , s) ;
688+ }
458689}
0 commit comments