@@ -15,16 +15,16 @@ pub trait CacheObject {
1515}
1616
1717/// A response from the transaction cache, containing an item.
18- #[ derive( Debug , Clone , Serialize , Deserialize ) ]
19- #[ serde( untagged) ]
18+ #[ derive( Debug , Clone , Serialize , Deserialize , PartialEq , Eq ) ]
19+ #[ serde( untagged, rename_all_fields = "camelCase" ) ]
2020pub enum CacheResponse < T : CacheObject > {
2121 /// A paginated response, containing the inner item and a next cursor.
2222 Paginated {
2323 /// The actual item.
2424 #[ serde( flatten) ]
2525 inner : T ,
2626 /// The next cursor for pagination, if any.
27- next_cursor : Option < T :: Key > ,
27+ next_cursor : T :: Key ,
2828 } ,
2929 /// An unpaginated response, containing the actual item.
3030 Unpaginated {
@@ -41,7 +41,7 @@ impl<T: CacheObject> CacheObject for CacheResponse<T> {
4141impl < T : CacheObject > CacheResponse < T > {
4242 /// Create a new paginated response from a list of items and a pagination info.
4343 pub const fn paginated ( inner : T , pagination : T :: Key ) -> Self {
44- Self :: Paginated { inner, next_cursor : Some ( pagination) }
44+ Self :: Paginated { inner, next_cursor : pagination }
4545 }
4646
4747 /// Create a new unpaginated response from a list of items.
@@ -68,7 +68,7 @@ impl<T: CacheObject> CacheResponse<T> {
6868 /// Return the next cursor for pagination, if any.
6969 pub const fn next_cursor ( & self ) -> Option < & T :: Key > {
7070 match self {
71- Self :: Paginated { next_cursor, .. } => next_cursor . as_ref ( ) ,
71+ Self :: Paginated { next_cursor, .. } => Some ( next_cursor ) ,
7272 Self :: Unpaginated { .. } => None ,
7373 }
7474 }
@@ -99,7 +99,7 @@ impl<T: CacheObject> CacheResponse<T> {
9999 /// Consume the response and return the parts.
100100 pub fn into_parts ( self ) -> ( T , Option < T :: Key > ) {
101101 match self {
102- Self :: Paginated { inner, next_cursor } => ( inner, next_cursor) ,
102+ Self :: Paginated { inner, next_cursor } => ( inner, Some ( next_cursor) ) ,
103103 Self :: Unpaginated { inner } => ( inner, None ) ,
104104 }
105105 }
@@ -112,7 +112,7 @@ impl<T: CacheObject> CacheResponse<T> {
112112
113113/// A bundle response from the transaction cache, containing a UUID and a
114114/// [`SignetEthBundle`].
115- #[ derive( Debug , Clone , Serialize , Deserialize ) ]
115+ #[ derive( Debug , Clone , Serialize , Deserialize , PartialEq , Eq ) ]
116116pub struct TxCacheBundle {
117117 /// The bundle id (a UUID)
118118 pub id : uuid:: Uuid ,
@@ -154,7 +154,7 @@ impl TxCacheBundle {
154154}
155155
156156/// A response from the transaction cache, containing a single bundle.
157- #[ derive( Debug , Clone , Serialize , Deserialize ) ]
157+ #[ derive( Debug , Clone , Serialize , Deserialize , PartialEq , Eq ) ]
158158pub struct TxCacheBundleResponse {
159159 /// The bundle.
160160 pub bundle : TxCacheBundle ,
@@ -196,7 +196,7 @@ impl TxCacheBundleResponse {
196196}
197197
198198/// Response from the transaction cache `bundles` endpoint, containing a list of bundles.
199- #[ derive( Debug , Clone , Serialize , Deserialize ) ]
199+ #[ derive( Debug , Clone , Serialize , Deserialize , PartialEq , Eq ) ]
200200pub struct TxCacheBundlesResponse {
201201 /// the list of bundles
202202 pub bundles : Vec < TxCacheBundle > ,
@@ -243,7 +243,7 @@ impl TxCacheBundlesResponse {
243243}
244244
245245/// Represents a response to successfully adding or updating a bundle in the transaction cache.
246- #[ derive( Debug , Copy , Clone , Serialize , Deserialize ) ]
246+ #[ derive( Debug , Copy , Clone , Serialize , Deserialize , PartialEq , Eq ) ]
247247pub struct TxCacheSendBundleResponse {
248248 /// The bundle id (a UUID)
249249 pub id : uuid:: Uuid ,
@@ -273,7 +273,7 @@ impl CacheObject for TxCacheSendBundleResponse {
273273}
274274
275275/// Response from the transaction cache `transactions` endpoint, containing a list of transactions.
276- #[ derive( Debug , Clone , Serialize , Deserialize ) ]
276+ #[ derive( Debug , Clone , Serialize , Deserialize , PartialEq , Eq ) ]
277277pub struct TxCacheTransactionsResponse {
278278 /// The list of transactions.
279279 pub transactions : Vec < TxEnvelope > ,
@@ -320,7 +320,7 @@ impl TxCacheTransactionsResponse {
320320}
321321
322322/// Response from the transaction cache to successfully adding a transaction.
323- #[ derive( Debug , Clone , Copy , Serialize , Deserialize ) ]
323+ #[ derive( Debug , Clone , Copy , Serialize , Deserialize , PartialEq , Eq ) ]
324324pub struct TxCacheSendTransactionResponse {
325325 /// The transaction hash
326326 pub tx_hash : B256 ,
@@ -362,7 +362,7 @@ impl TxCacheSendTransactionResponse {
362362}
363363
364364/// Response from the transaction cache `orders` endpoint, containing a list of signed orders.
365- #[ derive( Debug , Clone , Serialize , Deserialize ) ]
365+ #[ derive( Debug , Clone , Serialize , Deserialize , PartialEq , Eq ) ]
366366pub struct TxCacheOrdersResponse {
367367 /// The list of signed orders.
368368 pub orders : Vec < SignedOrder > ,
@@ -404,7 +404,7 @@ impl TxCacheOrdersResponse {
404404}
405405
406406/// Response from the transaction cache to successfully adding an order.
407- #[ derive( Debug , Clone , Copy , Serialize , Deserialize ) ]
407+ #[ derive( Debug , Clone , Copy , Serialize , Deserialize , PartialEq , Eq ) ]
408408pub struct TxCacheSendOrderResponse {
409409 /// The order id
410410 pub id : B256 ,
@@ -861,9 +861,135 @@ impl<'de> Deserialize<'de> for CursorPayload<OrderKey> {
861861
862862#[ cfg( test) ]
863863mod tests {
864+ use super :: * ;
864865 use std:: str:: FromStr ;
865866
866- use super :: * ;
867+ fn dummy_bundle_with_id ( id : Uuid ) -> TxCacheBundle {
868+ TxCacheBundle {
869+ id,
870+ bundle : SignetEthBundle {
871+ bundle : alloy:: rpc:: types:: mev:: EthSendBundle {
872+ txs : vec ! [ ] ,
873+ block_number : 0 ,
874+ min_timestamp : None ,
875+ max_timestamp : None ,
876+ reverting_tx_hashes : vec ! [ ] ,
877+ replacement_uuid : Some ( id. to_string ( ) ) ,
878+ dropping_tx_hashes : vec ! [ ] ,
879+ refund_percent : None ,
880+ refund_recipient : None ,
881+ refund_tx_hashes : vec ! [ ] ,
882+ extra_fields : Default :: default ( ) ,
883+ } ,
884+ host_fills : None ,
885+ host_txs : vec ! [ ] ,
886+ } ,
887+ }
888+ }
889+
890+ #[ test]
891+ fn test_unpaginated_cache_response_deser ( ) {
892+ let cache_response = CacheResponse :: Unpaginated {
893+ inner : TxCacheTransactionsResponse { transactions : vec ! [ ] } ,
894+ } ;
895+ let expected_json = r#"{"transactions":[]}"# ;
896+ let serialized = serde_json:: to_string ( & cache_response) . unwrap ( ) ;
897+ assert_eq ! ( serialized, expected_json) ;
898+ let deserialized =
899+ serde_json:: from_str :: < CacheResponse < TxCacheTransactionsResponse > > ( & serialized)
900+ . unwrap ( ) ;
901+ assert_eq ! ( deserialized, cache_response) ;
902+ }
903+
904+ #[ test]
905+ fn test_paginated_cache_response_deser ( ) {
906+ let cache_response = CacheResponse :: Paginated {
907+ inner : TxCacheTransactionsResponse { transactions : vec ! [ ] } ,
908+ next_cursor : TxKey {
909+ txn_hash : B256 :: repeat_byte ( 0xaa ) ,
910+ score : 100 ,
911+ global_transaction_score_key : "gtsk" . to_string ( ) ,
912+ } ,
913+ } ;
914+ let expected_json = r#"{"transactions":[],"nextCursor":{"txnHash":"0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","score":100,"globalTransactionScoreKey":"gtsk"}}"# ;
915+ let serialized = serde_json:: to_string ( & cache_response) . unwrap ( ) ;
916+ assert_eq ! ( serialized, expected_json) ;
917+ let deserialized =
918+ serde_json:: from_str :: < CacheResponse < TxCacheTransactionsResponse > > ( & expected_json)
919+ . unwrap ( ) ;
920+ assert_eq ! ( deserialized, cache_response) ;
921+ }
922+
923+ // `serde_json` should be able to deserialize the old format, regardless if there's pagination information on the response.
924+ // This mimics the behavior of the types pre-pagination.
925+ #[ test]
926+ fn test_backwards_compatibility_cache_response_deser ( ) {
927+ let expected_json = r#"{"transactions":[],"nextCursor":{"txnHash":"0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","score":100,"globalTransactionScoreKey":"gtsk"}}"# ;
928+ let deserialized =
929+ serde_json:: from_str :: < TxCacheTransactionsResponse > ( & expected_json) . unwrap ( ) ;
930+ assert_eq ! ( deserialized, TxCacheTransactionsResponse { transactions: vec![ ] } ) ;
931+ }
932+
933+ // `serde_json` should be able to deserialize the old format, regardless if there's pagination information on the response.
934+ // This mimics the behavior of the types pre-pagination.
935+ #[ test]
936+ fn test_backwards_compatibility_cache_bundle_response_deser ( ) {
937+ let expected_json = r#"{"bundles":[{"id":"5932d4bb-58d9-41a9-851d-8dd7f04ccc33","bundle":{"txs":[],"blockNumber":"0x0","replacementUuid":"5932d4bb-58d9-41a9-851d-8dd7f04ccc33"}}]}"# ;
938+ let uuid = Uuid :: from_str ( "5932d4bb-58d9-41a9-851d-8dd7f04ccc33" ) . unwrap ( ) ;
939+
940+ let deserialized = serde_json:: from_str :: < TxCacheBundlesResponse > ( & expected_json) . unwrap ( ) ;
941+
942+ assert_eq ! (
943+ deserialized,
944+ TxCacheBundlesResponse { bundles: vec![ dummy_bundle_with_id( uuid) ] }
945+ ) ;
946+ }
947+
948+ // `serde_json` should be able to deserialize the old format, regardless if there's pagination information on the response.
949+ // This mimics the behavior of the types pre-pagination.
950+ #[ test]
951+ fn test_backwards_compatibility_cache_order_response_deser ( ) {
952+ let expected_json = r#"{"orders":[{"permit":{"permitted":[{"token":"0x0b8bc5e60ee10957e0d1a0d95598fa63e65605e2","amount":"0xf4240"}],"nonce":"0x637253c1eb651","deadline":"0x6846fde6"},"owner":"0x492e9c316f073fe4de9d665221568cdad1a7e95b","signature":"0x73e31a7c80f02840c4e0671230c408a5cbc7cddefc780db4dd102eed8e87c5740fc89944eb8e5756edd368ed755415ed090b043d1740ee6869c20cb1676329621c","outputs":[{"token":"0x885f8db528dc8a38aa3ddad9d3f619746b4a6a81","amount":"0xf4240","recipient":"0x492e9c316f073fe4de9d665221568cdad1a7e95b","chainId":3151908}]}], "id":"0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"}"# ;
953+ let _ = serde_json:: from_str :: < TxCacheOrdersResponse > ( & expected_json) . unwrap ( ) ;
954+ }
955+
956+ #[ test]
957+ fn test_unpaginated_cache_bundle_response_deser ( ) {
958+ let cache_response = CacheResponse :: Unpaginated {
959+ inner : TxCacheBundlesResponse {
960+ bundles : vec ! [ dummy_bundle_with_id(
961+ Uuid :: from_str( "5932d4bb-58d9-41a9-851d-8dd7f04ccc33" ) . unwrap( ) ,
962+ ) ] ,
963+ } ,
964+ } ;
965+ let expected_json = r#"{"bundles":[{"id":"5932d4bb-58d9-41a9-851d-8dd7f04ccc33","bundle":{"txs":[],"blockNumber":"0x0","replacementUuid":"5932d4bb-58d9-41a9-851d-8dd7f04ccc33"}}]}"# ;
966+ let serialized = serde_json:: to_string ( & cache_response) . unwrap ( ) ;
967+ assert_eq ! ( serialized, expected_json) ;
968+ let deserialized =
969+ serde_json:: from_str :: < CacheResponse < TxCacheBundlesResponse > > ( & expected_json) . unwrap ( ) ;
970+ assert_eq ! ( deserialized, cache_response) ;
971+ }
972+
973+ #[ test]
974+ fn test_paginated_cache_bundle_response_deser ( ) {
975+ let uuid = Uuid :: from_str ( "5932d4bb-58d9-41a9-851d-8dd7f04ccc33" ) . unwrap ( ) ;
976+
977+ let cache_response = CacheResponse :: Paginated {
978+ inner : TxCacheBundlesResponse { bundles : vec ! [ dummy_bundle_with_id( uuid) ] } ,
979+ next_cursor : BundleKey {
980+ id : uuid,
981+ score : 100 ,
982+ global_bundle_score_key : "gbsk" . to_string ( ) ,
983+ } ,
984+ } ;
985+ let expected_json = r#"{"bundles":[{"id":"5932d4bb-58d9-41a9-851d-8dd7f04ccc33","bundle":{"txs":[],"blockNumber":"0x0","replacementUuid":"5932d4bb-58d9-41a9-851d-8dd7f04ccc33"}}],"nextCursor":{"id":"5932d4bb-58d9-41a9-851d-8dd7f04ccc33","score":100,"globalBundleScoreKey":"gbsk"}}"# ;
986+ let serialized = serde_json:: to_string ( & cache_response) . unwrap ( ) ;
987+ dbg ! ( & serialized) ;
988+ assert_eq ! ( serialized, expected_json) ;
989+ let deserialized =
990+ serde_json:: from_str :: < CacheResponse < TxCacheBundlesResponse > > ( & expected_json) . unwrap ( ) ;
991+ assert_eq ! ( deserialized, cache_response) ;
992+ }
867993
868994 #[ test]
869995 fn test_pagination_params_simple_deser ( ) {
0 commit comments