1
- use thiserror:: Error ;
1
+ #![ allow( deprecated) ]
2
+ use { std:: borrow:: Cow , thiserror:: Error } ;
3
+
4
+ const MAX_DATA_SIZE : usize = 128 ;
5
+ const MAX_DATA_BASE58_SIZE : usize = 175 ;
6
+ const MAX_DATA_BASE64_SIZE : usize = 172 ;
2
7
3
8
#[ derive( Debug , Clone , PartialEq , Eq , Hash , Serialize , Deserialize ) ]
4
9
#[ serde( rename_all = "camelCase" ) ]
@@ -15,15 +20,50 @@ impl RpcFilterType {
15
20
let encoding = compare. encoding . as_ref ( ) . unwrap_or ( & MemcmpEncoding :: Binary ) ;
16
21
match encoding {
17
22
MemcmpEncoding :: Binary => {
18
- let MemcmpEncodedBytes :: Binary ( bytes) = & compare. bytes ;
19
-
20
- if bytes. len ( ) > 128 {
21
- Err ( RpcFilterError :: Base58DataTooLarge )
22
- } else {
23
- bs58:: decode ( & bytes)
24
- . into_vec ( )
25
- . map ( |_| ( ) )
26
- . map_err ( |e| e. into ( ) )
23
+ use MemcmpEncodedBytes :: * ;
24
+ match & compare. bytes {
25
+ Binary ( bytes) if bytes. len ( ) > MAX_DATA_BASE58_SIZE => {
26
+ Err ( RpcFilterError :: Base58DataTooLarge )
27
+ }
28
+ Base58 ( bytes) if bytes. len ( ) > MAX_DATA_BASE58_SIZE => {
29
+ Err ( RpcFilterError :: DataTooLarge )
30
+ }
31
+ Base64 ( bytes) if bytes. len ( ) > MAX_DATA_BASE64_SIZE => {
32
+ Err ( RpcFilterError :: DataTooLarge )
33
+ }
34
+ Bytes ( bytes) if bytes. len ( ) > MAX_DATA_SIZE => {
35
+ Err ( RpcFilterError :: DataTooLarge )
36
+ }
37
+ _ => Ok ( ( ) ) ,
38
+ } ?;
39
+ match & compare. bytes {
40
+ Binary ( bytes) => {
41
+ let bytes = bs58:: decode ( & bytes)
42
+ . into_vec ( )
43
+ . map_err ( RpcFilterError :: DecodeError ) ?;
44
+ if bytes. len ( ) > MAX_DATA_SIZE {
45
+ Err ( RpcFilterError :: Base58DataTooLarge )
46
+ } else {
47
+ Ok ( ( ) )
48
+ }
49
+ }
50
+ Base58 ( bytes) => {
51
+ let bytes = bs58:: decode ( & bytes) . into_vec ( ) ?;
52
+ if bytes. len ( ) > MAX_DATA_SIZE {
53
+ Err ( RpcFilterError :: DataTooLarge )
54
+ } else {
55
+ Ok ( ( ) )
56
+ }
57
+ }
58
+ Base64 ( bytes) => {
59
+ let bytes = base64:: decode ( & bytes) ?;
60
+ if bytes. len ( ) > MAX_DATA_SIZE {
61
+ Err ( RpcFilterError :: DataTooLarge )
62
+ } else {
63
+ Ok ( ( ) )
64
+ }
65
+ }
66
+ Bytes ( _) => Ok ( ( ) ) ,
27
67
}
28
68
}
29
69
}
@@ -34,10 +74,24 @@ impl RpcFilterType {
34
74
35
75
#[ derive( Error , PartialEq , Debug ) ]
36
76
pub enum RpcFilterError {
37
- #[ error( "bs58 decode error" ) ]
38
- DecodeError ( #[ from] bs58:: decode:: Error ) ,
77
+ #[ error( "encoded binary data should be less than 129 bytes" ) ]
78
+ DataTooLarge ,
79
+ #[ deprecated(
80
+ since = "1.9.0" ,
81
+ note = "Error for MemcmpEncodedBytes::Binary which is deprecated"
82
+ ) ]
39
83
#[ error( "encoded binary (base 58) data should be less than 129 bytes" ) ]
40
84
Base58DataTooLarge ,
85
+ #[ deprecated(
86
+ since = "1.9.0" ,
87
+ note = "Error for MemcmpEncodedBytes::Binary which is deprecated"
88
+ ) ]
89
+ #[ error( "bs58 decode error" ) ]
90
+ DecodeError ( bs58:: decode:: Error ) ,
91
+ #[ error( "base58 decode error" ) ]
92
+ Base58DecodeError ( #[ from] bs58:: decode:: Error ) ,
93
+ #[ error( "base64 decode error" ) ]
94
+ Base64DecodeError ( #[ from] base64:: DecodeError ) ,
41
95
}
42
96
43
97
#[ derive( Debug , Clone , PartialEq , Eq , Hash , Serialize , Deserialize ) ]
@@ -49,7 +103,14 @@ pub enum MemcmpEncoding {
49
103
#[ derive( Debug , Clone , PartialEq , Eq , Hash , Serialize , Deserialize ) ]
50
104
#[ serde( rename_all = "camelCase" , untagged) ]
51
105
pub enum MemcmpEncodedBytes {
106
+ #[ deprecated(
107
+ since = "1.9.0" ,
108
+ note = "Please use MemcmpEncodedBytes::Base58 instead"
109
+ ) ]
52
110
Binary ( String ) ,
111
+ Base58 ( String ) ,
112
+ Base64 ( String ) ,
113
+ Bytes ( Vec < u8 > ) ,
53
114
}
54
115
55
116
#[ derive( Debug , Clone , PartialEq , Eq , Hash , Serialize , Deserialize ) ]
@@ -63,14 +124,18 @@ pub struct Memcmp {
63
124
}
64
125
65
126
impl Memcmp {
66
- pub fn bytes_match ( & self , data : & [ u8 ] ) -> bool {
127
+ pub fn bytes ( & self ) -> Option < Cow < Vec < u8 > > > {
128
+ use MemcmpEncodedBytes :: * ;
67
129
match & self . bytes {
68
- MemcmpEncodedBytes :: Binary ( bytes) => {
69
- let bytes = bs58:: decode ( bytes) . into_vec ( ) ;
70
- if bytes. is_err ( ) {
71
- return false ;
72
- }
73
- let bytes = bytes. unwrap ( ) ;
130
+ Binary ( bytes) | Base58 ( bytes) => bs58:: decode ( bytes) . into_vec ( ) . ok ( ) . map ( Cow :: Owned ) ,
131
+ Base64 ( bytes) => base64:: decode ( bytes) . ok ( ) . map ( Cow :: Owned ) ,
132
+ Bytes ( bytes) => Some ( Cow :: Borrowed ( bytes) ) ,
133
+ }
134
+ }
135
+
136
+ pub fn bytes_match ( & self , data : & [ u8 ] ) -> bool {
137
+ match self . bytes ( ) {
138
+ Some ( bytes) => {
74
139
if self . offset > data. len ( ) {
75
140
return false ;
76
141
}
@@ -79,6 +144,7 @@ impl Memcmp {
79
144
}
80
145
data[ self . offset ..self . offset + bytes. len ( ) ] == bytes[ ..]
81
146
}
147
+ None => false ,
82
148
}
83
149
}
84
150
}
@@ -87,62 +153,71 @@ impl Memcmp {
87
153
mod tests {
88
154
use super :: * ;
89
155
156
+ #[ test]
157
+ fn test_worst_case_encoded_tx_goldens ( ) {
158
+ let ff_data = vec ! [ 0xffu8 ; MAX_DATA_SIZE ] ;
159
+ let data58 = bs58:: encode ( & ff_data) . into_string ( ) ;
160
+ assert_eq ! ( data58. len( ) , MAX_DATA_BASE58_SIZE ) ;
161
+ let data64 = base64:: encode ( & ff_data) ;
162
+ assert_eq ! ( data64. len( ) , MAX_DATA_BASE64_SIZE ) ;
163
+ }
164
+
90
165
#[ test]
91
166
fn test_bytes_match ( ) {
92
167
let data = vec ! [ 1 , 2 , 3 , 4 , 5 ] ;
93
168
94
169
// Exact match of data succeeds
95
170
assert ! ( Memcmp {
96
171
offset: 0 ,
97
- bytes: MemcmpEncodedBytes :: Binary ( bs58:: encode( vec![ 1 , 2 , 3 , 4 , 5 ] ) . into_string( ) ) ,
172
+ bytes: MemcmpEncodedBytes :: Base58 ( bs58:: encode( vec![ 1 , 2 , 3 , 4 , 5 ] ) . into_string( ) ) ,
98
173
encoding: None ,
99
174
}
100
175
. bytes_match( & data) ) ;
101
176
102
177
// Partial match of data succeeds
103
178
assert ! ( Memcmp {
104
179
offset: 0 ,
105
- bytes: MemcmpEncodedBytes :: Binary ( bs58:: encode( vec![ 1 , 2 ] ) . into_string( ) ) ,
180
+ bytes: MemcmpEncodedBytes :: Base58 ( bs58:: encode( vec![ 1 , 2 ] ) . into_string( ) ) ,
106
181
encoding: None ,
107
182
}
108
183
. bytes_match( & data) ) ;
109
184
110
185
// Offset partial match of data succeeds
111
186
assert ! ( Memcmp {
112
187
offset: 2 ,
113
- bytes: MemcmpEncodedBytes :: Binary ( bs58:: encode( vec![ 3 , 4 ] ) . into_string( ) ) ,
188
+ bytes: MemcmpEncodedBytes :: Base58 ( bs58:: encode( vec![ 3 , 4 ] ) . into_string( ) ) ,
114
189
encoding: None ,
115
190
}
116
191
. bytes_match( & data) ) ;
117
192
118
193
// Incorrect partial match of data fails
119
194
assert ! ( !Memcmp {
120
195
offset: 0 ,
121
- bytes: MemcmpEncodedBytes :: Binary ( bs58:: encode( vec![ 2 ] ) . into_string( ) ) ,
196
+ bytes: MemcmpEncodedBytes :: Base58 ( bs58:: encode( vec![ 2 ] ) . into_string( ) ) ,
122
197
encoding: None ,
123
198
}
124
199
. bytes_match( & data) ) ;
125
200
126
201
// Bytes overrun data fails
127
202
assert ! ( !Memcmp {
128
203
offset: 2 ,
129
- bytes: MemcmpEncodedBytes :: Binary ( bs58:: encode( vec![ 3 , 4 , 5 , 6 ] ) . into_string( ) ) ,
204
+ bytes: MemcmpEncodedBytes :: Base58 ( bs58:: encode( vec![ 3 , 4 , 5 , 6 ] ) . into_string( ) ) ,
130
205
encoding: None ,
131
206
}
132
207
. bytes_match( & data) ) ;
133
208
134
209
// Offset outside data fails
135
210
assert ! ( !Memcmp {
136
211
offset: 6 ,
137
- bytes: MemcmpEncodedBytes :: Binary ( bs58:: encode( vec![ 5 ] ) . into_string( ) ) ,
212
+ bytes: MemcmpEncodedBytes :: Base58 ( bs58:: encode( vec![ 5 ] ) . into_string( ) ) ,
138
213
encoding: None ,
139
214
}
140
215
. bytes_match( & data) ) ;
141
216
142
217
// Invalid base-58 fails
143
218
assert ! ( !Memcmp {
144
219
offset: 0 ,
145
- bytes: MemcmpEncodedBytes :: Binary ( "III" . to_string( ) ) ,
220
+ bytes: MemcmpEncodedBytes :: Base58 ( "III" . to_string( ) ) ,
146
221
encoding: None ,
147
222
}
148
223
. bytes_match( & data) ) ;
@@ -157,7 +232,7 @@ mod tests {
157
232
assert_eq ! (
158
233
RpcFilterType :: Memcmp ( Memcmp {
159
234
offset: 0 ,
160
- bytes: MemcmpEncodedBytes :: Binary ( base58_bytes. to_string( ) ) ,
235
+ bytes: MemcmpEncodedBytes :: Base58 ( base58_bytes. to_string( ) ) ,
161
236
encoding: None ,
162
237
} )
163
238
. verify( ) ,
@@ -172,11 +247,11 @@ mod tests {
172
247
assert_eq ! (
173
248
RpcFilterType :: Memcmp ( Memcmp {
174
249
offset: 0 ,
175
- bytes: MemcmpEncodedBytes :: Binary ( base58_bytes. to_string( ) ) ,
250
+ bytes: MemcmpEncodedBytes :: Base58 ( base58_bytes. to_string( ) ) ,
176
251
encoding: None ,
177
252
} )
178
253
. verify( ) ,
179
- Err ( RpcFilterError :: Base58DataTooLarge )
254
+ Err ( RpcFilterError :: DataTooLarge )
180
255
) ;
181
256
}
182
257
}
0 commit comments