1use std::fmt;
4
5use alloy_primitives::{B256, keccak256};
6use serde::{Deserialize, Serialize};
7
8use cow_errors::CowError;
9
10use super::{
11 order_id,
12 types::{ConditionalOrderParams, ProofLocation},
13};
14
15#[derive(Debug, Clone)]
17pub struct OrderProof {
18 pub order_id: B256,
20 pub proof: Vec<B256>,
22 pub params: ConditionalOrderParams,
24}
25
26impl OrderProof {
27 #[must_use]
39 pub const fn new(order_id: B256, proof: Vec<B256>, params: ConditionalOrderParams) -> Self {
40 Self { order_id, proof, params }
41 }
42
43 #[must_use]
50 pub const fn proof_len(&self) -> usize {
51 self.proof.len()
52 }
53}
54
55#[derive(Debug, Clone)]
57pub struct ProofWithParams {
58 pub proof: Vec<B256>,
60 pub params: ConditionalOrderParams,
62}
63
64impl ProofWithParams {
65 #[must_use]
76 pub const fn new(proof: Vec<B256>, params: ConditionalOrderParams) -> Self {
77 Self { proof, params }
78 }
79
80 #[must_use]
87 pub const fn proof_len(&self) -> usize {
88 self.proof.len()
89 }
90}
91
92impl fmt::Display for OrderProof {
93 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
94 write!(f, "order-proof({:#x}, {} siblings)", self.order_id, self.proof.len())
95 }
96}
97
98impl fmt::Display for ProofWithParams {
99 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
100 write!(
101 f,
102 "proof-with-params({} siblings, handler={:#x})",
103 self.proof.len(),
104 self.params.handler
105 )
106 }
107}
108
109#[derive(Serialize, Deserialize)]
112struct MultiplexerJson {
113 proof_location: u8,
114 orders: Vec<ParamsJson>,
115}
116
117#[derive(Serialize, Deserialize)]
118struct ParamsJson {
119 handler: String,
120 salt: String,
121 static_input: String,
122}
123
124#[derive(Deserialize)]
126struct WatchtowerEntry {
127 proof: Vec<String>,
128 params: WatchtowerParams,
129}
130
131#[derive(Deserialize)]
133#[serde(rename_all = "camelCase")]
134struct WatchtowerParams {
135 handler: String,
136 salt: String,
137 static_input: String,
138}
139
140impl From<&ConditionalOrderParams> for ParamsJson {
141 fn from(p: &ConditionalOrderParams) -> Self {
142 Self {
143 handler: format!("{:?}", p.handler),
144 salt: format!("0x{}", alloy_primitives::hex::encode(p.salt.as_slice())),
145 static_input: format!("0x{}", alloy_primitives::hex::encode(&p.static_input)),
146 }
147 }
148}
149
150impl TryFrom<ParamsJson> for ConditionalOrderParams {
151 type Error = CowError;
152 fn try_from(j: ParamsJson) -> Result<Self, CowError> {
153 let handler = j
154 .handler
155 .parse()
156 .map_err(|e: alloy_primitives::hex::FromHexError| CowError::AppData(e.to_string()))?;
157 let salt_hex = j.salt.strip_prefix("0x").map_or(j.salt.as_str(), |s| s);
158 let salt_bytes = alloy_primitives::hex::decode(salt_hex)
159 .map_err(|e| CowError::AppData(format!("salt: {e}")))?;
160 let mut salt = [0u8; 32];
161 salt.copy_from_slice(&salt_bytes);
162 let input_hex = j.static_input.strip_prefix("0x").map_or(j.static_input.as_str(), |s| s);
163 let static_input = alloy_primitives::hex::decode(input_hex)
164 .map_err(|e| CowError::AppData(format!("static_input: {e}")))?;
165 Ok(Self { handler, salt: B256::new(salt), static_input })
166 }
167}
168
169#[derive(Debug, Clone, Default)]
180pub struct Multiplexer {
181 orders: Vec<ConditionalOrderParams>,
182 proof_location: ProofLocation,
183}
184
185impl Multiplexer {
186 #[must_use]
197 pub const fn new(proof_location: ProofLocation) -> Self {
198 Self { orders: Vec::new(), proof_location }
199 }
200
201 pub fn add(&mut self, params: ConditionalOrderParams) {
210 self.orders.push(params);
211 }
212
213 pub fn remove(&mut self, id: B256) {
221 self.orders.retain(|p| order_id(p) != id);
222 }
223
224 pub fn update(&mut self, index: usize, params: ConditionalOrderParams) -> Result<(), CowError> {
230 if index >= self.orders.len() {
231 return Err(CowError::AppData(format!(
232 "index {index} out of range (len {})",
233 self.orders.len()
234 )));
235 }
236 self.orders[index] = params;
237 Ok(())
238 }
239
240 #[must_use]
250 pub fn get_by_index(&self, index: usize) -> Option<&ConditionalOrderParams> {
251 self.orders.get(index)
252 }
253
254 #[must_use]
265 pub fn get_by_id(&self, id: B256) -> Option<&ConditionalOrderParams> {
266 self.orders.iter().find(|p| order_id(p) == id)
267 }
268
269 #[must_use]
275 pub const fn len(&self) -> usize {
276 self.orders.len()
277 }
278
279 #[must_use]
285 pub const fn is_empty(&self) -> bool {
286 self.orders.is_empty()
287 }
288
289 pub fn root(&self) -> Result<Option<B256>, CowError> {
301 if self.orders.is_empty() {
302 return Ok(None);
303 }
304 let leaves: Vec<B256> = self.orders.iter().map(leaf_hash).collect();
305 Ok(Some(merkle_root(&leaves)))
306 }
307
308 pub fn proof(&self, index: usize) -> Result<OrderProof, CowError> {
317 if index >= self.orders.len() {
318 return Err(CowError::AppData(format!(
319 "index {index} out of range (len {})",
320 self.orders.len()
321 )));
322 }
323 let leaves: Vec<B256> = self.orders.iter().map(leaf_hash).collect();
324 Ok(OrderProof {
325 order_id: order_id(&self.orders[index]),
326 proof: generate_proof(&leaves, index),
327 params: self.orders[index].clone(),
328 })
329 }
330
331 pub fn dump_proofs_and_params(&self) -> Result<Vec<ProofWithParams>, CowError> {
337 (0..self.orders.len())
338 .map(|i| {
339 let op = self.proof(i)?;
340 Ok(ProofWithParams { proof: op.proof, params: op.params })
341 })
342 .collect()
343 }
344
345 pub fn order_ids(&self) -> impl Iterator<Item = alloy_primitives::B256> + '_ {
354 self.orders.iter().map(order_id)
355 }
356
357 pub fn iter(&self) -> impl Iterator<Item = &ConditionalOrderParams> {
364 self.orders.iter()
365 }
366
367 #[must_use]
373 pub fn as_slice(&self) -> &[ConditionalOrderParams] {
374 &self.orders
375 }
376
377 pub fn clear(&mut self) {
379 self.orders.clear();
380 }
381
382 #[must_use]
389 pub const fn proof_location(&self) -> ProofLocation {
390 self.proof_location
391 }
392
393 #[must_use]
404 pub const fn with_proof_location(mut self, location: ProofLocation) -> Self {
405 self.proof_location = location;
406 self
407 }
408
409 #[must_use]
416 pub fn into_vec(self) -> Vec<ConditionalOrderParams> {
417 self.orders
418 }
419
420 pub fn to_json(&self) -> Result<String, CowError> {
430 let j = MultiplexerJson {
431 proof_location: self.proof_location as u8,
432 orders: self.orders.iter().map(ParamsJson::from).collect(),
433 };
434 serde_json::to_string(&j).map_err(|e| CowError::AppData(e.to_string()))
435 }
436
437 pub fn decode_proofs_from_json(json: &str) -> Result<Vec<ProofWithParams>, CowError> {
447 let entries: Vec<WatchtowerEntry> =
448 serde_json::from_str(json).map_err(|e| CowError::AppData(e.to_string()))?;
449 entries
450 .into_iter()
451 .map(|entry| {
452 let proof = entry
453 .proof
454 .iter()
455 .map(|s| {
456 let hex = s.strip_prefix("0x").map_or(s.as_str(), |h| h);
457 let bytes = alloy_primitives::hex::decode(hex)
458 .map_err(|e| CowError::AppData(format!("proof hash: {e}")))?;
459 let mut arr = [0u8; 32];
460 arr.copy_from_slice(&bytes);
461 Ok(B256::new(arr))
462 })
463 .collect::<Result<Vec<_>, CowError>>()?;
464 let p = entry.params;
465 let handler =
466 p.handler.parse().map_err(|e: alloy_primitives::hex::FromHexError| {
467 CowError::AppData(e.to_string())
468 })?;
469 let salt_hex = p.salt.strip_prefix("0x").map_or(p.salt.as_str(), |s| s);
470 let salt_bytes = alloy_primitives::hex::decode(salt_hex)
471 .map_err(|e| CowError::AppData(format!("salt: {e}")))?;
472 let mut salt = [0u8; 32];
473 salt.copy_from_slice(&salt_bytes);
474 let input_hex =
475 p.static_input.strip_prefix("0x").map_or(p.static_input.as_str(), |s| s);
476 let static_input = alloy_primitives::hex::decode(input_hex)
477 .map_err(|e| CowError::AppData(format!("staticInput: {e}")))?;
478 let params =
479 ConditionalOrderParams { handler, salt: B256::new(salt), static_input };
480 Ok(ProofWithParams { proof, params })
481 })
482 .collect()
483 }
484
485 pub fn from_json(json: &str) -> Result<Self, CowError> {
491 let j: MultiplexerJson =
492 serde_json::from_str(json).map_err(|e| CowError::AppData(e.to_string()))?;
493 let proof_location = match j.proof_location {
494 0 => ProofLocation::Private,
495 1 => ProofLocation::Emitted,
496 2 => ProofLocation::Swarm,
497 3 => ProofLocation::Waku,
498 4 => ProofLocation::Reserved,
499 5 => ProofLocation::Ipfs,
500 n => {
501 return Err(CowError::AppData(format!("unknown ProofLocation: {n}")));
502 }
503 };
504 let orders = j
505 .orders
506 .into_iter()
507 .map(ConditionalOrderParams::try_from)
508 .collect::<Result<Vec<_>, _>>()?;
509 Ok(Self { orders, proof_location })
510 }
511}
512impl fmt::Display for Multiplexer {
513 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
514 write!(f, "multiplexer({} orders, {})", self.orders.len(), self.proof_location)
515 }
516}
517
518fn leaf_hash(params: &ConditionalOrderParams) -> B256 {
532 keccak256(order_id(params))
533}
534
535fn merkle_root(leaves: &[B256]) -> B256 {
547 if leaves.len() == 1 {
548 return leaves[0];
549 }
550 let mut layer = leaves.to_vec();
551 while layer.len() > 1 {
552 let mut next = Vec::with_capacity(layer.len().div_ceil(2));
553 let mut i = 0;
554 while i < layer.len() {
555 if i + 1 < layer.len() {
556 next.push(hash_pair(layer[i], layer[i + 1]));
557 } else {
558 next.push(layer[i]);
559 }
560 i += 2;
561 }
562 layer = next;
563 }
564 layer[0]
565}
566
567fn hash_pair(a: B256, b: B256) -> B256 {
579 let (lo, hi) = if a <= b { (a, b) } else { (b, a) };
580 let mut buf = [0u8; 64];
581 buf[..32].copy_from_slice(lo.as_slice());
582 buf[32..].copy_from_slice(hi.as_slice());
583 keccak256(buf)
584}
585
586fn generate_proof(leaves: &[B256], mut index: usize) -> Vec<B256> {
599 let mut proof = Vec::new();
600 let mut layer = leaves.to_vec();
601 while layer.len() > 1 {
602 let sibling = if index.is_multiple_of(2) {
603 (index + 1 < layer.len()).then(|| layer[index + 1])
604 } else {
605 Some(layer[index - 1])
606 };
607 if let Some(s) = sibling {
608 proof.push(s);
609 }
610 let mut next = Vec::with_capacity(layer.len().div_ceil(2));
611 let mut i = 0;
612 while i < layer.len() {
613 if i + 1 < layer.len() {
614 next.push(hash_pair(layer[i], layer[i + 1]));
615 } else {
616 next.push(layer[i]);
617 }
618 i += 2;
619 }
620 layer = next;
621 index /= 2;
622 }
623 proof
624}
625
626#[cfg(test)]
629mod tests {
630 use alloy_primitives::Address;
631
632 use super::*;
633
634 fn make_params(salt_byte: u8) -> ConditionalOrderParams {
635 ConditionalOrderParams {
636 handler: Address::ZERO,
637 salt: B256::new([salt_byte; 32]),
638 static_input: vec![salt_byte; 4],
639 }
640 }
641
642 #[test]
643 fn decode_proofs_from_json_roundtrip() {
644 let mut mux = Multiplexer::new(ProofLocation::Private);
646 mux.add(make_params(0xaa));
647 mux.add(make_params(0xbb));
648
649 let proofs = mux.dump_proofs_and_params().unwrap();
650
651 let json_entries: Vec<serde_json::Value> = proofs
653 .iter()
654 .map(|p| {
655 let proof_arr: Vec<String> = p
656 .proof
657 .iter()
658 .map(|h| format!("0x{}", alloy_primitives::hex::encode(h.as_slice())))
659 .collect();
660 serde_json::json!({
661 "proof": proof_arr,
662 "params": {
663 "handler": format!("{:#x}", p.params.handler),
664 "salt": format!("0x{}", alloy_primitives::hex::encode(p.params.salt.as_slice())),
665 "staticInput": format!("0x{}", alloy_primitives::hex::encode(&p.params.static_input)),
666 }
667 })
668 })
669 .collect();
670 let json = serde_json::to_string(&json_entries).unwrap();
671
672 let decoded = Multiplexer::decode_proofs_from_json(&json).unwrap();
673 assert_eq!(decoded.len(), 2);
674 assert_eq!(decoded[0].params.salt, proofs[0].params.salt);
675 assert_eq!(decoded[1].params.static_input, proofs[1].params.static_input);
676 }
677
678 #[test]
679 fn decode_proofs_from_json_invalid_returns_error() {
680 let result = Multiplexer::decode_proofs_from_json("not json");
681 assert!(result.is_err());
682 }
683
684 #[test]
685 fn decode_proofs_from_json_rejects_non_hex_handler() {
686 let json = serde_json::json!([{
689 "proof": [],
690 "params": {
691 "handler": "not-a-hex-address",
692 "salt": "0x0000000000000000000000000000000000000000000000000000000000000000",
693 "staticInput": "0x"
694 }
695 }])
696 .to_string();
697 let err = Multiplexer::decode_proofs_from_json(&json).unwrap_err();
698 assert!(matches!(err, CowError::AppData(_)));
699 }
700
701 #[test]
702 fn multiplexer_root_single_order() {
703 let mut mux = Multiplexer::new(ProofLocation::Private);
704 mux.add(make_params(1));
705 let root = mux.root().unwrap();
706 assert!(root.is_some());
707 }
708
709 #[test]
710 fn multiplexer_root_empty() {
711 let mux = Multiplexer::new(ProofLocation::Private);
712 assert!(mux.root().unwrap().is_none());
713 }
714
715 #[test]
718 fn add_increases_len() {
719 let mut mux = Multiplexer::new(ProofLocation::Private);
720 assert!(mux.is_empty());
721 mux.add(make_params(1));
722 assert_eq!(mux.len(), 1);
723 mux.add(make_params(2));
724 assert_eq!(mux.len(), 2);
725 }
726
727 #[test]
728 fn remove_by_id() {
729 let mut mux = Multiplexer::new(ProofLocation::Private);
730 let p = make_params(0xaa);
731 let id = order_id(&p);
732 mux.add(p);
733 mux.add(make_params(0xbb));
734 assert_eq!(mux.len(), 2);
735 mux.remove(id);
736 assert_eq!(mux.len(), 1);
737 }
738
739 #[test]
740 fn remove_nonexistent_is_noop() {
741 let mut mux = Multiplexer::new(ProofLocation::Private);
742 mux.add(make_params(1));
743 mux.remove(B256::ZERO);
744 assert_eq!(mux.len(), 1);
745 }
746
747 #[test]
748 fn update_in_range() {
749 let mut mux = Multiplexer::new(ProofLocation::Private);
750 mux.add(make_params(1));
751 mux.add(make_params(2));
752 let new_params = make_params(99);
753 mux.update(1, new_params.clone()).unwrap();
754 assert_eq!(mux.get_by_index(1).unwrap().salt, new_params.salt);
755 }
756
757 #[test]
758 fn update_out_of_range() {
759 let mut mux = Multiplexer::new(ProofLocation::Private);
760 mux.add(make_params(1));
761 assert!(mux.update(5, make_params(2)).is_err());
762 }
763
764 #[test]
767 fn get_by_index_valid() {
768 let mut mux = Multiplexer::new(ProofLocation::Private);
769 let p = make_params(0xcc);
770 mux.add(p.clone());
771 let got = mux.get_by_index(0).unwrap();
772 assert_eq!(got.salt, p.salt);
773 }
774
775 #[test]
776 fn get_by_index_out_of_range() {
777 let mux = Multiplexer::new(ProofLocation::Private);
778 assert!(mux.get_by_index(0).is_none());
779 }
780
781 #[test]
782 fn get_by_id_found() {
783 let mut mux = Multiplexer::new(ProofLocation::Private);
784 let p = make_params(0xdd);
785 let id = order_id(&p);
786 mux.add(p.clone());
787 let got = mux.get_by_id(id).unwrap();
788 assert_eq!(got.salt, p.salt);
789 }
790
791 #[test]
792 fn get_by_id_not_found() {
793 let mut mux = Multiplexer::new(ProofLocation::Private);
794 mux.add(make_params(1));
795 assert!(mux.get_by_id(B256::ZERO).is_none());
796 }
797
798 #[test]
801 fn root_changes_when_order_added() {
802 let mut mux = Multiplexer::new(ProofLocation::Private);
803 mux.add(make_params(1));
804 let root1 = mux.root().unwrap().unwrap();
805 mux.add(make_params(2));
806 let root2 = mux.root().unwrap().unwrap();
807 assert_ne!(root1, root2);
808 }
809
810 #[test]
811 fn root_two_orders() {
812 let mut mux = Multiplexer::new(ProofLocation::Private);
813 mux.add(make_params(0xaa));
814 mux.add(make_params(0xbb));
815 let root = mux.root().unwrap();
816 assert!(root.is_some());
817 }
818
819 #[test]
820 fn proof_valid_index() {
821 let mut mux = Multiplexer::new(ProofLocation::Private);
822 mux.add(make_params(0xaa));
823 mux.add(make_params(0xbb));
824 let proof = mux.proof(0).unwrap();
825 assert!(!proof.proof.is_empty());
826 assert_eq!(proof.params.salt, make_params(0xaa).salt);
827 }
828
829 #[test]
830 fn proof_out_of_range() {
831 let mut mux = Multiplexer::new(ProofLocation::Private);
832 mux.add(make_params(1));
833 assert!(mux.proof(5).is_err());
834 }
835
836 #[test]
839 fn dump_proofs_and_params_returns_all() {
840 let mut mux = Multiplexer::new(ProofLocation::Private);
841 mux.add(make_params(0xaa));
842 mux.add(make_params(0xbb));
843 mux.add(make_params(0xcc));
844 let proofs = mux.dump_proofs_and_params().unwrap();
845 assert_eq!(proofs.len(), 3);
846 }
847
848 #[test]
851 fn to_json_from_json_roundtrip() {
852 let mut mux = Multiplexer::new(ProofLocation::Ipfs);
853 mux.add(make_params(0x11));
854 mux.add(make_params(0x22));
855
856 let json = mux.to_json().unwrap();
857 let restored = Multiplexer::from_json(&json).unwrap();
858
859 assert_eq!(restored.len(), 2);
860 assert_eq!(restored.proof_location(), ProofLocation::Ipfs);
861 assert_eq!(restored.get_by_index(0).unwrap().salt, make_params(0x11).salt);
862 assert_eq!(restored.get_by_index(1).unwrap().salt, make_params(0x22).salt);
863 }
864
865 #[test]
866 fn from_json_invalid() {
867 assert!(Multiplexer::from_json("not json").is_err());
868 }
869
870 #[test]
871 fn from_json_unknown_proof_location() {
872 let json = r#"{"proof_location": 99, "orders": []}"#;
873 assert!(Multiplexer::from_json(json).is_err());
874 }
875
876 #[test]
879 fn clear_empties_multiplexer() {
880 let mut mux = Multiplexer::new(ProofLocation::Private);
881 mux.add(make_params(1));
882 mux.add(make_params(2));
883 mux.clear();
884 assert!(mux.is_empty());
885 }
886
887 #[test]
888 fn order_ids_iterator() {
889 let mut mux = Multiplexer::new(ProofLocation::Private);
890 mux.add(make_params(0xaa));
891 mux.add(make_params(0xbb));
892 let ids: Vec<_> = mux.order_ids().collect();
893 assert_eq!(ids.len(), 2);
894 assert_eq!(ids[0], order_id(&make_params(0xaa)));
895 }
896
897 #[test]
898 fn iter_and_as_slice() {
899 let mut mux = Multiplexer::new(ProofLocation::Private);
900 mux.add(make_params(1));
901 mux.add(make_params(2));
902 assert_eq!(mux.iter().count(), 2);
903 assert_eq!(mux.as_slice().len(), 2);
904 }
905
906 #[test]
907 fn into_vec_returns_orders() {
908 let mut mux = Multiplexer::new(ProofLocation::Private);
909 mux.add(make_params(1));
910 let v = mux.into_vec();
911 assert_eq!(v.len(), 1);
912 }
913
914 #[test]
915 fn with_proof_location_builder() {
916 let mux =
917 Multiplexer::new(ProofLocation::Private).with_proof_location(ProofLocation::Swarm);
918 assert_eq!(mux.proof_location(), ProofLocation::Swarm);
919 }
920
921 #[test]
922 fn display_multiplexer() {
923 let mut mux = Multiplexer::new(ProofLocation::Private);
924 mux.add(make_params(1));
925 let s = format!("{mux}");
926 assert!(s.contains("1 orders"));
927 }
928
929 #[test]
930 fn display_order_proof() {
931 let mut mux = Multiplexer::new(ProofLocation::Private);
932 mux.add(make_params(0xaa));
933 mux.add(make_params(0xbb));
934 let proof = mux.proof(0).unwrap();
935 let s = format!("{proof}");
936 assert!(s.contains("order-proof"));
937 }
938
939 #[test]
940 fn from_json_all_proof_locations() {
941 for (val, expected) in [
942 (0, ProofLocation::Private),
943 (1, ProofLocation::Emitted),
944 (2, ProofLocation::Swarm),
945 (3, ProofLocation::Waku),
946 (4, ProofLocation::Reserved),
947 (5, ProofLocation::Ipfs),
948 ] {
949 let json = format!(r#"{{"proof_location": {val}, "orders": []}}"#);
950 let mux = Multiplexer::from_json(&json).unwrap();
951 assert_eq!(mux.proof_location(), expected);
952 }
953 }
954
955 #[test]
956 fn multiplexer_root_three_orders() {
957 let mut mux = Multiplexer::new(ProofLocation::Private);
958 mux.add(make_params(0xaa));
959 mux.add(make_params(0xbb));
960 mux.add(make_params(0xcc));
961 let root = mux.root().unwrap();
962 assert!(root.is_some());
963 for i in 0..3 {
965 let proof = mux.proof(i).unwrap();
966 assert!(!proof.proof.is_empty() || mux.len() == 1);
967 }
968 }
969
970 #[test]
971 fn order_proof_accessors() {
972 let params = make_params(0xaa);
973 let id = order_id(¶ms);
974 let proof = OrderProof::new(id, vec![B256::ZERO], params.clone());
975 assert_eq!(proof.order_id, id);
976 assert_eq!(proof.proof_len(), 1);
977 assert_eq!(proof.params.salt, params.salt);
978 }
979
980 #[test]
981 fn proof_with_params_accessors() {
982 let params = make_params(0xaa);
983 let pwp = ProofWithParams::new(vec![B256::ZERO, B256::ZERO], params);
984 assert_eq!(pwp.proof_len(), 2);
985 }
986
987 #[test]
988 fn display_proof_with_params() {
989 let mut mux = Multiplexer::new(ProofLocation::Private);
990 mux.add(make_params(0xaa));
991 mux.add(make_params(0xbb));
992 let proofs = mux.dump_proofs_and_params().unwrap();
993 let s = format!("{}", proofs[0]);
994 assert!(s.contains("proof-with-params"));
995 }
996
997 #[test]
998 fn order_proof_new_and_proof_len() {
999 let op = OrderProof::new(B256::ZERO, vec![B256::ZERO, B256::ZERO], make_params(1));
1000 assert_eq!(op.proof_len(), 2);
1001 }
1002
1003 #[test]
1004 fn proof_with_params_new_and_proof_len() {
1005 let pwp = ProofWithParams::new(vec![B256::ZERO], make_params(1));
1006 assert_eq!(pwp.proof_len(), 1);
1007 }
1008}