1use std::{fmt, vec};
2
3use async_trait::async_trait;
4use serde::{Deserialize, Deserializer, Serialize, Serializer};
5
6use aztec_core::abi::{ContractArtifact, EventSelector};
7use aztec_core::error::Error;
8use aztec_core::tx::{
9 AuthWitness, ChonkProof, ContractClassLogFields, FunctionCall, HashedValues,
10 PrivateKernelTailCircuitPublicInputs, Tx, TxHash,
11};
12use aztec_core::types::{AztecAddress, CompleteAddress, ContractInstanceWithAddress, Fr};
13
14fn strip_0x(s: &str) -> &str {
19 s.strip_prefix("0x").unwrap_or(s)
20}
21
22fn decode_hex_32(s: &str) -> Result<[u8; 32], Error> {
23 let raw = strip_0x(s);
24 if raw.len() > 64 {
25 return Err(Error::InvalidData(
26 "hex value too large: expected at most 32 bytes".to_owned(),
27 ));
28 }
29
30 let padded = if raw.len() % 2 == 1 {
31 format!("0{raw}")
32 } else {
33 raw.to_owned()
34 };
35
36 let decoded = hex::decode(padded).map_err(|e| Error::InvalidData(e.to_string()))?;
37 if decoded.len() > 32 {
38 return Err(Error::InvalidData(
39 "hex value too large: expected at most 32 bytes".to_owned(),
40 ));
41 }
42
43 let mut out = [0u8; 32];
44 out[32 - decoded.len()..].copy_from_slice(&decoded);
45 Ok(out)
46}
47
48fn encode_hex(bytes: &[u8]) -> String {
49 format!("0x{}", hex::encode(bytes))
50}
51
52#[derive(Debug, Clone, Serialize, Deserialize)]
57pub struct BlockHeader {
58 #[serde(flatten)]
60 pub data: serde_json::Value,
61}
62
63#[derive(Debug, Clone, Serialize, Deserialize)]
68pub struct TxExecutionRequest {
69 #[serde(flatten)]
71 pub data: serde_json::Value,
72}
73
74#[derive(Debug, Clone, Serialize, Deserialize, Default)]
79#[serde(rename_all = "camelCase")]
80pub struct TxProvingResult {
81 #[serde(default, skip_serializing_if = "Option::is_none")]
83 pub tx_hash: Option<TxHash>,
84 #[serde(default)]
86 pub private_execution_result: serde_json::Value,
87 pub public_inputs: PrivateKernelTailCircuitPublicInputs,
89 pub chonk_proof: ChonkProof,
91 #[serde(default)]
93 pub contract_class_log_fields: Vec<ContractClassLogFields>,
94 #[serde(default)]
96 pub public_function_calldata: Vec<HashedValues>,
97 #[serde(default, skip_serializing_if = "Option::is_none")]
99 pub stats: Option<serde_json::Value>,
100}
101
102impl TxProvingResult {
103 pub fn to_tx(&self) -> Tx {
110 Tx {
111 data: self.public_inputs.clone(),
112 chonk_proof: self.chonk_proof.clone(),
113 contract_class_log_fields: self.contract_class_log_fields.clone(),
114 public_function_calldata: self.public_function_calldata.clone(),
115 }
116 }
117
118 pub fn validate(&self) -> Result<(), Error> {
124 let _ = self.public_function_calldata.len();
129 let _ = self.contract_class_log_fields.len();
130 Ok(())
131 }
132}
133
134#[derive(Debug, Clone, Serialize, Deserialize)]
136pub struct TxSimulationResult {
137 #[serde(flatten)]
139 pub data: serde_json::Value,
140}
141
142#[derive(Debug, Clone, Serialize, Deserialize)]
144pub struct TxProfileResult {
145 #[serde(flatten)]
147 pub data: serde_json::Value,
148}
149
150#[derive(Clone, Copy, Default, PartialEq, Eq, Hash)]
152pub struct BlockHash(pub [u8; 32]);
153
154impl BlockHash {
155 pub fn from_hex(value: &str) -> Result<Self, Error> {
157 Ok(Self(decode_hex_32(value)?))
158 }
159}
160
161impl fmt::Display for BlockHash {
162 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
163 f.write_str(&encode_hex(&self.0))
164 }
165}
166
167impl fmt::Debug for BlockHash {
168 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
169 write!(f, "BlockHash({self})")
170 }
171}
172
173impl Serialize for BlockHash {
174 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
175 where
176 S: Serializer,
177 {
178 serializer.serialize_str(&self.to_string())
179 }
180}
181
182impl<'de> Deserialize<'de> for BlockHash {
183 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
184 where
185 D: Deserializer<'de>,
186 {
187 let s = String::deserialize(deserializer)?;
188 Self::from_hex(&s).map_err(serde::de::Error::custom)
189 }
190}
191
192#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
194#[serde(rename_all = "camelCase")]
195pub struct LogId {
196 pub block_number: u64,
198 pub block_hash: BlockHash,
200 pub tx_hash: TxHash,
202 pub tx_index: u64,
204 pub log_index: u64,
206}
207
208#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
210pub enum ProfileMode {
211 #[serde(rename = "full")]
213 Full,
214 #[serde(rename = "execution-steps")]
216 ExecutionSteps,
217 #[serde(rename = "gates")]
219 Gates,
220}
221
222#[derive(Debug, Clone, Serialize, Deserialize)]
228#[serde(rename_all = "camelCase")]
229pub struct UtilityExecutionResult {
230 pub result: Vec<Fr>,
232 #[serde(default, skip_serializing_if = "Option::is_none")]
234 pub stats: Option<serde_json::Value>,
235}
236
237#[derive(Debug, Clone, Default, Serialize, Deserialize)]
239#[serde(rename_all = "camelCase")]
240pub struct SimulateTxOpts {
241 #[serde(default)]
243 pub simulate_public: bool,
244 #[serde(default)]
246 pub skip_tx_validation: bool,
247 #[serde(default)]
249 pub skip_fee_enforcement: bool,
250 #[serde(default, skip_serializing_if = "Option::is_none")]
252 pub overrides: Option<serde_json::Value>,
253 #[serde(default)]
255 pub scopes: Vec<AztecAddress>,
256}
257
258#[derive(Debug, Clone, Serialize, Deserialize)]
260#[serde(rename_all = "camelCase")]
261pub struct ProfileTxOpts {
262 pub profile_mode: ProfileMode,
264 #[serde(default = "default_skip_proof_generation")]
266 pub skip_proof_generation: bool,
267 #[serde(default)]
269 pub scopes: Vec<AztecAddress>,
270}
271
272impl Default for ProfileTxOpts {
273 fn default() -> Self {
274 Self {
275 profile_mode: ProfileMode::Full,
276 skip_proof_generation: default_skip_proof_generation(),
277 scopes: vec![],
278 }
279 }
280}
281
282#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
284#[serde(rename_all = "camelCase")]
285pub struct ExecuteUtilityOpts {
286 #[serde(default)]
288 pub authwits: Vec<AuthWitness>,
289 #[serde(default)]
291 pub scopes: Vec<AztecAddress>,
292}
293
294#[derive(Debug, Clone, Serialize, Deserialize)]
296#[serde(rename_all = "camelCase")]
297pub struct PackedPrivateEvent {
298 pub packed_event: Vec<Fr>,
300 pub tx_hash: TxHash,
302 pub l2_block_number: u64,
304 pub l2_block_hash: BlockHash,
306 pub event_selector: EventSelector,
308}
309
310#[derive(Debug, Clone, Serialize, Deserialize)]
312#[serde(rename_all = "camelCase")]
313pub struct PrivateEventFilter {
314 pub contract_address: AztecAddress,
316 #[serde(default, skip_serializing_if = "Option::is_none")]
318 pub tx_hash: Option<TxHash>,
319 #[serde(default, skip_serializing_if = "Option::is_none")]
321 pub from_block: Option<u64>,
322 #[serde(default, skip_serializing_if = "Option::is_none")]
324 pub to_block: Option<u64>,
325 #[serde(default, skip_serializing_if = "Option::is_none")]
327 pub after_log: Option<LogId>,
328 #[serde(default)]
330 pub scopes: Vec<AztecAddress>,
331}
332
333impl Default for PrivateEventFilter {
334 fn default() -> Self {
335 Self {
336 contract_address: AztecAddress(Fr::zero()),
337 tx_hash: None,
338 from_block: None,
339 to_block: None,
340 after_log: None,
341 scopes: vec![],
342 }
343 }
344}
345
346#[derive(Debug, Clone, Serialize, Deserialize)]
348#[serde(rename_all = "camelCase")]
349pub struct RegisterContractRequest {
350 pub instance: ContractInstanceWithAddress,
352 #[serde(default, skip_serializing_if = "Option::is_none")]
354 pub artifact: Option<ContractArtifact>,
355}
356
357const fn default_skip_proof_generation() -> bool {
358 true
359}
360
361#[async_trait]
371pub trait Pxe: Send + Sync {
372 async fn get_synced_block_header(&self) -> Result<BlockHeader, Error>;
374
375 async fn get_contract_instance(
377 &self,
378 address: &AztecAddress,
379 ) -> Result<Option<ContractInstanceWithAddress>, Error>;
380
381 async fn get_contract_artifact(&self, id: &Fr) -> Result<Option<ContractArtifact>, Error>;
383
384 async fn get_contracts(&self) -> Result<Vec<AztecAddress>, Error>;
386
387 async fn register_account(
389 &self,
390 secret_key: &Fr,
391 partial_address: &Fr,
392 ) -> Result<CompleteAddress, Error>;
393
394 async fn get_registered_accounts(&self) -> Result<Vec<CompleteAddress>, Error>;
396
397 async fn register_sender(&self, sender: &AztecAddress) -> Result<AztecAddress, Error>;
399
400 async fn get_senders(&self) -> Result<Vec<AztecAddress>, Error>;
402
403 async fn remove_sender(&self, sender: &AztecAddress) -> Result<(), Error>;
405
406 async fn register_contract_class(&self, artifact: &ContractArtifact) -> Result<(), Error>;
408
409 async fn register_contract(&self, request: RegisterContractRequest) -> Result<(), Error>;
411
412 async fn update_contract(
414 &self,
415 address: &AztecAddress,
416 artifact: &ContractArtifact,
417 ) -> Result<(), Error>;
418
419 async fn simulate_tx(
421 &self,
422 tx_request: &TxExecutionRequest,
423 opts: SimulateTxOpts,
424 ) -> Result<TxSimulationResult, Error>;
425
426 async fn prove_tx(
428 &self,
429 tx_request: &TxExecutionRequest,
430 scopes: Vec<AztecAddress>,
431 ) -> Result<TxProvingResult, Error>;
432
433 async fn profile_tx(
435 &self,
436 tx_request: &TxExecutionRequest,
437 opts: ProfileTxOpts,
438 ) -> Result<TxProfileResult, Error>;
439
440 async fn execute_utility(
442 &self,
443 call: &FunctionCall,
444 opts: ExecuteUtilityOpts,
445 ) -> Result<UtilityExecutionResult, Error>;
446
447 async fn get_private_events(
449 &self,
450 event_selector: &EventSelector,
451 filter: PrivateEventFilter,
452 ) -> Result<Vec<PackedPrivateEvent>, Error>;
453
454 async fn stop(&self) -> Result<(), Error>;
456}
457
458#[cfg(test)]
463#[allow(clippy::unwrap_used, clippy::expect_used)]
464mod tests {
465 use super::*;
466 use aztec_core::abi::{FunctionSelector, FunctionType};
467 use aztec_core::types::{ContractInstance, PublicKeys};
468 use std::sync::atomic::{AtomicUsize, Ordering};
469 use std::sync::Mutex;
470
471 #[test]
474 fn block_header_roundtrip() {
475 let json_str = r#"{"globalVariables":{"blockNumber":42},"contentCommitment":"0x01"}"#;
476 let header: BlockHeader = serde_json::from_str(json_str).unwrap();
477 let reserialized = serde_json::to_string(&header).unwrap();
478 let decoded: BlockHeader = serde_json::from_str(&reserialized).unwrap();
479 assert_eq!(decoded.data["globalVariables"]["blockNumber"], 42);
480 }
481
482 #[test]
483 fn tx_execution_request_roundtrip() {
484 let json_str = r#"{"origin":"0x0000000000000000000000000000000000000000000000000000000000000001","functionSelector":"0xaabbccdd"}"#;
485 let req: TxExecutionRequest = serde_json::from_str(json_str).unwrap();
486 let reserialized = serde_json::to_string(&req).unwrap();
487 let decoded: TxExecutionRequest = serde_json::from_str(&reserialized).unwrap();
488 assert_eq!(decoded.data["functionSelector"], "0xaabbccdd");
489 }
490
491 #[test]
492 fn tx_proving_result_roundtrip() {
493 let json_str = r#"{
494 "privateExecutionResult": {"entrypoint": "ok"},
495 "publicInputs": "AQID",
496 "chonkProof": "BAUG",
497 "contractClassLogFields": [{"fields": ["0x01"]}],
498 "publicFunctionCalldata": [{"values": ["0x02"], "hash": "0x03"}]
499 }"#;
500 let result: TxProvingResult = serde_json::from_str(json_str).unwrap();
501 let reserialized = serde_json::to_string(&result).unwrap();
502 let decoded: TxProvingResult = serde_json::from_str(&reserialized).unwrap();
503 assert_eq!(decoded.private_execution_result["entrypoint"], "ok");
504 assert_eq!(decoded.public_inputs.bytes, vec![1, 2, 3]);
505 assert_eq!(decoded.chonk_proof.bytes, vec![4, 5, 6]);
506 assert_eq!(decoded.contract_class_log_fields.len(), 1);
507 assert_eq!(decoded.public_function_calldata.len(), 1);
508 }
509
510 #[test]
511 fn tx_simulation_result_roundtrip() {
512 let json_str = r#"{"returnValues":[42],"gasUsed":{"daGas":100,"l2Gas":200}}"#;
513 let result: TxSimulationResult = serde_json::from_str(json_str).unwrap();
514 let reserialized = serde_json::to_string(&result).unwrap();
515 let decoded: TxSimulationResult = serde_json::from_str(&reserialized).unwrap();
516 assert_eq!(decoded.data["gasUsed"]["l2Gas"], 200);
517 }
518
519 #[test]
520 fn tx_profile_result_roundtrip() {
521 let json_str = r#"{"gateCounts":[10,20],"executionSteps":5}"#;
522 let result: TxProfileResult = serde_json::from_str(json_str).unwrap();
523 let reserialized = serde_json::to_string(&result).unwrap();
524 let decoded: TxProfileResult = serde_json::from_str(&reserialized).unwrap();
525 assert_eq!(decoded.data["executionSteps"], 5);
526 }
527
528 #[test]
529 fn block_hash_roundtrip() {
530 let hash = BlockHash([0x11; 32]);
531 let json = serde_json::to_string(&hash).unwrap();
532 let decoded: BlockHash = serde_json::from_str(&json).unwrap();
533 assert_eq!(decoded, hash);
534 }
535
536 #[test]
537 fn log_id_roundtrip() {
538 let log_id = sample_log_id();
539 let json = serde_json::to_string(&log_id).unwrap();
540 let decoded: LogId = serde_json::from_str(&json).unwrap();
541 assert_eq!(decoded, log_id);
542 }
543
544 #[test]
545 fn utility_execution_result_roundtrip() {
546 let result = UtilityExecutionResult {
547 result: vec![Fr::from(1u64), Fr::from(2u64)],
548 stats: Some(serde_json::json!({"timings": {"total": 1}})),
549 };
550 let json = serde_json::to_string(&result).unwrap();
551 let decoded: UtilityExecutionResult = serde_json::from_str(&json).unwrap();
552 assert_eq!(decoded.result, result.result);
553 assert_eq!(decoded.stats, result.stats);
554 }
555
556 #[test]
557 fn simulate_tx_opts_defaults() {
558 let opts = SimulateTxOpts::default();
559 assert!(!opts.simulate_public);
560 assert!(!opts.skip_tx_validation);
561 assert!(!opts.skip_fee_enforcement);
562 assert!(opts.overrides.is_none());
563 assert!(opts.scopes.is_empty());
564
565 let json = serde_json::to_value(&opts).unwrap();
566 assert_eq!(json["simulatePublic"], false);
567 assert_eq!(json["skipTxValidation"], false);
568 assert_eq!(json["skipFeeEnforcement"], false);
569 }
570
571 #[test]
572 fn profile_tx_opts_defaults() {
573 let opts = ProfileTxOpts::default();
574 assert_eq!(opts.profile_mode, ProfileMode::Full);
575 assert!(opts.skip_proof_generation);
576 assert!(opts.scopes.is_empty());
577 }
578
579 #[test]
580 fn execute_utility_opts_defaults() {
581 let opts = ExecuteUtilityOpts::default();
582 assert!(opts.authwits.is_empty());
583 assert!(opts.scopes.is_empty());
584 }
585
586 #[test]
587 fn packed_private_event_roundtrip() {
588 let event = PackedPrivateEvent {
589 packed_event: vec![Fr::from(1u64), Fr::from(2u64)],
590 tx_hash: TxHash::zero(),
591 l2_block_number: 42,
592 l2_block_hash: sample_block_hash(),
593 event_selector: EventSelector(Fr::from(7u64)),
594 };
595 let json = serde_json::to_string(&event).unwrap();
596 let decoded: PackedPrivateEvent = serde_json::from_str(&json).unwrap();
597 assert_eq!(decoded.packed_event.len(), 2);
598 assert_eq!(decoded.l2_block_number, 42);
599 assert_eq!(decoded.l2_block_hash, sample_block_hash());
600 }
601
602 #[test]
603 fn packed_private_event_minimal() {
604 let event = PackedPrivateEvent {
605 packed_event: vec![],
606 tx_hash: TxHash::zero(),
607 l2_block_number: 0,
608 l2_block_hash: BlockHash::default(),
609 event_selector: EventSelector(Fr::zero()),
610 };
611 let json = serde_json::to_value(&event).unwrap();
612 assert_eq!(json["txHash"], TxHash::zero().to_string());
613 assert_eq!(json["l2BlockNumber"], 0);
614 }
615
616 #[test]
617 fn private_event_filter_default_serializes_minimal() {
618 let filter = PrivateEventFilter::default();
619 let json = serde_json::to_value(&filter).unwrap();
620 assert_eq!(
621 json["contractAddress"],
622 AztecAddress(Fr::zero()).to_string()
623 );
624 assert!(json.get("txHash").is_none());
625 assert!(json.get("fromBlock").is_none());
626 assert!(json.get("toBlock").is_none());
627 assert!(json.get("afterLog").is_none());
628 assert_eq!(json["scopes"], serde_json::json!([]));
629 }
630
631 #[test]
632 fn private_event_filter_with_fields() {
633 let filter = PrivateEventFilter {
634 contract_address: AztecAddress(Fr::from(9u64)),
635 tx_hash: Some(TxHash::zero()),
636 from_block: Some(10),
637 to_block: Some(20),
638 after_log: Some(sample_log_id()),
639 scopes: vec![AztecAddress(Fr::from(1u64))],
640 };
641 let json = serde_json::to_value(&filter).unwrap();
642 assert_eq!(
643 json["contractAddress"],
644 AztecAddress(Fr::from(9u64)).to_string()
645 );
646 assert_eq!(json["txHash"], TxHash::zero().to_string());
647 assert_eq!(json["fromBlock"], 10);
648 assert_eq!(json["toBlock"], 20);
649 assert!(json.get("afterLog").is_some());
650 assert_eq!(json["scopes"].as_array().unwrap().len(), 1);
651 }
652
653 #[test]
654 fn register_contract_request_roundtrip() {
655 let request = RegisterContractRequest {
656 instance: sample_instance(),
657 artifact: None,
658 };
659 let json = serde_json::to_string(&request).unwrap();
660 let decoded: RegisterContractRequest = serde_json::from_str(&json).unwrap();
661 assert_eq!(decoded.instance.address, request.instance.address);
662 assert!(decoded.artifact.is_none());
663 }
664
665 #[test]
666 fn register_contract_request_with_artifact() {
667 let request = RegisterContractRequest {
668 instance: sample_instance(),
669 artifact: Some(ContractArtifact {
670 name: "TestContract".into(),
671 functions: vec![],
672 outputs: None,
673 file_map: None,
674 context_inputs_sizes: None,
675 }),
676 };
677 let json = serde_json::to_string(&request).unwrap();
678 let decoded: RegisterContractRequest = serde_json::from_str(&json).unwrap();
679 assert_eq!(decoded.artifact.unwrap().name, "TestContract");
680 }
681
682 #[test]
685 fn pxe_is_object_safe() {
686 fn _assert_object_safe(_: &dyn Pxe) {}
687 }
688
689 fn sample_instance() -> ContractInstanceWithAddress {
692 ContractInstanceWithAddress {
693 address: AztecAddress(Fr::from(1u64)),
694 inner: ContractInstance {
695 version: 1,
696 salt: Fr::from(42u64),
697 deployer: AztecAddress(Fr::from(2u64)),
698 current_contract_class_id: Fr::from(100u64),
699 original_contract_class_id: Fr::from(100u64),
700 initialization_hash: Fr::from(0u64),
701 public_keys: PublicKeys::default(),
702 },
703 }
704 }
705
706 fn sample_block_header() -> BlockHeader {
707 BlockHeader {
708 data: serde_json::json!({"globalVariables": {"blockNumber": 1}}),
709 }
710 }
711
712 fn sample_block_hash() -> BlockHash {
713 BlockHash([0x22; 32])
714 }
715
716 fn sample_log_id() -> LogId {
717 LogId {
718 block_number: 42,
719 block_hash: sample_block_hash(),
720 tx_hash: TxHash::zero(),
721 tx_index: 3,
722 log_index: 7,
723 }
724 }
725
726 struct MockPxe {
729 header_results: Mutex<Vec<Result<BlockHeader, Error>>>,
730 accounts: Vec<CompleteAddress>,
731 senders: Mutex<Vec<AztecAddress>>,
732 contracts: Vec<AztecAddress>,
733 call_count: AtomicUsize,
734 }
735
736 impl MockPxe {
737 fn new_ready() -> Self {
738 Self {
739 header_results: Mutex::new(vec![Ok(sample_block_header())]),
740 accounts: vec![],
741 senders: Mutex::new(vec![]),
742 contracts: vec![],
743 call_count: AtomicUsize::new(0),
744 }
745 }
746
747 fn with_accounts(mut self, accounts: Vec<CompleteAddress>) -> Self {
748 self.accounts = accounts;
749 self
750 }
751
752 fn with_contracts(mut self, contracts: Vec<AztecAddress>) -> Self {
753 self.contracts = contracts;
754 self
755 }
756 }
757
758 #[async_trait]
759 impl Pxe for MockPxe {
760 async fn get_synced_block_header(&self) -> Result<BlockHeader, Error> {
761 let idx = self.call_count.fetch_add(1, Ordering::Relaxed);
762 let results = self.header_results.lock().unwrap();
763 if idx < results.len() {
764 match &results[idx] {
765 Ok(h) => Ok(h.clone()),
766 Err(e) => Err(Error::Transport(e.to_string())),
767 }
768 } else if let Some(last) = results.last() {
769 match last {
770 Ok(h) => Ok(h.clone()),
771 Err(e) => Err(Error::Transport(e.to_string())),
772 }
773 } else {
774 Err(Error::Transport("no mock results configured".into()))
775 }
776 }
777
778 async fn get_contract_instance(
779 &self,
780 address: &AztecAddress,
781 ) -> Result<Option<ContractInstanceWithAddress>, Error> {
782 if *address == AztecAddress(Fr::from(1u64)) {
783 Ok(Some(sample_instance()))
784 } else {
785 Ok(None)
786 }
787 }
788
789 async fn get_contract_artifact(&self, _id: &Fr) -> Result<Option<ContractArtifact>, Error> {
790 Ok(None)
791 }
792
793 async fn get_contracts(&self) -> Result<Vec<AztecAddress>, Error> {
794 Ok(self.contracts.clone())
795 }
796
797 async fn register_account(
798 &self,
799 _secret_key: &Fr,
800 _partial_address: &Fr,
801 ) -> Result<CompleteAddress, Error> {
802 Ok(CompleteAddress::default())
803 }
804
805 async fn get_registered_accounts(&self) -> Result<Vec<CompleteAddress>, Error> {
806 Ok(self.accounts.clone())
807 }
808
809 async fn register_sender(&self, sender: &AztecAddress) -> Result<AztecAddress, Error> {
810 self.senders.lock().unwrap().push(*sender);
811 Ok(*sender)
812 }
813
814 async fn get_senders(&self) -> Result<Vec<AztecAddress>, Error> {
815 Ok(self.senders.lock().unwrap().clone())
816 }
817
818 async fn remove_sender(&self, sender: &AztecAddress) -> Result<(), Error> {
819 self.senders.lock().unwrap().retain(|s| s != sender);
820 Ok(())
821 }
822
823 async fn register_contract_class(&self, _artifact: &ContractArtifact) -> Result<(), Error> {
824 Ok(())
825 }
826
827 async fn register_contract(&self, _request: RegisterContractRequest) -> Result<(), Error> {
828 Ok(())
829 }
830
831 async fn update_contract(
832 &self,
833 _address: &AztecAddress,
834 _artifact: &ContractArtifact,
835 ) -> Result<(), Error> {
836 Ok(())
837 }
838
839 async fn simulate_tx(
840 &self,
841 _tx_request: &TxExecutionRequest,
842 _opts: SimulateTxOpts,
843 ) -> Result<TxSimulationResult, Error> {
844 Ok(TxSimulationResult {
845 data: serde_json::json!({"returnValues": []}),
846 })
847 }
848
849 async fn prove_tx(
850 &self,
851 _tx_request: &TxExecutionRequest,
852 _scopes: Vec<AztecAddress>,
853 ) -> Result<TxProvingResult, Error> {
854 Ok(TxProvingResult {
855 tx_hash: None,
856 private_execution_result: serde_json::json!({}),
857 public_inputs: PrivateKernelTailCircuitPublicInputs::from_bytes(vec![0]),
858 chonk_proof: ChonkProof::from_bytes(vec![0]),
859 contract_class_log_fields: vec![],
860 public_function_calldata: vec![],
861 stats: None,
862 })
863 }
864
865 async fn profile_tx(
866 &self,
867 _tx_request: &TxExecutionRequest,
868 _opts: ProfileTxOpts,
869 ) -> Result<TxProfileResult, Error> {
870 Ok(TxProfileResult {
871 data: serde_json::json!({"gateCounts": []}),
872 })
873 }
874
875 async fn execute_utility(
876 &self,
877 _call: &FunctionCall,
878 _opts: ExecuteUtilityOpts,
879 ) -> Result<UtilityExecutionResult, Error> {
880 Ok(UtilityExecutionResult {
881 result: vec![],
882 stats: None,
883 })
884 }
885
886 async fn get_private_events(
887 &self,
888 _event_selector: &EventSelector,
889 _filter: PrivateEventFilter,
890 ) -> Result<Vec<PackedPrivateEvent>, Error> {
891 Ok(vec![])
892 }
893
894 async fn stop(&self) -> Result<(), Error> {
895 Ok(())
896 }
897 }
898
899 #[tokio::test]
902 async fn mock_get_synced_block_header() {
903 let pxe = MockPxe::new_ready();
904 let header = pxe.get_synced_block_header().await.unwrap();
905 assert_eq!(header.data["globalVariables"]["blockNumber"], 1);
906 }
907
908 #[tokio::test]
909 async fn mock_register_account() {
910 let pxe = MockPxe::new_ready();
911 let result = pxe
912 .register_account(&Fr::from(1u64), &Fr::from(2u64))
913 .await
914 .unwrap();
915 assert_eq!(result, CompleteAddress::default());
916 }
917
918 #[tokio::test]
919 async fn mock_get_registered_accounts() {
920 let account = CompleteAddress {
921 address: AztecAddress(Fr::from(99u64)),
922 ..CompleteAddress::default()
923 };
924 let pxe = MockPxe::new_ready().with_accounts(vec![account.clone()]);
925 let accounts = pxe.get_registered_accounts().await.unwrap();
926 assert_eq!(accounts.len(), 1);
927 assert_eq!(accounts[0].address, AztecAddress(Fr::from(99u64)));
928 }
929
930 #[tokio::test]
931 async fn mock_register_and_get_senders() {
932 let pxe = MockPxe::new_ready();
933 let addr = AztecAddress(Fr::from(42u64));
934
935 let result = pxe.register_sender(&addr).await.unwrap();
936 assert_eq!(result, addr);
937
938 let senders = pxe.get_senders().await.unwrap();
939 assert_eq!(senders.len(), 1);
940 assert_eq!(senders[0], addr);
941 }
942
943 #[tokio::test]
944 async fn mock_remove_sender() {
945 let pxe = MockPxe::new_ready();
946 let addr = AztecAddress(Fr::from(42u64));
947
948 pxe.register_sender(&addr).await.unwrap();
949 assert_eq!(pxe.get_senders().await.unwrap().len(), 1);
950
951 pxe.remove_sender(&addr).await.unwrap();
952 assert!(pxe.get_senders().await.unwrap().is_empty());
953 }
954
955 #[tokio::test]
956 async fn mock_get_contract_instance_found() {
957 let pxe = MockPxe::new_ready();
958 let result = pxe
959 .get_contract_instance(&AztecAddress(Fr::from(1u64)))
960 .await
961 .unwrap();
962 assert!(result.is_some());
963 assert_eq!(result.unwrap().address, AztecAddress(Fr::from(1u64)));
964 }
965
966 #[tokio::test]
967 async fn mock_get_contract_instance_not_found() {
968 let pxe = MockPxe::new_ready();
969 let result = pxe
970 .get_contract_instance(&AztecAddress(Fr::from(999u64)))
971 .await
972 .unwrap();
973 assert!(result.is_none());
974 }
975
976 #[tokio::test]
977 async fn mock_get_contracts() {
978 let pxe = MockPxe::new_ready().with_contracts(vec![
979 AztecAddress(Fr::from(1u64)),
980 AztecAddress(Fr::from(2u64)),
981 ]);
982 let contracts = pxe.get_contracts().await.unwrap();
983 assert_eq!(contracts.len(), 2);
984 }
985
986 #[tokio::test]
987 async fn mock_simulate_tx() {
988 let pxe = MockPxe::new_ready();
989 let req = TxExecutionRequest {
990 data: serde_json::json!({}),
991 };
992 let result = pxe
993 .simulate_tx(&req, SimulateTxOpts::default())
994 .await
995 .unwrap();
996 assert_eq!(result.data["returnValues"], serde_json::json!([]));
997 }
998
999 #[tokio::test]
1000 async fn mock_execute_utility() {
1001 let pxe = MockPxe::new_ready();
1002 let call = FunctionCall {
1003 to: AztecAddress(Fr::from(1u64)),
1004 selector: FunctionSelector::from_hex("0xaabbccdd").unwrap(),
1005 args: vec![],
1006 function_type: FunctionType::Utility,
1007 is_static: true,
1008 hide_msg_sender: false,
1009 };
1010 let result = pxe
1011 .execute_utility(&call, ExecuteUtilityOpts::default())
1012 .await
1013 .unwrap();
1014 assert!(result.result.is_empty());
1015 assert!(result.stats.is_none());
1016 }
1017
1018 #[tokio::test]
1019 async fn mock_get_private_events_empty() {
1020 let pxe = MockPxe::new_ready();
1021 let events = pxe
1022 .get_private_events(
1023 &EventSelector(Fr::from(1u64)),
1024 PrivateEventFilter {
1025 contract_address: AztecAddress(Fr::from(1u64)),
1026 scopes: vec![AztecAddress(Fr::from(2u64))],
1027 ..PrivateEventFilter::default()
1028 },
1029 )
1030 .await
1031 .unwrap();
1032 assert!(events.is_empty());
1033 }
1034
1035 #[tokio::test]
1036 async fn mock_register_contract() {
1037 let pxe = MockPxe::new_ready();
1038 let request = RegisterContractRequest {
1039 instance: sample_instance(),
1040 artifact: None,
1041 };
1042 pxe.register_contract(request).await.unwrap();
1043 }
1044
1045 #[tokio::test]
1046 async fn mock_stop() {
1047 let pxe = MockPxe::new_ready();
1048 pxe.stop().await.unwrap();
1049 }
1050}